@@ -19,13 +19,16 @@ import "./external/uniswap/UniswapV2Library.sol";
19
19
20
20
import { ICErc20 } from "./compound/CTokenInterfaces.sol " ;
21
21
22
+ import "@pythnetwork/express-relay-sdk-solidity/IExpressRelay.sol " ;
23
+ import "@pythnetwork/express-relay-sdk-solidity/IExpressRelayFeeReceiver.sol " ;
24
+
22
25
/**
23
26
* @title IonicLiquidator
24
27
* @author David Lucid <[email protected] > (https://github.com/davidlucid)
25
28
* @notice IonicLiquidator safely liquidates unhealthy borrowers (with flashloan support).
26
29
* @dev Do not transfer NATIVE or tokens directly to this address. Only send NATIVE here when using a method, and only approve tokens for transfer to here when using a method. Direct NATIVE transfers will be rejected and direct token transfers will be lost.
27
30
*/
28
- contract IonicLiquidator is OwnableUpgradeable , ILiquidator , IUniswapV2Callee {
31
+ contract IonicLiquidator is OwnableUpgradeable , ILiquidator , IUniswapV2Callee , IExpressRelayFeeReceiver {
29
32
using AddressUpgradeable for address payable ;
30
33
using SafeERC20Upgradeable for IERC20Upgradeable ;
31
34
@@ -64,11 +67,17 @@ contract IonicLiquidator is OwnableUpgradeable, ILiquidator, IUniswapV2Callee {
64
67
*/
65
68
uint8 public flashSwapFee;
66
69
67
- function initialize (
68
- address _wtoken ,
69
- address _uniswapV2router ,
70
- uint8 _flashSwapFee
71
- ) external initializer {
70
+ /**
71
+ * @dev Addres of Pyth Express Relay for preventing value leakage in liquidations.
72
+ */
73
+ IExpressRelay private expressRelay;
74
+
75
+ modifier onlyPERPermissioned (address borrower ) {
76
+ require (expressRelay.isPermissioned (address (this ), abi.encode (borrower)), "invalid liquidation " );
77
+ _;
78
+ }
79
+
80
+ function initialize (address _wtoken , address _uniswapV2router , uint8 _flashSwapFee ) external initializer {
72
81
__Ownable_init ();
73
82
require (_uniswapV2router != address (0 ), "_uniswapV2router not defined. " );
74
83
W_NATIVE_ADDRESS = _wtoken;
@@ -81,11 +90,7 @@ contract IonicLiquidator is OwnableUpgradeable, ILiquidator, IUniswapV2Callee {
81
90
/**
82
91
* @dev Internal function to approve unlimited tokens of `erc20Contract` to `to`.
83
92
*/
84
- function safeApprove (
85
- IERC20Upgradeable token ,
86
- address to ,
87
- uint256 minAmount
88
- ) private {
93
+ function safeApprove (IERC20Upgradeable token , address to , uint256 minAmount ) private {
89
94
uint256 allowance = token.allowance (address (this ), to);
90
95
91
96
if (allowance < minAmount) {
@@ -97,11 +102,7 @@ contract IonicLiquidator is OwnableUpgradeable, ILiquidator, IUniswapV2Callee {
97
102
/**
98
103
* @dev Internal function to approve
99
104
*/
100
- function justApprove (
101
- IERC20Upgradeable token ,
102
- address to ,
103
- uint256 amount
104
- ) private {
105
+ function justApprove (IERC20Upgradeable token , address to , uint256 amount ) private {
105
106
token.approve (to, amount);
106
107
}
107
108
@@ -119,7 +120,7 @@ contract IonicLiquidator is OwnableUpgradeable, ILiquidator, IUniswapV2Callee {
119
120
ICErc20 cErc20 ,
120
121
ICErc20 cTokenCollateral ,
121
122
uint256 minOutputAmount
122
- ) external returns (uint256 ) {
123
+ ) external onlyPERPermissioned (borrower) returns (uint256 ) {
123
124
// Transfer tokens in, approve to cErc20, and liquidate borrow
124
125
require (repayAmount > 0 , "Repay amount (transaction value) must be greater than 0. " );
125
126
IERC20Upgradeable underlying = IERC20Upgradeable (cErc20.underlying ());
@@ -148,10 +149,9 @@ contract IonicLiquidator is OwnableUpgradeable, ILiquidator, IUniswapV2Callee {
148
149
* @notice Safely liquidate an unhealthy loan, confirming that at least `minProfitAmount` in NATIVE profit is seized.
149
150
* @param vars @see LiquidateToTokensWithFlashSwapVars.
150
151
*/
151
- function safeLiquidateToTokensWithFlashLoan (LiquidateToTokensWithFlashSwapVars calldata vars )
152
- external
153
- returns (uint256 )
154
- {
152
+ function safeLiquidateToTokensWithFlashLoan (
153
+ LiquidateToTokensWithFlashSwapVars calldata vars
154
+ ) external onlyPERPermissioned (vars.borrower) returns (uint256 ) {
155
155
// Input validation
156
156
require (vars.repayAmount > 0 , "Repay amount must be greater than 0. " );
157
157
@@ -199,15 +199,25 @@ contract IonicLiquidator is OwnableUpgradeable, ILiquidator, IUniswapV2Callee {
199
199
require (payable (msg .sender ).isContract (), "Sender is not a contract. " );
200
200
}
201
201
202
+ /**
203
+ * @notice receiveAuctionProceedings function - receives native token from the express relay
204
+ * You can use permission key to distribute the received funds to users who got liquidated, LPs, etc...
205
+ */
206
+ function receiveAuctionProceedings (bytes calldata permissionKey ) external payable {}
207
+
208
+ function withdrawAll () external onlyOwner {
209
+ uint256 balance = address (this ).balance;
210
+ require (balance > 0 , "No Ether left to withdraw " );
211
+
212
+ // Transfer all Ether to the owner
213
+ (bool sent , ) = msg .sender .call { value: balance }("" );
214
+ require (sent, "Failed to send Ether " );
215
+ }
216
+
202
217
/**
203
218
* @dev Callback function for Uniswap flashloans.
204
219
*/
205
- function uniswapV2Call (
206
- address ,
207
- uint256 ,
208
- uint256 ,
209
- bytes calldata data
210
- ) public override {
220
+ function uniswapV2Call (address , uint256 , uint256 , bytes calldata data ) public override {
211
221
// Liquidate unhealthy borrow, exchange seized collateral, return flashloaned funds, and exchange profit
212
222
// Decode params
213
223
LiquidateToTokensWithFlashSwapVars memory vars = abi.decode (data[4 :], (LiquidateToTokensWithFlashSwapVars));
@@ -220,21 +230,11 @@ contract IonicLiquidator is OwnableUpgradeable, ILiquidator, IUniswapV2Callee {
220
230
/**
221
231
* @dev Callback function for PCS flashloans.
222
232
*/
223
- function pancakeCall (
224
- address sender ,
225
- uint256 amount0 ,
226
- uint256 amount1 ,
227
- bytes calldata data
228
- ) external {
233
+ function pancakeCall (address sender , uint256 amount0 , uint256 amount1 , bytes calldata data ) external {
229
234
uniswapV2Call (sender, amount0, amount1, data);
230
235
}
231
236
232
- function moraswapCall (
233
- address sender ,
234
- uint256 amount0 ,
235
- uint256 amount1 ,
236
- bytes calldata data
237
- ) external {
237
+ function moraswapCall (address sender , uint256 amount0 , uint256 amount1 , bytes calldata data ) external {
238
238
uniswapV2Call (sender, amount0, amount1, data);
239
239
}
240
240
@@ -405,10 +405,10 @@ contract IonicLiquidator is OwnableUpgradeable, ILiquidator, IUniswapV2Callee {
405
405
* Each whitelisted redemption strategy has to be checked to not be able to
406
406
* call `selfdestruct` with the `delegatecall` call in `redeemCustomCollateral`
407
407
*/
408
- function _whitelistRedemptionStrategies (IRedemptionStrategy[] calldata strategies , bool [] calldata whitelisted )
409
- external
410
- onlyOwner
411
- {
408
+ function _whitelistRedemptionStrategies (
409
+ IRedemptionStrategy[] calldata strategies ,
410
+ bool [] calldata whitelisted
411
+ ) external onlyOwner {
412
412
require (
413
413
strategies.length > 0 && strategies.length == whitelisted.length ,
414
414
"list of strategies empty or whitelist does not match its length "
@@ -419,6 +419,10 @@ contract IonicLiquidator is OwnableUpgradeable, ILiquidator, IUniswapV2Callee {
419
419
}
420
420
}
421
421
422
+ function setExpressRelay (address _expressRelay ) external onlyOwner {
423
+ expressRelay = IExpressRelay (_expressRelay);
424
+ }
425
+
422
426
/**
423
427
* @dev Redeem "special" collateral tokens (before swapping the output for borrowed tokens to be repaid via Uniswap).
424
428
* Public visibility because we have to call this function externally if called from a payable IonicLiquidator function (for some reason delegatecall fails when called with msg.value > 0).
0 commit comments