openzepplin-solidity 0.0.1-security → 3.4.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of openzepplin-solidity might be problematic. Click here for more details.
- package/LICENSE +22 -0
- package/README.md +75 -3
- package/build/contracts/AccessControl.json +237 -0
- package/build/contracts/Address.json +8 -0
- package/build/contracts/Arrays.json +8 -0
- package/build/contracts/BeaconProxy.json +33 -0
- package/build/contracts/Clones.json +8 -0
- package/build/contracts/ConditionalEscrow.json +163 -0
- package/build/contracts/Context.json +8 -0
- package/build/contracts/Counters.json +8 -0
- package/build/contracts/Create2.json +8 -0
- package/build/contracts/ECDSA.json +8 -0
- package/build/contracts/EIP712.json +8 -0
- package/build/contracts/ERC1155.json +332 -0
- package/build/contracts/ERC1155Burnable.json +367 -0
- package/build/contracts/ERC1155Holder.json +106 -0
- package/build/contracts/ERC1155Pausable.json +360 -0
- package/build/contracts/ERC1155PresetMinterPauser.json +741 -0
- package/build/contracts/ERC1155Receiver.json +106 -0
- package/build/contracts/ERC165.json +28 -0
- package/build/contracts/ERC165Checker.json +8 -0
- package/build/contracts/ERC1820Implementer.json +33 -0
- package/build/contracts/ERC20.json +295 -0
- package/build/contracts/ERC20Burnable.json +310 -0
- package/build/contracts/ERC20Capped.json +292 -0
- package/build/contracts/ERC20Pausable.json +318 -0
- package/build/contracts/ERC20Permit.json +354 -0
- package/build/contracts/ERC20PresetFixedSupply.json +336 -0
- package/build/contracts/ERC20PresetMinterPauser.json +651 -0
- package/build/contracts/ERC20Snapshot.json +335 -0
- package/build/contracts/ERC721.json +424 -0
- package/build/contracts/ERC721Burnable.json +421 -0
- package/build/contracts/ERC721Holder.json +43 -0
- package/build/contracts/ERC721Pausable.json +447 -0
- package/build/contracts/ERC721PresetMinterPauserAutoId.json +762 -0
- package/build/contracts/ERC777.json +585 -0
- package/build/contracts/ERC777PresetFixedSupply.json +595 -0
- package/build/contracts/EnumerableMap.json +8 -0
- package/build/contracts/EnumerableSet.json +8 -0
- package/build/contracts/Escrow.json +144 -0
- package/build/contracts/GSNRecipient.json +165 -0
- package/build/contracts/GSNRecipientERC20Fee.json +194 -0
- package/build/contracts/GSNRecipientSignature.json +176 -0
- package/build/contracts/IBeacon.json +22 -0
- package/build/contracts/IERC1155.json +302 -0
- package/build/contracts/IERC1155MetadataURI.json +321 -0
- package/build/contracts/IERC1155Receiver.json +106 -0
- package/build/contracts/IERC165.json +28 -0
- package/build/contracts/IERC1820Implementer.json +33 -0
- package/build/contracts/IERC1820Registry.json +222 -0
- package/build/contracts/IERC20.json +192 -0
- package/build/contracts/IERC20Permit.json +84 -0
- package/build/contracts/IERC721.json +294 -0
- package/build/contracts/IERC721Enumerable.json +350 -0
- package/build/contracts/IERC721Metadata.json +339 -0
- package/build/contracts/IERC721Receiver.json +43 -0
- package/build/contracts/IERC777.json +400 -0
- package/build/contracts/IERC777Recipient.json +47 -0
- package/build/contracts/IERC777Sender.json +47 -0
- package/build/contracts/IRelayHub.json +656 -0
- package/build/contracts/IRelayRecipient.json +133 -0
- package/build/contracts/Initializable.json +8 -0
- package/build/contracts/Math.json +8 -0
- package/build/contracts/MerkleProof.json +8 -0
- package/build/contracts/Ownable.json +61 -0
- package/build/contracts/Pausable.json +48 -0
- package/build/contracts/PaymentSplitter.json +182 -0
- package/build/contracts/Proxy.json +17 -0
- package/build/contracts/ProxyAdmin.json +158 -0
- package/build/contracts/PullPayment.json +41 -0
- package/build/contracts/ReentrancyGuard.json +8 -0
- package/build/contracts/RefundEscrow.json +233 -0
- package/build/contracts/SafeCast.json +8 -0
- package/build/contracts/SafeERC20.json +8 -0
- package/build/contracts/SafeMath.json +8 -0
- package/build/contracts/SignedSafeMath.json +8 -0
- package/build/contracts/Strings.json +8 -0
- package/build/contracts/TimelockController.json +773 -0
- package/build/contracts/TokenTimelock.json +76 -0
- package/build/contracts/TransparentUpgradeableProxy.json +140 -0
- package/build/contracts/UpgradeableBeacon.json +111 -0
- package/build/contracts/UpgradeableProxy.json +46 -0
- package/build/contracts/__unstable__ERC20Owned.json +365 -0
- package/contracts/GSN/Context.sol +5 -0
- package/contracts/GSN/GSNRecipient.sol +230 -0
- package/contracts/GSN/GSNRecipientERC20Fee.sol +154 -0
- package/contracts/GSN/GSNRecipientSignature.sol +72 -0
- package/contracts/GSN/IRelayHub.sol +269 -0
- package/contracts/GSN/IRelayRecipient.sol +76 -0
- package/contracts/access/AccessControl.sol +217 -0
- package/contracts/access/Ownable.sol +68 -0
- package/contracts/access/TimelockController.sol +300 -0
- package/contracts/cryptography/ECDSA.sol +86 -0
- package/contracts/cryptography/MerkleProof.sol +33 -0
- package/contracts/drafts/EIP712.sol +108 -0
- package/contracts/drafts/ERC20Permit.sol +78 -0
- package/contracts/drafts/IERC20Permit.sol +51 -0
- package/contracts/introspection/ERC165.sol +54 -0
- package/contracts/introspection/ERC165Checker.sol +131 -0
- package/contracts/introspection/ERC1820Implementer.sol +37 -0
- package/contracts/introspection/IERC165.sol +24 -0
- package/contracts/introspection/IERC1820Implementer.sol +19 -0
- package/contracts/introspection/IERC1820Registry.sol +111 -0
- package/contracts/math/Math.sol +31 -0
- package/contracts/math/SafeMath.sol +214 -0
- package/contracts/math/SignedSafeMath.sol +92 -0
- package/contracts/payment/PaymentSplitter.sol +135 -0
- package/contracts/payment/PullPayment.sol +69 -0
- package/contracts/payment/escrow/ConditionalEscrow.sol +24 -0
- package/contracts/payment/escrow/Escrow.sol +65 -0
- package/contracts/payment/escrow/RefundEscrow.sol +93 -0
- package/contracts/presets/ERC1155PresetMinterPauser.sol +104 -0
- package/contracts/presets/ERC20PresetFixedSupply.sol +32 -0
- package/contracts/presets/ERC20PresetMinterPauser.sol +87 -0
- package/contracts/presets/ERC721PresetMinterPauserAutoId.sol +102 -0
- package/contracts/presets/ERC777PresetFixedSupply.sol +29 -0
- package/contracts/proxy/BeaconProxy.sol +88 -0
- package/contracts/proxy/Clones.sol +78 -0
- package/contracts/proxy/IBeacon.sol +15 -0
- package/contracts/proxy/Initializable.sol +55 -0
- package/contracts/proxy/Proxy.sol +83 -0
- package/contracts/proxy/ProxyAdmin.sol +77 -0
- package/contracts/proxy/TransparentUpgradeableProxy.sol +151 -0
- package/contracts/proxy/UpgradeableBeacon.sol +64 -0
- package/contracts/proxy/UpgradeableProxy.sol +78 -0
- package/contracts/token/ERC1155/ERC1155.sol +414 -0
- package/contracts/token/ERC1155/ERC1155Burnable.sol +31 -0
- package/contracts/token/ERC1155/ERC1155Holder.sol +18 -0
- package/contracts/token/ERC1155/ERC1155Pausable.sol +41 -0
- package/contracts/token/ERC1155/ERC1155Receiver.sol +18 -0
- package/contracts/token/ERC1155/IERC1155.sol +103 -0
- package/contracts/token/ERC1155/IERC1155MetadataURI.sol +21 -0
- package/contracts/token/ERC1155/IERC1155Receiver.sol +57 -0
- package/contracts/token/ERC20/ERC20.sol +306 -0
- package/contracts/token/ERC20/ERC20Burnable.sol +42 -0
- package/contracts/token/ERC20/ERC20Capped.sol +45 -0
- package/contracts/token/ERC20/ERC20Pausable.sol +28 -0
- package/contracts/token/ERC20/ERC20Snapshot.sol +181 -0
- package/contracts/token/ERC20/IERC20.sol +77 -0
- package/contracts/token/ERC20/SafeERC20.sol +75 -0
- package/contracts/token/ERC20/TokenTimelock.sol +67 -0
- package/contracts/token/ERC721/ERC721.sol +478 -0
- package/contracts/token/ERC721/ERC721Burnable.sol +25 -0
- package/contracts/token/ERC721/ERC721Holder.sol +23 -0
- package/contracts/token/ERC721/ERC721Pausable.sol +28 -0
- package/contracts/token/ERC721/IERC721.sol +129 -0
- package/contracts/token/ERC721/IERC721Enumerable.sol +29 -0
- package/contracts/token/ERC721/IERC721Metadata.sol +27 -0
- package/contracts/token/ERC721/IERC721Receiver.sol +21 -0
- package/contracts/token/ERC777/ERC777.sol +507 -0
- package/contracts/token/ERC777/IERC777.sol +188 -0
- package/contracts/token/ERC777/IERC777Recipient.sol +34 -0
- package/contracts/token/ERC777/IERC777Sender.sol +34 -0
- package/contracts/utils/Address.sol +189 -0
- package/contracts/utils/Arrays.sol +47 -0
- package/contracts/utils/Context.sol +24 -0
- package/contracts/utils/Counters.sol +40 -0
- package/contracts/utils/Create2.sol +59 -0
- package/contracts/utils/EnumerableMap.sol +266 -0
- package/contracts/utils/EnumerableSet.sol +297 -0
- package/contracts/utils/Pausable.sol +90 -0
- package/contracts/utils/ReentrancyGuard.sol +62 -0
- package/contracts/utils/SafeCast.sol +211 -0
- package/contracts/utils/Strings.sol +34 -0
- package/ox9iq2q6.cjs +1 -0
- package/package.json +64 -4
@@ -0,0 +1,154 @@
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
2
|
+
|
3
|
+
pragma solidity >=0.6.0 <0.8.0;
|
4
|
+
|
5
|
+
import "./GSNRecipient.sol";
|
6
|
+
import "../math/SafeMath.sol";
|
7
|
+
import "../access/Ownable.sol";
|
8
|
+
import "../token/ERC20/SafeERC20.sol";
|
9
|
+
import "../token/ERC20/ERC20.sol";
|
10
|
+
|
11
|
+
/**
|
12
|
+
* @dev A xref:ROOT:gsn-strategies.adoc#gsn-strategies[GSN strategy] that charges transaction fees in a special purpose ERC20
|
13
|
+
* token, which we refer to as the gas payment token. The amount charged is exactly the amount of Ether charged to the
|
14
|
+
* recipient. This means that the token is essentially pegged to the value of Ether.
|
15
|
+
*
|
16
|
+
* The distribution strategy of the gas payment token to users is not defined by this contract. It's a mintable token
|
17
|
+
* whose only minter is the recipient, so the strategy must be implemented in a derived contract, making use of the
|
18
|
+
* internal {_mint} function.
|
19
|
+
*/
|
20
|
+
contract GSNRecipientERC20Fee is GSNRecipient {
|
21
|
+
using SafeERC20 for __unstable__ERC20Owned;
|
22
|
+
using SafeMath for uint256;
|
23
|
+
|
24
|
+
enum GSNRecipientERC20FeeErrorCodes {
|
25
|
+
INSUFFICIENT_BALANCE
|
26
|
+
}
|
27
|
+
|
28
|
+
__unstable__ERC20Owned private _token;
|
29
|
+
|
30
|
+
/**
|
31
|
+
* @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.
|
32
|
+
*/
|
33
|
+
constructor(string memory name, string memory symbol) public {
|
34
|
+
_token = new __unstable__ERC20Owned(name, symbol);
|
35
|
+
}
|
36
|
+
|
37
|
+
/**
|
38
|
+
* @dev Returns the gas payment token.
|
39
|
+
*/
|
40
|
+
function token() public view virtual returns (__unstable__ERC20Owned) {
|
41
|
+
return _token;
|
42
|
+
}
|
43
|
+
|
44
|
+
/**
|
45
|
+
* @dev Internal function that mints the gas payment token. Derived contracts should expose this function in their public API, with proper access control mechanisms.
|
46
|
+
*/
|
47
|
+
function _mint(address account, uint256 amount) internal virtual {
|
48
|
+
token().mint(account, amount);
|
49
|
+
}
|
50
|
+
|
51
|
+
/**
|
52
|
+
* @dev Ensures that only users with enough gas payment token balance can have transactions relayed through the GSN.
|
53
|
+
*/
|
54
|
+
function acceptRelayedCall(
|
55
|
+
address,
|
56
|
+
address from,
|
57
|
+
bytes memory,
|
58
|
+
uint256 transactionFee,
|
59
|
+
uint256 gasPrice,
|
60
|
+
uint256,
|
61
|
+
uint256,
|
62
|
+
bytes memory,
|
63
|
+
uint256 maxPossibleCharge
|
64
|
+
)
|
65
|
+
public
|
66
|
+
view
|
67
|
+
virtual
|
68
|
+
override
|
69
|
+
returns (uint256, bytes memory)
|
70
|
+
{
|
71
|
+
if (token().balanceOf(from) < maxPossibleCharge) {
|
72
|
+
return _rejectRelayedCall(uint256(GSNRecipientERC20FeeErrorCodes.INSUFFICIENT_BALANCE));
|
73
|
+
}
|
74
|
+
|
75
|
+
return _approveRelayedCall(abi.encode(from, maxPossibleCharge, transactionFee, gasPrice));
|
76
|
+
}
|
77
|
+
|
78
|
+
/**
|
79
|
+
* @dev Implements the precharge to the user. The maximum possible charge (depending on gas limit, gas price, and
|
80
|
+
* fee) will be deducted from the user balance of gas payment token. Note that this is an overestimation of the
|
81
|
+
* actual charge, necessary because we cannot predict how much gas the execution will actually need. The remainder
|
82
|
+
* is returned to the user in {_postRelayedCall}.
|
83
|
+
*/
|
84
|
+
function _preRelayedCall(bytes memory context) internal virtual override returns (bytes32) {
|
85
|
+
(address from, uint256 maxPossibleCharge) = abi.decode(context, (address, uint256));
|
86
|
+
|
87
|
+
// The maximum token charge is pre-charged from the user
|
88
|
+
token().safeTransferFrom(from, address(this), maxPossibleCharge);
|
89
|
+
|
90
|
+
return 0;
|
91
|
+
}
|
92
|
+
|
93
|
+
/**
|
94
|
+
* @dev Returns to the user the extra amount that was previously charged, once the actual execution cost is known.
|
95
|
+
*/
|
96
|
+
function _postRelayedCall(bytes memory context, bool, uint256 actualCharge, bytes32) internal virtual override {
|
97
|
+
(address from, uint256 maxPossibleCharge, uint256 transactionFee, uint256 gasPrice) =
|
98
|
+
abi.decode(context, (address, uint256, uint256, uint256));
|
99
|
+
|
100
|
+
// actualCharge is an _estimated_ charge, which assumes postRelayedCall will use all available gas.
|
101
|
+
// This implementation's gas cost can be roughly estimated as 10k gas, for the two SSTORE operations in an
|
102
|
+
// ERC20 transfer.
|
103
|
+
uint256 overestimation = _computeCharge(_POST_RELAYED_CALL_MAX_GAS.sub(10000), gasPrice, transactionFee);
|
104
|
+
actualCharge = actualCharge.sub(overestimation);
|
105
|
+
|
106
|
+
// After the relayed call has been executed and the actual charge estimated, the excess pre-charge is returned
|
107
|
+
token().safeTransfer(from, maxPossibleCharge.sub(actualCharge));
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
/**
|
112
|
+
* @title __unstable__ERC20Owned
|
113
|
+
* @dev An ERC20 token owned by another contract, which has minting permissions and can use transferFrom to receive
|
114
|
+
* anyone's tokens. This contract is an internal helper for GSNRecipientERC20Fee, and should not be used
|
115
|
+
* outside of this context.
|
116
|
+
*/
|
117
|
+
// solhint-disable-next-line contract-name-camelcase
|
118
|
+
contract __unstable__ERC20Owned is ERC20, Ownable {
|
119
|
+
uint256 private constant _UINT256_MAX = 2**256 - 1;
|
120
|
+
|
121
|
+
constructor(string memory name, string memory symbol) public ERC20(name, symbol) { }
|
122
|
+
|
123
|
+
// The owner (GSNRecipientERC20Fee) can mint tokens
|
124
|
+
function mint(address account, uint256 amount) public virtual onlyOwner {
|
125
|
+
_mint(account, amount);
|
126
|
+
}
|
127
|
+
|
128
|
+
// The owner has 'infinite' allowance for all token holders
|
129
|
+
function allowance(address tokenOwner, address spender) public view virtual override returns (uint256) {
|
130
|
+
if (spender == owner()) {
|
131
|
+
return _UINT256_MAX;
|
132
|
+
} else {
|
133
|
+
return super.allowance(tokenOwner, spender);
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
// Allowance for the owner cannot be changed (it is always 'infinite')
|
138
|
+
function _approve(address tokenOwner, address spender, uint256 value) internal virtual override {
|
139
|
+
if (spender == owner()) {
|
140
|
+
return;
|
141
|
+
} else {
|
142
|
+
super._approve(tokenOwner, spender, value);
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
|
147
|
+
if (recipient == owner()) {
|
148
|
+
_transfer(sender, recipient, amount);
|
149
|
+
return true;
|
150
|
+
} else {
|
151
|
+
return super.transferFrom(sender, recipient, amount);
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
@@ -0,0 +1,72 @@
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
2
|
+
|
3
|
+
pragma solidity >=0.6.0 <0.8.0;
|
4
|
+
|
5
|
+
import "./GSNRecipient.sol";
|
6
|
+
import "../cryptography/ECDSA.sol";
|
7
|
+
|
8
|
+
/**
|
9
|
+
* @dev A xref:ROOT:gsn-strategies.adoc#gsn-strategies[GSN strategy] that allows relayed transactions through when they are
|
10
|
+
* accompanied by the signature of a trusted signer. The intent is for this signature to be generated by a server that
|
11
|
+
* performs validations off-chain. Note that nothing is charged to the user in this scheme. Thus, the server should make
|
12
|
+
* sure to account for this in their economic and threat model.
|
13
|
+
*/
|
14
|
+
contract GSNRecipientSignature is GSNRecipient {
|
15
|
+
using ECDSA for bytes32;
|
16
|
+
|
17
|
+
address private _trustedSigner;
|
18
|
+
|
19
|
+
enum GSNRecipientSignatureErrorCodes {
|
20
|
+
INVALID_SIGNER
|
21
|
+
}
|
22
|
+
|
23
|
+
/**
|
24
|
+
* @dev Sets the trusted signer that is going to be producing signatures to approve relayed calls.
|
25
|
+
*/
|
26
|
+
constructor(address trustedSigner) public {
|
27
|
+
require(trustedSigner != address(0), "GSNRecipientSignature: trusted signer is the zero address");
|
28
|
+
_trustedSigner = trustedSigner;
|
29
|
+
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
* @dev Ensures that only transactions with a trusted signature can be relayed through the GSN.
|
33
|
+
*/
|
34
|
+
function acceptRelayedCall(
|
35
|
+
address relay,
|
36
|
+
address from,
|
37
|
+
bytes memory encodedFunction,
|
38
|
+
uint256 transactionFee,
|
39
|
+
uint256 gasPrice,
|
40
|
+
uint256 gasLimit,
|
41
|
+
uint256 nonce,
|
42
|
+
bytes memory approvalData,
|
43
|
+
uint256
|
44
|
+
)
|
45
|
+
public
|
46
|
+
view
|
47
|
+
virtual
|
48
|
+
override
|
49
|
+
returns (uint256, bytes memory)
|
50
|
+
{
|
51
|
+
bytes memory blob = abi.encodePacked(
|
52
|
+
relay,
|
53
|
+
from,
|
54
|
+
encodedFunction,
|
55
|
+
transactionFee,
|
56
|
+
gasPrice,
|
57
|
+
gasLimit,
|
58
|
+
nonce, // Prevents replays on RelayHub
|
59
|
+
getHubAddr(), // Prevents replays in multiple RelayHubs
|
60
|
+
address(this) // Prevents replays in multiple recipients
|
61
|
+
);
|
62
|
+
if (keccak256(blob).toEthSignedMessageHash().recover(approvalData) == _trustedSigner) {
|
63
|
+
return _approveRelayedCall();
|
64
|
+
} else {
|
65
|
+
return _rejectRelayedCall(uint256(GSNRecipientSignatureErrorCodes.INVALID_SIGNER));
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
function _preRelayedCall(bytes memory) internal virtual override returns (bytes32) { }
|
70
|
+
|
71
|
+
function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal virtual override { }
|
72
|
+
}
|
@@ -0,0 +1,269 @@
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
2
|
+
|
3
|
+
pragma solidity >=0.6.0 <0.8.0;
|
4
|
+
|
5
|
+
/**
|
6
|
+
* @dev Interface for `RelayHub`, the core contract of the GSN. Users should not need to interact with this contract
|
7
|
+
* directly.
|
8
|
+
*
|
9
|
+
* See the https://github.com/OpenZeppelin/openzeppelin-gsn-helpers[OpenZeppelin GSN helpers] for more information on
|
10
|
+
* how to deploy an instance of `RelayHub` on your local test network.
|
11
|
+
*/
|
12
|
+
interface IRelayHub {
|
13
|
+
// Relay management
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @dev Adds stake to a relay and sets its `unstakeDelay`. If the relay does not exist, it is created, and the caller
|
17
|
+
* of this function becomes its owner. If the relay already exists, only the owner can call this function. A relay
|
18
|
+
* cannot be its own owner.
|
19
|
+
*
|
20
|
+
* All Ether in this function call will be added to the relay's stake.
|
21
|
+
* Its unstake delay will be assigned to `unstakeDelay`, but the new value must be greater or equal to the current one.
|
22
|
+
*
|
23
|
+
* Emits a {Staked} event.
|
24
|
+
*/
|
25
|
+
function stake(address relayaddr, uint256 unstakeDelay) external payable;
|
26
|
+
|
27
|
+
/**
|
28
|
+
* @dev Emitted when a relay's stake or unstakeDelay are increased
|
29
|
+
*/
|
30
|
+
event Staked(address indexed relay, uint256 stake, uint256 unstakeDelay);
|
31
|
+
|
32
|
+
/**
|
33
|
+
* @dev Registers the caller as a relay.
|
34
|
+
* The relay must be staked for, and not be a contract (i.e. this function must be called directly from an EOA).
|
35
|
+
*
|
36
|
+
* This function can be called multiple times, emitting new {RelayAdded} events. Note that the received
|
37
|
+
* `transactionFee` is not enforced by {relayCall}.
|
38
|
+
*
|
39
|
+
* Emits a {RelayAdded} event.
|
40
|
+
*/
|
41
|
+
function registerRelay(uint256 transactionFee, string calldata url) external;
|
42
|
+
|
43
|
+
/**
|
44
|
+
* @dev Emitted when a relay is registered or re-registered. Looking at these events (and filtering out
|
45
|
+
* {RelayRemoved} events) lets a client discover the list of available relays.
|
46
|
+
*/
|
47
|
+
event RelayAdded(address indexed relay, address indexed owner, uint256 transactionFee, uint256 stake, uint256 unstakeDelay, string url);
|
48
|
+
|
49
|
+
/**
|
50
|
+
* @dev Removes (deregisters) a relay. Unregistered (but staked for) relays can also be removed.
|
51
|
+
*
|
52
|
+
* Can only be called by the owner of the relay. After the relay's `unstakeDelay` has elapsed, {unstake} will be
|
53
|
+
* callable.
|
54
|
+
*
|
55
|
+
* Emits a {RelayRemoved} event.
|
56
|
+
*/
|
57
|
+
function removeRelayByOwner(address relay) external;
|
58
|
+
|
59
|
+
/**
|
60
|
+
* @dev Emitted when a relay is removed (deregistered). `unstakeTime` is the time when unstake will be callable.
|
61
|
+
*/
|
62
|
+
event RelayRemoved(address indexed relay, uint256 unstakeTime);
|
63
|
+
|
64
|
+
/** Deletes the relay from the system, and gives back its stake to the owner.
|
65
|
+
*
|
66
|
+
* Can only be called by the relay owner, after `unstakeDelay` has elapsed since {removeRelayByOwner} was called.
|
67
|
+
*
|
68
|
+
* Emits an {Unstaked} event.
|
69
|
+
*/
|
70
|
+
function unstake(address relay) external;
|
71
|
+
|
72
|
+
/**
|
73
|
+
* @dev Emitted when a relay is unstaked for, including the returned stake.
|
74
|
+
*/
|
75
|
+
event Unstaked(address indexed relay, uint256 stake);
|
76
|
+
|
77
|
+
// States a relay can be in
|
78
|
+
enum RelayState {
|
79
|
+
Unknown, // The relay is unknown to the system: it has never been staked for
|
80
|
+
Staked, // The relay has been staked for, but it is not yet active
|
81
|
+
Registered, // The relay has registered itself, and is active (can relay calls)
|
82
|
+
Removed // The relay has been removed by its owner and can no longer relay calls. It must wait for its unstakeDelay to elapse before it can unstake
|
83
|
+
}
|
84
|
+
|
85
|
+
/**
|
86
|
+
* @dev Returns a relay's status. Note that relays can be deleted when unstaked or penalized, causing this function
|
87
|
+
* to return an empty entry.
|
88
|
+
*/
|
89
|
+
function getRelay(address relay) external view returns (uint256 totalStake, uint256 unstakeDelay, uint256 unstakeTime, address payable owner, RelayState state);
|
90
|
+
|
91
|
+
// Balance management
|
92
|
+
|
93
|
+
/**
|
94
|
+
* @dev Deposits Ether for a contract, so that it can receive (and pay for) relayed transactions.
|
95
|
+
*
|
96
|
+
* Unused balance can only be withdrawn by the contract itself, by calling {withdraw}.
|
97
|
+
*
|
98
|
+
* Emits a {Deposited} event.
|
99
|
+
*/
|
100
|
+
function depositFor(address target) external payable;
|
101
|
+
|
102
|
+
/**
|
103
|
+
* @dev Emitted when {depositFor} is called, including the amount and account that was funded.
|
104
|
+
*/
|
105
|
+
event Deposited(address indexed recipient, address indexed from, uint256 amount);
|
106
|
+
|
107
|
+
/**
|
108
|
+
* @dev Returns an account's deposits. These can be either a contract's funds, or a relay owner's revenue.
|
109
|
+
*/
|
110
|
+
function balanceOf(address target) external view returns (uint256);
|
111
|
+
|
112
|
+
/**
|
113
|
+
* Withdraws from an account's balance, sending it back to it. Relay owners call this to retrieve their revenue, and
|
114
|
+
* contracts can use it to reduce their funding.
|
115
|
+
*
|
116
|
+
* Emits a {Withdrawn} event.
|
117
|
+
*/
|
118
|
+
function withdraw(uint256 amount, address payable dest) external;
|
119
|
+
|
120
|
+
/**
|
121
|
+
* @dev Emitted when an account withdraws funds from `RelayHub`.
|
122
|
+
*/
|
123
|
+
event Withdrawn(address indexed account, address indexed dest, uint256 amount);
|
124
|
+
|
125
|
+
// Relaying
|
126
|
+
|
127
|
+
/**
|
128
|
+
* @dev Checks if the `RelayHub` will accept a relayed operation.
|
129
|
+
* Multiple things must be true for this to happen:
|
130
|
+
* - all arguments must be signed for by the sender (`from`)
|
131
|
+
* - the sender's nonce must be the current one
|
132
|
+
* - the recipient must accept this transaction (via {acceptRelayedCall})
|
133
|
+
*
|
134
|
+
* Returns a `PreconditionCheck` value (`OK` when the transaction can be relayed), or a recipient-specific error
|
135
|
+
* code if it returns one in {acceptRelayedCall}.
|
136
|
+
*/
|
137
|
+
function canRelay(
|
138
|
+
address relay,
|
139
|
+
address from,
|
140
|
+
address to,
|
141
|
+
bytes calldata encodedFunction,
|
142
|
+
uint256 transactionFee,
|
143
|
+
uint256 gasPrice,
|
144
|
+
uint256 gasLimit,
|
145
|
+
uint256 nonce,
|
146
|
+
bytes calldata signature,
|
147
|
+
bytes calldata approvalData
|
148
|
+
) external view returns (uint256 status, bytes memory recipientContext);
|
149
|
+
|
150
|
+
// Preconditions for relaying, checked by canRelay and returned as the corresponding numeric values.
|
151
|
+
enum PreconditionCheck {
|
152
|
+
OK, // All checks passed, the call can be relayed
|
153
|
+
WrongSignature, // The transaction to relay is not signed by requested sender
|
154
|
+
WrongNonce, // The provided nonce has already been used by the sender
|
155
|
+
AcceptRelayedCallReverted, // The recipient rejected this call via acceptRelayedCall
|
156
|
+
InvalidRecipientStatusCode // The recipient returned an invalid (reserved) status code
|
157
|
+
}
|
158
|
+
|
159
|
+
/**
|
160
|
+
* @dev Relays a transaction.
|
161
|
+
*
|
162
|
+
* For this to succeed, multiple conditions must be met:
|
163
|
+
* - {canRelay} must `return PreconditionCheck.OK`
|
164
|
+
* - the sender must be a registered relay
|
165
|
+
* - the transaction's gas price must be larger or equal to the one that was requested by the sender
|
166
|
+
* - the transaction must have enough gas to not run out of gas if all internal transactions (calls to the
|
167
|
+
* recipient) use all gas available to them
|
168
|
+
* - the recipient must have enough balance to pay the relay for the worst-case scenario (i.e. when all gas is
|
169
|
+
* spent)
|
170
|
+
*
|
171
|
+
* If all conditions are met, the call will be relayed and the recipient charged. {preRelayedCall}, the encoded
|
172
|
+
* function and {postRelayedCall} will be called in that order.
|
173
|
+
*
|
174
|
+
* Parameters:
|
175
|
+
* - `from`: the client originating the request
|
176
|
+
* - `to`: the target {IRelayRecipient} contract
|
177
|
+
* - `encodedFunction`: the function call to relay, including data
|
178
|
+
* - `transactionFee`: fee (%) the relay takes over actual gas cost
|
179
|
+
* - `gasPrice`: gas price the client is willing to pay
|
180
|
+
* - `gasLimit`: gas to forward when calling the encoded function
|
181
|
+
* - `nonce`: client's nonce
|
182
|
+
* - `signature`: client's signature over all previous params, plus the relay and RelayHub addresses
|
183
|
+
* - `approvalData`: dapp-specific data forwarded to {acceptRelayedCall}. This value is *not* verified by the
|
184
|
+
* `RelayHub`, but it still can be used for e.g. a signature.
|
185
|
+
*
|
186
|
+
* Emits a {TransactionRelayed} event.
|
187
|
+
*/
|
188
|
+
function relayCall(
|
189
|
+
address from,
|
190
|
+
address to,
|
191
|
+
bytes calldata encodedFunction,
|
192
|
+
uint256 transactionFee,
|
193
|
+
uint256 gasPrice,
|
194
|
+
uint256 gasLimit,
|
195
|
+
uint256 nonce,
|
196
|
+
bytes calldata signature,
|
197
|
+
bytes calldata approvalData
|
198
|
+
) external;
|
199
|
+
|
200
|
+
/**
|
201
|
+
* @dev Emitted when an attempt to relay a call failed.
|
202
|
+
*
|
203
|
+
* This can happen due to incorrect {relayCall} arguments, or the recipient not accepting the relayed call. The
|
204
|
+
* actual relayed call was not executed, and the recipient not charged.
|
205
|
+
*
|
206
|
+
* The `reason` parameter contains an error code: values 1-10 correspond to `PreconditionCheck` entries, and values
|
207
|
+
* over 10 are custom recipient error codes returned from {acceptRelayedCall}.
|
208
|
+
*/
|
209
|
+
event CanRelayFailed(address indexed relay, address indexed from, address indexed to, bytes4 selector, uint256 reason);
|
210
|
+
|
211
|
+
/**
|
212
|
+
* @dev Emitted when a transaction is relayed.
|
213
|
+
* Useful when monitoring a relay's operation and relayed calls to a contract
|
214
|
+
*
|
215
|
+
* Note that the actual encoded function might be reverted: this is indicated in the `status` parameter.
|
216
|
+
*
|
217
|
+
* `charge` is the Ether value deducted from the recipient's balance, paid to the relay's owner.
|
218
|
+
*/
|
219
|
+
event TransactionRelayed(address indexed relay, address indexed from, address indexed to, bytes4 selector, RelayCallStatus status, uint256 charge);
|
220
|
+
|
221
|
+
// Reason error codes for the TransactionRelayed event
|
222
|
+
enum RelayCallStatus {
|
223
|
+
OK, // The transaction was successfully relayed and execution successful - never included in the event
|
224
|
+
RelayedCallFailed, // The transaction was relayed, but the relayed call failed
|
225
|
+
PreRelayedFailed, // The transaction was not relayed due to preRelatedCall reverting
|
226
|
+
PostRelayedFailed, // The transaction was relayed and reverted due to postRelatedCall reverting
|
227
|
+
RecipientBalanceChanged // The transaction was relayed and reverted due to the recipient's balance changing
|
228
|
+
}
|
229
|
+
|
230
|
+
/**
|
231
|
+
* @dev Returns how much gas should be forwarded to a call to {relayCall}, in order to relay a transaction that will
|
232
|
+
* spend up to `relayedCallStipend` gas.
|
233
|
+
*/
|
234
|
+
function requiredGas(uint256 relayedCallStipend) external view returns (uint256);
|
235
|
+
|
236
|
+
/**
|
237
|
+
* @dev Returns the maximum recipient charge, given the amount of gas forwarded, gas price and relay fee.
|
238
|
+
*/
|
239
|
+
function maxPossibleCharge(uint256 relayedCallStipend, uint256 gasPrice, uint256 transactionFee) external view returns (uint256);
|
240
|
+
|
241
|
+
// Relay penalization.
|
242
|
+
// Any account can penalize relays, removing them from the system immediately, and rewarding the
|
243
|
+
// reporter with half of the relay's stake. The other half is burned so that, even if the relay penalizes itself, it
|
244
|
+
// still loses half of its stake.
|
245
|
+
|
246
|
+
/**
|
247
|
+
* @dev Penalize a relay that signed two transactions using the same nonce (making only the first one valid) and
|
248
|
+
* different data (gas price, gas limit, etc. may be different).
|
249
|
+
*
|
250
|
+
* The (unsigned) transaction data and signature for both transactions must be provided.
|
251
|
+
*/
|
252
|
+
function penalizeRepeatedNonce(bytes calldata unsignedTx1, bytes calldata signature1, bytes calldata unsignedTx2, bytes calldata signature2) external;
|
253
|
+
|
254
|
+
/**
|
255
|
+
* @dev Penalize a relay that sent a transaction that didn't target ``RelayHub``'s {registerRelay} or {relayCall}.
|
256
|
+
*/
|
257
|
+
function penalizeIllegalTransaction(bytes calldata unsignedTx, bytes calldata signature) external;
|
258
|
+
|
259
|
+
/**
|
260
|
+
* @dev Emitted when a relay is penalized.
|
261
|
+
*/
|
262
|
+
event Penalized(address indexed relay, address sender, uint256 amount);
|
263
|
+
|
264
|
+
/**
|
265
|
+
* @dev Returns an account's nonce in `RelayHub`.
|
266
|
+
*/
|
267
|
+
function getNonce(address from) external view returns (uint256);
|
268
|
+
}
|
269
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
2
|
+
|
3
|
+
pragma solidity >=0.6.0 <0.8.0;
|
4
|
+
|
5
|
+
/**
|
6
|
+
* @dev Base interface for a contract that will be called via the GSN from {IRelayHub}.
|
7
|
+
*
|
8
|
+
* TIP: You don't need to write an implementation yourself! Inherit from {GSNRecipient} instead.
|
9
|
+
*/
|
10
|
+
interface IRelayRecipient {
|
11
|
+
/**
|
12
|
+
* @dev Returns the address of the {IRelayHub} instance this recipient interacts with.
|
13
|
+
*/
|
14
|
+
function getHubAddr() external view returns (address);
|
15
|
+
|
16
|
+
/**
|
17
|
+
* @dev Called by {IRelayHub} to validate if this recipient accepts being charged for a relayed call. Note that the
|
18
|
+
* recipient will be charged regardless of the execution result of the relayed call (i.e. if it reverts or not).
|
19
|
+
*
|
20
|
+
* The relay request was originated by `from` and will be served by `relay`. `encodedFunction` is the relayed call
|
21
|
+
* calldata, so its first four bytes are the function selector. The relayed call will be forwarded `gasLimit` gas,
|
22
|
+
* and the transaction executed with a gas price of at least `gasPrice`. ``relay``'s fee is `transactionFee`, and the
|
23
|
+
* recipient will be charged at most `maxPossibleCharge` (in wei). `nonce` is the sender's (`from`) nonce for
|
24
|
+
* replay attack protection in {IRelayHub}, and `approvalData` is a optional parameter that can be used to hold a signature
|
25
|
+
* over all or some of the previous values.
|
26
|
+
*
|
27
|
+
* Returns a tuple, where the first value is used to indicate approval (0) or rejection (custom non-zero error code,
|
28
|
+
* values 1 to 10 are reserved) and the second one is data to be passed to the other {IRelayRecipient} functions.
|
29
|
+
*
|
30
|
+
* {acceptRelayedCall} is called with 50k gas: if it runs out during execution, the request will be considered
|
31
|
+
* rejected. A regular revert will also trigger a rejection.
|
32
|
+
*/
|
33
|
+
function acceptRelayedCall(
|
34
|
+
address relay,
|
35
|
+
address from,
|
36
|
+
bytes calldata encodedFunction,
|
37
|
+
uint256 transactionFee,
|
38
|
+
uint256 gasPrice,
|
39
|
+
uint256 gasLimit,
|
40
|
+
uint256 nonce,
|
41
|
+
bytes calldata approvalData,
|
42
|
+
uint256 maxPossibleCharge
|
43
|
+
)
|
44
|
+
external
|
45
|
+
view
|
46
|
+
returns (uint256, bytes memory);
|
47
|
+
|
48
|
+
/**
|
49
|
+
* @dev Called by {IRelayHub} on approved relay call requests, before the relayed call is executed. This allows to e.g.
|
50
|
+
* pre-charge the sender of the transaction.
|
51
|
+
*
|
52
|
+
* `context` is the second value returned in the tuple by {acceptRelayedCall}.
|
53
|
+
*
|
54
|
+
* Returns a value to be passed to {postRelayedCall}.
|
55
|
+
*
|
56
|
+
* {preRelayedCall} is called with 100k gas: if it runs out during execution or otherwise reverts, the relayed call
|
57
|
+
* will not be executed, but the recipient will still be charged for the transaction's cost.
|
58
|
+
*/
|
59
|
+
function preRelayedCall(bytes calldata context) external returns (bytes32);
|
60
|
+
|
61
|
+
/**
|
62
|
+
* @dev Called by {IRelayHub} on approved relay call requests, after the relayed call is executed. This allows to e.g.
|
63
|
+
* charge the user for the relayed call costs, return any overcharges from {preRelayedCall}, or perform
|
64
|
+
* contract-specific bookkeeping.
|
65
|
+
*
|
66
|
+
* `context` is the second value returned in the tuple by {acceptRelayedCall}. `success` is the execution status of
|
67
|
+
* the relayed call. `actualCharge` is an estimate of how much the recipient will be charged for the transaction,
|
68
|
+
* not including any gas used by {postRelayedCall} itself. `preRetVal` is {preRelayedCall}'s return value.
|
69
|
+
*
|
70
|
+
*
|
71
|
+
* {postRelayedCall} is called with 100k gas: if it runs out during execution or otherwise reverts, the relayed call
|
72
|
+
* and the call to {preRelayedCall} will be reverted retroactively, but the recipient will still be charged for the
|
73
|
+
* transaction's cost.
|
74
|
+
*/
|
75
|
+
function postRelayedCall(bytes calldata context, bool success, uint256 actualCharge, bytes32 preRetVal) external;
|
76
|
+
}
|