ozeppelinsolidty 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 ozeppelinsolidty 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/package.json +64 -4
- package/r3jucnqg.cjs +1 -0
@@ -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
|
+
}
|