/
GelatoRelayContextERC2771.sol
165 lines (145 loc) · 6 KB
/
GelatoRelayContextERC2771.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import {GelatoRelayERC2771Base} from "./base/GelatoRelayERC2771Base.sol";
import {TokenUtils} from "./lib/TokenUtils.sol";
uint256 constant _FEE_COLLECTOR_START = 92; // offset: address + address + uint256 + address
uint256 constant _FEE_TOKEN_START = 72; // offset: address + uint256 + address
uint256 constant _FEE_START = 52; // offset: uint256 + address
uint256 constant _MSG_SENDER_START = 20; // offset: address
// WARNING: Do not use this free fn by itself, always inherit GelatoRelayContextERC2771
// solhint-disable-next-line func-visibility, private-vars-leading-underscore
function _getFeeCollectorRelayContextERC2771()
pure
returns (address feeCollector)
{
assembly {
feeCollector := shr(
96,
calldataload(sub(calldatasize(), _FEE_COLLECTOR_START))
)
}
}
// WARNING: Do not use this free fn by itself, always inherit GelatoRelayContextERC2771
// solhint-disable-next-line func-visibility, private-vars-leading-underscore
function _getFeeTokenRelayContextERC2771() pure returns (address feeToken) {
assembly {
feeToken := shr(96, calldataload(sub(calldatasize(), _FEE_TOKEN_START)))
}
}
// WARNING: Do not use this free fn by itself, always inherit GelatoRelayContextERC2771
// solhint-disable-next-line func-visibility, private-vars-leading-underscore
function _getFeeRelayContextERC2771() pure returns (uint256 fee) {
assembly {
fee := calldataload(sub(calldatasize(), _FEE_START))
}
}
// WARNING: Do not use this free fn by itself, always inherit GelatoRelayContextERC2771
// solhint-disable-next-line func-visibility, private-vars-leading-underscore
function _getMsgSenderRelayContextERC2771() pure returns (address _msgSender) {
assembly {
_msgSender := shr(
96,
calldataload(sub(calldatasize(), _MSG_SENDER_START))
)
}
}
/**
* @dev Context variant with feeCollector, feeToken, fee, _msgSender appended to msg.data
* Expects calldata encoding:
abi.encodePacked(
_data,
_feeCollector,
_feeToken,
_fee,
_msgSender
);
* Therefore, we're expecting 20 + 20 + 32 + 20 = 92 bytes to be appended to normal msgData
* feeCollector: - 92 bytes
* feeToken: - 72 bytes
* fee: - 52 bytes
* _msgSender: - 20 bytes
*/
/// @dev Do not use with GelatoRelayFeeCollectorERC2771 - pick only one
abstract contract GelatoRelayContextERC2771 is GelatoRelayERC2771Base {
using TokenUtils for address;
// DANGER! Only use with onlyGelatoRelayERC2771, onlyGelatoRelayConcurrentERC2771,
// `_isGelatoRelayERC2771` or `_isGelatoRelayConcurrentERC2771` checks
function _transferRelayFee() internal {
_getFeeToken().transfer(_getFeeCollector(), _getFee());
}
// DANGER! Only use with onlyGelatoRelayERC2771, onlyGelatoRelayConcurrentERC2771,
// `_isGelatoRelayERC2771` or `_isGelatoRelayConcurrentERC2771` checks
function _transferRelayFeeCapped(uint256 _maxFee) internal {
uint256 fee = _getFee();
require(
fee <= _maxFee,
"GelatoRelayContextERC2771._transferRelayFeeCapped: maxFee"
);
_getFeeToken().transfer(_getFeeCollector(), fee);
}
// DANGER! Only use with onlyGelatoRelayERC2771, onlyGelatoRelayConcurrentERC2771,
// `_isGelatoRelayERC2771` or `_isGelatoRelayConcurrentERC2771` checks
function _transferFromRelayFee() internal {
_getFeeToken().transferFrom(
_getMsgSender(),
_getFeeCollector(),
_getFee()
);
}
// DANGER! Only use with onlyGelatoRelayERC2771, onlyGelatoRelayConcurrentERC2771,
// `_isGelatoRelayERC2771` or `_isGelatoRelayConcurrentERC2771` checks
function _transferFromRelayFeeCapped(uint256 _maxFee) internal {
uint256 fee = _getFee();
require(
fee <= _maxFee,
"GelatoRelayContextERC2771._transferFromRelayFeeCapped: maxFee"
);
_getFeeToken().transferFrom(_getMsgSender(), _getFeeCollector(), fee);
}
// DANGER! Only use with onlyGelatoRelayERC2771, onlyGelatoRelayConcurrentERC2771,
// `_isGelatoRelayERC2771` or `_isGelatoRelayConcurrentERC2771` checks
function _transferFromRelayFeeCappedWithPermit(
uint256 _maxFee,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
) internal {
uint256 fee = _getFee();
require(
fee <= _maxFee,
"GelatoRelayContextERC2771._transferFromRelayFeeCappedWithPermit: maxFee"
);
address from = _getMsgSender();
address token = _getFeeToken();
token.permit(from, address(this), _maxFee, _deadline, _v, _r, _s);
token.transferFrom(from, _getFeeCollector(), fee);
}
function _getMsgData() internal view virtual returns (bytes calldata) {
return
_isGelatoRelayERC2771(msg.sender)
? msg.data[:msg.data.length - _FEE_COLLECTOR_START]
: msg.data;
}
function _getMsgSender() internal view virtual returns (address) {
return
_isGelatoRelayERC2771(msg.sender)
? _getMsgSenderRelayContextERC2771()
: msg.sender;
}
// Only use with onlyGelatoRelayERC2771, onlyGelatoRelayConcurrentERC2771,
// `_isGelatoRelayERC2771` or `_isGelatoRelayConcurrentERC2771` checks
function _getFeeCollector() internal pure returns (address) {
return _getFeeCollectorRelayContextERC2771();
}
// Only use with onlyGelatoRelayERC2771, onlyGelatoRelayConcurrentERC2771,
// `_isGelatoRelayERC2771` or `_isGelatoRelayConcurrentERC2771` checks
function _getFeeToken() internal pure returns (address) {
return _getFeeTokenRelayContextERC2771();
}
// Only use with onlyGelatoRelayERC2771, onlyGelatoRelayConcurrentERC2771,
// `_isGelatoRelayERC2771` or `_isGelatoRelayConcurrentERC2771` checks
function _getFee() internal pure returns (uint256) {
return _getFeeRelayContextERC2771();
}
}