16
16
* limitations under the License.
17
17
*/
18
18
pragma solidity 0.7.6 ;
19
+ pragma abicoder v2;
19
20
21
+ import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol " ;
20
22
import {BaseTokenMessenger} from "./BaseTokenMessenger.sol " ;
21
23
import {ITokenMinterV2} from "../interfaces/v2/ITokenMinterV2.sol " ;
22
24
import {AddressUtils} from "../messages/v2/AddressUtils.sol " ;
@@ -32,6 +34,16 @@ import {TOKEN_MESSENGER_MIN_FINALITY_THRESHOLD} from "./FinalityThresholds.sol";
32
34
* and to/from TokenMinters.
33
35
*/
34
36
contract TokenMessengerV2 is IMessageHandlerV2 , BaseTokenMessenger {
37
+ // ============ Structs ============
38
+ struct TokenMessengerV2Roles {
39
+ address owner;
40
+ address rescuer;
41
+ address feeRecipient;
42
+ address denylister;
43
+ address tokenMinter;
44
+ address minFeeController;
45
+ }
46
+
35
47
// ============ Events ============
36
48
/**
37
49
* @notice Emitted when a DepositForBurn message is sent
@@ -67,6 +79,7 @@ contract TokenMessengerV2 is IMessageHandlerV2, BaseTokenMessenger {
67
79
using BurnMessageV2 for bytes29 ;
68
80
using TypedMemView for bytes ;
69
81
using TypedMemView for bytes29 ;
82
+ using SafeMath for uint256 ;
70
83
71
84
// ============ Constructor ============
72
85
/**
@@ -83,46 +96,40 @@ contract TokenMessengerV2 is IMessageHandlerV2, BaseTokenMessenger {
83
96
// ============ Initializers ============
84
97
/**
85
98
* @notice Initializes the contract
86
- * @dev Reverts if `owner_` is the zero address
87
- * @dev Reverts if `rescuer_` is the zero address
88
- * @dev Reverts if `feeRecipient_` is the zero address
89
- * @dev Reverts if `denylister_` is the zero address
90
- * @dev Reverts if `tokenMinter_` is the zero address
99
+ * @dev Reverts if any of the roles are the zero address
91
100
* @dev Reverts if `remoteDomains_` and `remoteTokenMessengers_` are unequal length
92
101
* @dev Each remoteTokenMessenger address must correspond to the remote domain at the same
93
102
* index in respective arrays.
94
103
* @dev Reverts if any `remoteTokenMessengers_` entry equals bytes32(0)
95
- * @param owner_ Owner address
96
- * @param rescuer_ Rescuer address
97
- * @param feeRecipient_ FeeRecipient address
98
- * @param denylister_ Denylister address
99
- * @param tokenMinter_ Local token minter address
104
+ * @param roles Roles configuration
105
+ * @param minFee_ Minimum fee
100
106
* @param remoteDomains_ Array of remote domains to configure
101
107
* @param remoteTokenMessengers_ Array of remote token messenger addresses
102
108
*/
103
109
function initialize (
104
- address owner_ ,
105
- address rescuer_ ,
106
- address feeRecipient_ ,
107
- address denylister_ ,
108
- address tokenMinter_ ,
110
+ TokenMessengerV2Roles calldata roles ,
111
+ uint256 minFee_ ,
109
112
uint32 [] calldata remoteDomains_ ,
110
113
bytes32 [] calldata remoteTokenMessengers_
111
114
) external initializer {
112
- require (owner_ != address (0 ), "Owner is the zero address " );
115
+ require (roles.owner != address (0 ), "Owner is the zero address " );
113
116
require (
114
117
remoteDomains_.length == remoteTokenMessengers_.length ,
115
118
"Invalid remote domain configuration "
116
119
);
117
120
118
121
// Roles
119
- _transferOwnership (owner_ );
120
- _updateRescuer (rescuer_ );
121
- _updateDenylister (denylister_ );
122
- _setFeeRecipient (feeRecipient_ );
122
+ _transferOwnership (roles.owner );
123
+ _updateRescuer (roles.rescuer );
124
+ _updateDenylister (roles.denylister );
125
+ _setFeeRecipient (roles.feeRecipient );
123
126
124
127
// Local minter configuration
125
- _setLocalMinter (tokenMinter_);
128
+ _setLocalMinter (roles.tokenMinter);
129
+
130
+ // Fee configuration
131
+ _setMinFeeController (roles.minFeeController);
132
+ _setMinFee (minFee_);
126
133
127
134
// Remote token messenger configuration
128
135
uint256 _remoteDomainsLength = remoteDomains_.length ;
@@ -145,6 +152,7 @@ contract TokenMessengerV2 is IMessageHandlerV2, BaseTokenMessenger {
145
152
* to this contract is less than `amount`.
146
153
* - burn() reverts. For example, if `amount` is 0.
147
154
* - maxFee is greater than or equal to `amount`.
155
+ * - maxFee is less than `amount * minFee / MIN_FEE_MULTIPLIER`.
148
156
* - MessageTransmitterV2#sendMessage reverts.
149
157
* @param amount amount of tokens to burn
150
158
* @param destinationDomain destination domain to receive message on
@@ -188,6 +196,7 @@ contract TokenMessengerV2 is IMessageHandlerV2, BaseTokenMessenger {
188
196
* to this contract is less than `amount`.
189
197
* - burn() reverts. For example, if `amount` is 0.
190
198
* - maxFee is greater than or equal to `amount`.
199
+ * - maxFee is less than `amount * minFee / MIN_FEE_MULTIPLIER`.
191
200
* - MessageTransmitterV2#sendMessage reverts.
192
201
* @param amount amount of tokens to burn
193
202
* @param destinationDomain destination domain to receive message on
@@ -282,7 +291,33 @@ contract TokenMessengerV2 is IMessageHandlerV2, BaseTokenMessenger {
282
291
return _handleReceiveMessage (messageBody.ref (0 ), remoteDomain);
283
292
}
284
293
294
+ /**
295
+ * @notice Returns the minimum fee for a given amount
296
+ * @param amount The amount for which to calculate the minimum fee
297
+ * @return The minimum fee for the given amount
298
+ */
299
+ function getMinFeeAmount (uint256 amount ) external view returns (uint256 ) {
300
+ if (minFee == 0 ) return 0 ;
301
+
302
+ require (amount > 1 , "Amount too low " );
303
+ return _calcMinFeeAmount (amount);
304
+ }
305
+
285
306
// ============ Internal Utils ============
307
+ /**
308
+ * Calculates the minimum fee amount for a given amount.
309
+ * @dev Amount should be constrained to be greater than 1.
310
+ * @dev Assumes `minFee` is non-zero.
311
+ * @param _amount The amount for which to calculate the minimum fee.
312
+ * @return The minimum fee for the given amount.
313
+ */
314
+ function _calcMinFeeAmount (
315
+ uint256 _amount
316
+ ) internal view returns (uint256 ) {
317
+ uint256 _minFeeAmount = _amount.mul (minFee) / MIN_FEE_MULTIPLIER;
318
+ return _minFeeAmount == 0 ? 1 : _minFeeAmount;
319
+ }
320
+
286
321
/**
287
322
* @notice Deposits and burns tokens from sender to be minted on destination domain.
288
323
* Emits a `DepositForBurn` event.
@@ -308,6 +343,16 @@ contract TokenMessengerV2 is IMessageHandlerV2, BaseTokenMessenger {
308
343
require (_mintRecipient != bytes32 (0 ), "Mint recipient must be nonzero " );
309
344
require (_maxFee < _amount, "Max fee must be less than amount " );
310
345
346
+ // Verify minimum fee
347
+ if (minFee > 0 ) {
348
+ // Implicitly constrains `_amount` to be greater than 1
349
+ // 0 < minFeeAmount <= maxFee < amount
350
+ require (
351
+ _maxFee >= _calcMinFeeAmount (_amount),
352
+ "Insufficient max fee "
353
+ );
354
+ }
355
+
311
356
bytes32 _destinationTokenMessenger = _getRemoteTokenMessenger (
312
357
_destinationDomain
313
358
);
0 commit comments