@@ -12,20 +12,21 @@ import "./interfaces/ISignalBuyContract.sol";
12
12
import "./interfaces/IPermanentStorage.sol " ;
13
13
import "./interfaces/ISpender.sol " ;
14
14
import "./interfaces/IWeth.sol " ;
15
- import "./utils/StrategyBase.sol " ;
16
15
import "./utils/BaseLibEIP712.sol " ;
17
16
import "./utils/LibConstant.sol " ;
18
17
import "./utils/LibSignalBuyContractOrderStorage.sol " ;
18
+ import "./utils/Ownable.sol " ;
19
19
import "./utils/SignalBuyContractLibEIP712.sol " ;
20
20
import "./utils/SignatureValidator.sol " ;
21
21
22
22
/// @title SignalBuy Contract
23
23
/// @notice Order can be filled as long as the provided dealerToken/userToken ratio is better than or equal to user's specfied dealerToken/userToken ratio.
24
24
/// @author imToken Labs
25
- contract SignalBuyContract is ISignalBuyContract , StrategyBase , BaseLibEIP712 , SignatureValidator , ReentrancyGuard {
25
+ contract SignalBuyContract is ISignalBuyContract , BaseLibEIP712 , SignatureValidator , ReentrancyGuard , Ownable {
26
26
using SafeMath for uint256 ;
27
27
using SafeERC20 for IERC20 ;
28
28
29
+ IWETH public immutable weth;
29
30
uint256 public immutable factorActivateDelay;
30
31
31
32
// Below are the variables which consume storage slots.
@@ -37,23 +38,70 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S
37
38
uint16 public tokenlonFeeFactor = 0 ;
38
39
uint16 public pendingTokenlonFeeFactor;
39
40
41
+ mapping (bytes32 => uint256 ) public filledAmount;
42
+
43
+ /// @notice Emitted when allowing another account to spend assets
44
+ /// @param spender The address that is allowed to transfer tokens
45
+ event AllowTransfer (address indexed spender , address token );
46
+
47
+ /// @notice Emitted when disallowing an account to spend assets
48
+ /// @param spender The address that is removed from allow list
49
+ event DisallowTransfer (address indexed spender , address token );
50
+
51
+ /// @notice Emitted when ETH converted to WETH
52
+ /// @param amount The amount of converted ETH
53
+ event DepositETH (uint256 amount );
54
+
40
55
constructor (
41
56
address _owner ,
42
- address _userProxy ,
43
57
address _weth ,
44
- address _permStorage ,
45
- address _spender ,
46
58
address _coordinator ,
47
59
uint256 _factorActivateDelay ,
48
60
address _feeCollector
49
- ) StrategyBase (_owner, _userProxy, _weth, _permStorage, _spender) {
61
+ ) Ownable (_owner) {
62
+ weth = IWETH (_weth);
50
63
coordinator = _coordinator;
51
64
factorActivateDelay = _factorActivateDelay;
52
65
feeCollector = _feeCollector;
53
66
}
54
67
55
68
receive () external payable {}
56
69
70
+ /// @notice Set allowance of tokens to an address
71
+ /// @notice Only owner can call
72
+ /// @param _tokenList The list of tokens
73
+ /// @param _spender The address that will be allowed
74
+ function setAllowance (address [] calldata _tokenList , address _spender ) external onlyOwner {
75
+ for (uint256 i = 0 ; i < _tokenList.length ; ++ i) {
76
+ IERC20 (_tokenList[i]).safeApprove (_spender, LibConstant.MAX_UINT);
77
+
78
+ emit AllowTransfer (_spender, _tokenList[i]);
79
+ }
80
+ }
81
+
82
+ /// @notice Clear allowance of tokens to an address
83
+ /// @notice Only owner can call
84
+ /// @param _tokenList The list of tokens
85
+ /// @param _spender The address that will be cleared
86
+ function closeAllowance (address [] calldata _tokenList , address _spender ) external onlyOwner {
87
+ for (uint256 i = 0 ; i < _tokenList.length ; ++ i) {
88
+ IERC20 (_tokenList[i]).safeApprove (_spender, 0 );
89
+
90
+ emit DisallowTransfer (_spender, _tokenList[i]);
91
+ }
92
+ }
93
+
94
+ /// @notice Convert ETH in this contract to WETH
95
+ /// @notice Only owner can call
96
+ function depositETH () external onlyOwner {
97
+ uint256 balance = address (this ).balance;
98
+ if (balance > 0 ) {
99
+ weth.deposit { value: balance }();
100
+
101
+ emit DepositETH (balance);
102
+ }
103
+ }
104
+
57
105
/// @notice Only owner can call
58
106
/// @param _newCoordinator The new address of coordinator
59
107
function upgradeCoordinator (address _newCoordinator ) external onlyOwner {
@@ -99,7 +147,7 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S
99
147
bytes calldata _orderUserSig ,
100
148
TraderParams calldata _params ,
101
149
CoordinatorParams calldata _crdParams
102
- ) external override onlyUserProxy nonReentrant returns (uint256 , uint256 ) {
150
+ ) external override nonReentrant returns (uint256 , uint256 ) {
103
151
bytes32 orderHash = getEIP712Hash (SignalBuyContractLibEIP712._getOrderStructHash (_order));
104
152
105
153
_validateOrder (_order, orderHash, _orderUserSig);
@@ -161,11 +209,11 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S
161
209
require (_fill.recipient != address (0 ), "SignalBuyContract: recipient can not be zero address " );
162
210
163
211
bytes32 fillHash = getEIP712Hash (SignalBuyContractLibEIP712._getFillStructHash (_fill));
212
+ require (! LibSignalBuyContractOrderStorage.getStorage ().fillSeen[fillHash], "SignalBuyContract: Fill seen before " );
164
213
require (isValidSignature (_fill.dealer, fillHash, bytes ("" ), _fillTakerSig), "SignalBuyContract: Fill is not signed by dealer " );
165
214
166
215
// Set fill seen to avoid replay attack.
167
- // PermanentStorage would throw error if fill is already seen.
168
- permStorage.setLimitOrderTransactionSeen (fillHash);
216
+ LibSignalBuyContractOrderStorage.getStorage ().fillSeen[fillHash] = true ;
169
217
}
170
218
171
219
function _validateFillPermission (
@@ -187,11 +235,11 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S
187
235
})
188
236
)
189
237
);
238
+ require (! LibSignalBuyContractOrderStorage.getStorage ().fillSeen[allowFillHash], "SignalBuyContract: AllowFill seen before " );
190
239
require (isValidSignature (coordinator, allowFillHash, bytes ("" ), _crdParams.sig), "SignalBuyContract: AllowFill is not signed by coordinator " );
191
240
192
241
// Set allow fill seen to avoid replay attack
193
- // PermanentStorage would throw error if allow fill is already seen.
194
- permStorage.setLimitOrderAllowFillSeen (allowFillHash);
242
+ LibSignalBuyContractOrderStorage.getStorage ().allowFillSeen[allowFillHash] = true ;
195
243
196
244
return allowFillHash;
197
245
}
@@ -214,7 +262,6 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S
214
262
215
263
function _settleForTrader (TraderSettlement memory _settlement ) internal {
216
264
// memory cache
217
- ISpender _spender = spender;
218
265
address _feeCollector = feeCollector;
219
266
220
267
// Calculate user fee (user receives dealer token so fee is charged in dealer token)
@@ -226,14 +273,14 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S
226
273
require (dealerTokenForUser >= _settlement.minDealerTokenAmount, "SignalBuyContract: dealer token amount not enough " );
227
274
228
275
// trader -> user
229
- _spender. spendFromUserTo ( _settlement.trader, address (_settlement.dealerToken) , _settlement.user, dealerTokenForUser);
276
+ _settlement.dealerToken. safeTransferFrom (_settlement.trader , _settlement.user, dealerTokenForUser);
230
277
231
278
// user -> recipient
232
- _spender. spendFromUserTo ( _settlement.user, address (_settlement.userToken) , _settlement.recipient, _settlement.userTokenAmount);
279
+ _settlement.userToken. safeTransferFrom (_settlement.user , _settlement.recipient, _settlement.userTokenAmount);
233
280
234
281
// Collect user fee (charged in dealer token)
235
282
if (tokenlonFee > 0 ) {
236
- _spender. spendFromUserTo ( _settlement.trader, address (_settlement.dealerToken) , _feeCollector, tokenlonFee);
283
+ _settlement.dealerToken. safeTransferFrom (_settlement.trader , _feeCollector, tokenlonFee);
237
284
}
238
285
239
286
// bypass stack too deep error
@@ -256,12 +303,7 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S
256
303
}
257
304
258
305
/// @inheritdoc ISignalBuyContract
259
- function cancelSignalBuy (SignalBuyContractLibEIP712.Order calldata _order , bytes calldata _cancelOrderUserSig )
260
- external
261
- override
262
- onlyUserProxy
263
- nonReentrant
264
- {
306
+ function cancelSignalBuy (SignalBuyContractLibEIP712.Order calldata _order , bytes calldata _cancelOrderUserSig ) external override nonReentrant {
265
307
require (_order.expiry > uint64 (block .timestamp ), "SignalBuyContract: Order is expired " );
266
308
bytes32 orderHash = getEIP712Hash (SignalBuyContractLibEIP712._getOrderStructHash (_order));
267
309
bool isCancelled = LibSignalBuyContractOrderStorage.getStorage ().orderHashToCancelled[orderHash];
0 commit comments