Skip to content

Commit 004d466

Browse files
authored
Merge the develop branch to the master branch, preparation to v6.0.0-rc0
This set of changes includes the following improvements and fixes: * [Improvement] AMB Home-to-Foreign async calls (#570), closes #492 * [Improvement] Add GSN support for erc20-to-native bridge mode (#571) * [Fix] Fix issues with packages versions and linter (#600) * [Other] Bump package version before 6.0.0-rc0 (#598)
2 parents 7edfe77 + de37e25 commit 004d466

31 files changed

+18383
-47919
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ deploy/*.env*
1111
!deploy/.env.example
1212
upgrade/*.env*
1313
!upgrade/.env.example
14+
.vscode

contracts/gsn/BasePaymaster.sol

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// SPDX-License-Identifier:MIT
2+
pragma solidity 0.4.24;
3+
pragma experimental ABIEncoderV2;
4+
5+
import "../upgradeable_contracts/Ownable.sol";
6+
7+
import "./interfaces/GsnTypes.sol";
8+
import "./interfaces/IPaymaster.sol";
9+
import "./interfaces/IRelayHub.sol";
10+
import "./utils/GsnEip712Library.sol";
11+
import "./forwarder/IForwarder.sol";
12+
13+
/**
14+
* Abstract base class to be inherited by a concrete Paymaster
15+
* A subclass must implement:
16+
* - preRelayedCall
17+
* - postRelayedCall
18+
*/
19+
contract BasePaymaster is IPaymaster, Ownable {
20+
IRelayHub internal relayHub;
21+
IForwarder public trustedForwarder;
22+
23+
function getHubAddr() public view returns (address) {
24+
return address(relayHub);
25+
}
26+
27+
//overhead of forwarder verify+signature, plus hub overhead.
28+
uint256 public constant FORWARDER_HUB_OVERHEAD = 50000;
29+
30+
//These parameters are documented in IPaymaster.GasLimits
31+
uint256 public constant PRE_RELAYED_CALL_GAS_LIMIT = 100000;
32+
uint256 public constant POST_RELAYED_CALL_GAS_LIMIT = 110000;
33+
uint256 public constant PAYMASTER_ACCEPTANCE_BUDGET = PRE_RELAYED_CALL_GAS_LIMIT + FORWARDER_HUB_OVERHEAD;
34+
35+
function getGasLimits() external view returns (IPaymaster.GasLimits) {
36+
return
37+
IPaymaster.GasLimits(PAYMASTER_ACCEPTANCE_BUDGET, PRE_RELAYED_CALL_GAS_LIMIT, POST_RELAYED_CALL_GAS_LIMIT);
38+
}
39+
40+
// this method must be called from preRelayedCall to validate that the forwarder
41+
// is approved by the paymaster as well as by the recipient contract.
42+
function _verifyForwarder(GsnTypes.RelayRequest relayRequest) public view {
43+
require(address(trustedForwarder) == relayRequest.relayData.forwarder, "Forwarder is not trusted");
44+
GsnEip712Library.verifyForwarderTrusted(relayRequest);
45+
}
46+
47+
/*
48+
* modifier to be used by recipients as access control protection for preRelayedCall & postRelayedCall
49+
*/
50+
modifier relayHubOnly() {
51+
require(msg.sender == getHubAddr(), "Function can only be called by RelayHub");
52+
_;
53+
}
54+
55+
function setRelayHub(IRelayHub hub) public onlyOwner {
56+
relayHub = hub;
57+
}
58+
59+
function setTrustedForwarder(IForwarder forwarder) public onlyOwner {
60+
trustedForwarder = forwarder;
61+
}
62+
63+
// check current deposit on relay hub.
64+
function getRelayHubDeposit() public view returns (uint256) {
65+
return relayHub.balanceOf(address(this));
66+
}
67+
68+
// withdraw deposit from relayHub
69+
function withdrawRelayHubDepositTo(uint256 amount, address target) public onlyOwner {
70+
relayHub.withdraw(amount, target);
71+
}
72+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// SPDX-License-Identifier:MIT
2+
// solhint-disable no-inline-assembly
3+
pragma solidity 0.4.24;
4+
5+
import "./interfaces/IRelayRecipient.sol";
6+
7+
/**
8+
* A base contract to be inherited by any contract that want to receive relayed transactions
9+
* A subclass must use "_msgSender()" instead of "msg.sender"
10+
*/
11+
contract BaseRelayRecipient is IRelayRecipient {
12+
/**
13+
* return the sender of this call.
14+
* if the call came through our trusted forwarder, return the original sender.
15+
* otherwise, return `msg.sender`.
16+
* should be used in the contract anywhere instead of msg.sender
17+
*/
18+
function _msgSender() internal view returns (address ret) {
19+
if (msg.data.length >= 24 && isTrustedForwarder(msg.sender)) {
20+
// At this point we know that the sender is a trusted forwarder,
21+
// so we trust that the last bytes of msg.data are the verified sender address.
22+
// extract sender address from the end of msg.data
23+
assembly {
24+
ret := shr(96, calldataload(sub(calldatasize, 20)))
25+
}
26+
} else {
27+
return msg.sender;
28+
}
29+
}
30+
31+
/**
32+
* return the msg.data of this call.
33+
* if the call came through our trusted forwarder, then the real sender was appended as the last 20 bytes
34+
* of the msg.data - so this method will strip those 20 bytes off.
35+
* otherwise, return `msg.data`
36+
* should be used in the contract instead of msg.data, where the difference matters (e.g. when explicitly
37+
* signing or hashing the
38+
*/
39+
function _msgData() internal view returns (bytes memory ret) {
40+
if (msg.data.length >= 24 && isTrustedForwarder(msg.sender)) {
41+
// At this point we know that the sender is a trusted forwarder,
42+
// we copy the msg.data , except the last 20 bytes (and update the total length)
43+
assembly {
44+
let ptr := mload(0x40)
45+
// copy only size-20 bytes
46+
let size := sub(calldatasize, 20)
47+
// structure RLP data as <offset> <length> <bytes>
48+
mstore(ptr, 0x20)
49+
mstore(add(ptr, 32), size)
50+
calldatacopy(add(ptr, 64), 0, size)
51+
return(ptr, add(size, 64))
52+
}
53+
} else {
54+
return msg.data;
55+
}
56+
}
57+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// SPDX-License-Identifier:MIT
2+
pragma solidity 0.4.24;
3+
pragma experimental ABIEncoderV2;
4+
5+
contract IForwarder {
6+
struct ForwardRequest {
7+
address from;
8+
address to;
9+
uint256 value;
10+
uint256 gas;
11+
uint256 nonce;
12+
bytes data;
13+
}
14+
15+
function getNonce(address from) external view returns (uint256);
16+
17+
/**
18+
* verify the transaction would execute.
19+
* validate the signature and the nonce of the request.
20+
* revert if either signature or nonce are incorrect.
21+
*/
22+
function verify(
23+
ForwardRequest forwardRequest,
24+
bytes32 domainSeparator,
25+
bytes32 requestTypeHash,
26+
bytes suffixData,
27+
bytes signature
28+
) external view;
29+
30+
/**
31+
* execute a transaction
32+
* @param forwardRequest - all transaction parameters
33+
* @param domainSeparator - domain used when signing this request
34+
* @param requestTypeHash - request type used when signing this request.
35+
* @param suffixData - the extension data used when signing this request.
36+
* @param signature - signature to validate.
37+
*
38+
* the transaction is verified, and then executed.
39+
* the success and ret of "call" are returned.
40+
* This method would revert only verification errors. target errors
41+
* are reported using the returned "success" and ret string
42+
*/
43+
function execute(
44+
ForwardRequest forwardRequest,
45+
bytes32 domainSeparator,
46+
bytes32 requestTypeHash,
47+
bytes suffixData,
48+
bytes signature
49+
) external payable returns (bool success, bytes memory ret);
50+
51+
/**
52+
* Register a new Request typehash.
53+
* @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.
56+
*/
57+
function registerRequestType(string typeName, string typeSuffix) external;
58+
59+
/**
60+
* Register a new domain separator.
61+
* The domain separator must have the following fields: name,version,chainId, verifyingContract.
62+
* the chainId is the current network's chainId, and the verifyingContract is this forwarder.
63+
* This method is given the domain name and version to create and register the domain separator value.
64+
* @param name the domain's display name
65+
* @param version the domain/protocol version
66+
*/
67+
function registerDomainSeparator(string name, string version) external;
68+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier:MIT
2+
pragma solidity 0.4.24;
3+
4+
import "../forwarder/IForwarder.sol";
5+
6+
contract GsnTypes {
7+
struct RelayData {
8+
uint256 gasPrice;
9+
uint256 pctRelayFee;
10+
uint256 baseRelayFee;
11+
address relayWorker;
12+
address paymaster;
13+
bytes paymasterData;
14+
uint256 clientId;
15+
address forwarder;
16+
}
17+
18+
//note: must start with the ForwardRequest to be an extension of the generic forwarder
19+
struct RelayRequest {
20+
IForwarder.ForwardRequest request;
21+
RelayData relayData;
22+
}
23+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// SPDX-License-Identifier:MIT
2+
pragma solidity 0.4.24;
3+
4+
interface IKnowForwarderAddress {
5+
/**
6+
* return the forwarder we trust to forward relayed transactions to us.
7+
* the forwarder is required to verify the sender's signature, and verify
8+
* the call is not a replay.
9+
*/
10+
function getTrustedForwarder() external view returns (address);
11+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// SPDX-License-Identifier:MIT
2+
pragma solidity 0.4.24;
3+
pragma experimental ABIEncoderV2;
4+
5+
import "./GsnTypes.sol";
6+
7+
contract IPaymaster {
8+
/**
9+
* @param acceptanceBudget -
10+
* Paymaster expected gas budget to accept (or reject) a request
11+
* This a gas required by any calculations that might need to reject the
12+
* transaction, by preRelayedCall, forwarder and recipient.
13+
* See value in BasePaymaster.PAYMASTER_ACCEPTANCE_BUDGET
14+
* Transaction that gets rejected above that gas usage is on the paymaster's expense.
15+
* As long this value is above preRelayedCallGasLimit (see defaults in BasePaymaster), the
16+
* Paymaster is guaranteed it will never pay for rejected transactions.
17+
* If this value is below preRelayedCallGasLimt, it might might make Paymaster open to a "griefing" attack.
18+
*
19+
* Specifying value too high might make the call rejected by some relayers.
20+
*
21+
* From a Relay's point of view, this is the highest gas value a paymaster might "grief" the relay,
22+
* since the paymaster will pay anything above that (regardless if the tx reverts)
23+
*
24+
* @param preRelayedCallGasLimit - the max gas usage of preRelayedCall. any revert (including OOG)
25+
* of preRelayedCall is a reject by the paymaster.
26+
* as long as acceptanceBudget is above preRelayedCallGasLimit, any such revert (including OOG)
27+
* is not payed by the paymaster.
28+
* @param postRelayedCallGasLimit - the max gas usage of postRelayedCall.
29+
* note that an OOG will revert the transaction, but the paymaster already committed to pay,
30+
* so the relay will get compensated, at the expense of the paymaster
31+
*/
32+
struct GasLimits {
33+
uint256 acceptanceBudget;
34+
uint256 preRelayedCallGasLimit;
35+
uint256 postRelayedCallGasLimit;
36+
}
37+
38+
/**
39+
* Return the GasLimits constants used by the Paymaster.
40+
*/
41+
function getGasLimits() external view returns (GasLimits memory limits);
42+
43+
/**
44+
* return the relayHub of this contract.
45+
*/
46+
function getHubAddr() public view returns (address);
47+
48+
/**
49+
* Can be used to determine if the contract can pay for incoming calls before making any.
50+
* @return the paymaster's deposit in the RelayHub.
51+
*/
52+
function getRelayHubDeposit() public view returns (uint256);
53+
54+
/**
55+
* Called by Relay (and RelayHub), to validate if the paymaster agrees to pay for this call.
56+
*
57+
* MUST be protected with relayHubOnly() in case it modifies state.
58+
*
59+
* The Paymaster rejects by the following "revert" operations
60+
* - preRelayedCall() method reverts
61+
* - the forwarder reverts because of nonce or signature error
62+
* - the paymaster returned "rejectOnRecipientRevert", and the recipient contract reverted.
63+
* In any of the above cases, all paymaster calls (and recipient call) are reverted.
64+
* In any other case, the paymaster agrees to pay for the gas cost of the transaction (note
65+
* that this includes also postRelayedCall revert)
66+
*
67+
* The rejectOnRecipientRevert flag means the Paymaster "delegate" the rejection to the recipient
68+
* code. It also means the Paymaster trust the recipient to reject fast: both preRelayedCall,
69+
* forwarder check and receipient checks must fit into the GasLimits.acceptanceBudget,
70+
* otherwise the TX is paid by the Paymaster.
71+
*
72+
* @param relayRequest - the full relay request structure
73+
* @param signature - user's EIP712-compatible signature of the {@link relayRequest}.
74+
* Note that in most cases the paymaster shouldn't try use it at all. It is always checked
75+
* by the forwarder immediately after preRelayedCall returns.
76+
* @param approvalData - extra dapp-specific data (e.g. signature from trusted party)
77+
* @param maxPossibleGas - based on values returned from {@link getGasLimits},
78+
* the RelayHub will calculate the maximum possible amount of gas the user may be charged for.
79+
* In order to convert this value to wei, the Paymaster has to call "relayHub.calculateCharge()"
80+
* return:
81+
* a context to be passed to postRelayedCall
82+
* rejectOnRecipientRevert - TRUE if paymaster want to reject the TX if the recipient reverts.
83+
* FALSE means that rejects by the recipient will be completed on chain, and paid by the paymaster.
84+
* (note that in the latter case, the preRelayedCall and postRelayedCall are not reverted).
85+
*/
86+
function preRelayedCall(
87+
GsnTypes.RelayRequest relayRequest,
88+
bytes signature,
89+
bytes approvalData,
90+
uint256 maxPossibleGas
91+
) public returns (bytes memory context, bool rejectOnRecipientRevert);
92+
93+
/**
94+
* This method is called after the actual relayed function call.
95+
* It may be used to record the transaction (e.g. charge the caller by some contract logic) for this call.
96+
*
97+
* MUST be protected with relayHubOnly() in case it modifies state.
98+
*
99+
* @param context - the call context, as returned by the preRelayedCall
100+
* @param success - true if the relayed call succeeded, false if it reverted
101+
* @param gasUseWithoutPost - the actual amount of gas used by the entire transaction, EXCEPT
102+
* the gas used by the postRelayedCall itself.
103+
* @param relayData - the relay params of the request. can be used by relayHub.calculateCharge()
104+
*
105+
* Revert in this functions causes a revert of the client's relayed call (and preRelayedCall(), but the Paymaster
106+
* is still committed to pay the relay for the entire transaction.
107+
*/
108+
function postRelayedCall(bytes context, bool success, uint256 gasUseWithoutPost, GsnTypes.RelayData relayData)
109+
public;
110+
111+
function versionPaymaster() external view returns (string memory);
112+
}

0 commit comments

Comments
 (0)