forked from aave-dao/aave-v3-origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
WrappedTokenGatewayV3.sol
198 lines (179 loc) · 7.53 KB
/
WrappedTokenGatewayV3.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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.10;
import {Ownable} from '../dependencies/openzeppelin/contracts/Ownable.sol';
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
import {GPv2SafeERC20} from '../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
import {IWETH} from './interfaces/IWETH.sol';
import {IPool} from '../interfaces/IPool.sol';
import {IAToken} from '../interfaces/IAToken.sol';
import {ReserveConfiguration} from '../protocol/libraries/configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../protocol/libraries/configuration/UserConfiguration.sol';
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
import {IWrappedTokenGatewayV3} from './interfaces/IWrappedTokenGatewayV3.sol';
/**
* @dev This contract is an upgrade of the WrappedTokenGatewayV3 contract, with immutable pool address.
* This contract keeps the same interface of the deprecated WrappedTokenGatewayV3 contract.
*/
contract WrappedTokenGatewayV3 is IWrappedTokenGatewayV3, Ownable {
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using UserConfiguration for DataTypes.UserConfigurationMap;
using GPv2SafeERC20 for IERC20;
IWETH public immutable WETH;
IPool public immutable POOL;
/**
* @dev Sets the WETH address and the PoolAddressesProvider address. Infinite approves pool.
* @param weth Address of the Wrapped Ether contract
* @param owner Address of the owner of this contract
**/
constructor(address weth, address owner, IPool pool) {
WETH = IWETH(weth);
POOL = pool;
transferOwnership(owner);
IWETH(weth).approve(address(pool), type(uint256).max);
}
/**
* @dev deposits WETH into the reserve, using native ETH. A corresponding amount of the overlying asset (aTokens)
* is minted.
* @param onBehalfOf address of the user who will receive the aTokens representing the deposit
* @param referralCode integrators are assigned a referral code and can potentially receive rewards.
**/
function depositETH(address, address onBehalfOf, uint16 referralCode) external payable override {
WETH.deposit{value: msg.value}();
POOL.deposit(address(WETH), msg.value, onBehalfOf, referralCode);
}
/**
* @dev withdraws the WETH _reserves of msg.sender.
* @param amount amount of aWETH to withdraw and receive native ETH
* @param to address of the user who will receive native ETH
*/
function withdrawETH(address, uint256 amount, address to) external override {
IAToken aWETH = IAToken(POOL.getReserveAToken(address(WETH)));
uint256 userBalance = aWETH.balanceOf(msg.sender);
uint256 amountToWithdraw = amount;
// if amount is equal to uint(-1), the user wants to redeem everything
if (amount == type(uint256).max) {
amountToWithdraw = userBalance;
}
aWETH.transferFrom(msg.sender, address(this), amountToWithdraw);
POOL.withdraw(address(WETH), amountToWithdraw, address(this));
WETH.withdraw(amountToWithdraw);
_safeTransferETH(to, amountToWithdraw);
}
/**
* @dev repays a borrow on the WETH reserve, for the specified amount (or for the whole amount, if uint256(-1) is specified).
* @param amount the amount to repay, or uint256(-1) if the user wants to repay everything
* @param onBehalfOf the address for which msg.sender is repaying
*/
function repayETH(address, uint256 amount, address onBehalfOf) external payable override {
uint256 paybackAmount = IERC20(POOL.getReserveVariableDebtToken(address(WETH))).balanceOf(
onBehalfOf
);
if (amount < paybackAmount) {
paybackAmount = amount;
}
require(msg.value >= paybackAmount, 'msg.value is less than repayment amount');
WETH.deposit{value: paybackAmount}();
POOL.repay(
address(WETH),
paybackAmount,
uint256(DataTypes.InterestRateMode.VARIABLE),
onBehalfOf
);
// refund remaining dust eth
if (msg.value > paybackAmount) _safeTransferETH(msg.sender, msg.value - paybackAmount);
}
/**
* @dev borrow WETH, unwraps to ETH and send both the ETH and DebtTokens to msg.sender, via `approveDelegation` and onBehalf argument in `Pool.borrow`.
* @param amount the amount of ETH to borrow
* @param referralCode integrators are assigned a referral code and can potentially receive rewards
*/
function borrowETH(address, uint256 amount, uint16 referralCode) external override {
POOL.borrow(
address(WETH),
amount,
uint256(DataTypes.InterestRateMode.VARIABLE),
referralCode,
msg.sender
);
WETH.withdraw(amount);
_safeTransferETH(msg.sender, amount);
}
/**
* @dev withdraws the WETH _reserves of msg.sender.
* @param amount amount of aWETH to withdraw and receive native ETH
* @param to address of the user who will receive native ETH
* @param deadline validity deadline of permit and so depositWithPermit signature
* @param permitV V parameter of ERC712 permit sig
* @param permitR R parameter of ERC712 permit sig
* @param permitS S parameter of ERC712 permit sig
*/
function withdrawETHWithPermit(
address,
uint256 amount,
address to,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external override {
IAToken aWETH = IAToken(POOL.getReserveAToken(address(WETH)));
uint256 userBalance = aWETH.balanceOf(msg.sender);
uint256 amountToWithdraw = amount;
// if amount is equal to type(uint256).max, the user wants to redeem everything
if (amount == type(uint256).max) {
amountToWithdraw = userBalance;
}
// permit `amount` rather than `amountToWithdraw` to make it easier for front-ends and integrators
aWETH.permit(msg.sender, address(this), amount, deadline, permitV, permitR, permitS);
aWETH.transferFrom(msg.sender, address(this), amountToWithdraw);
POOL.withdraw(address(WETH), amountToWithdraw, address(this));
WETH.withdraw(amountToWithdraw);
_safeTransferETH(to, amountToWithdraw);
}
/**
* @dev transfer ETH to an address, revert if it fails.
* @param to recipient of the transfer
* @param value the amount to send
*/
function _safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'ETH_TRANSFER_FAILED');
}
/**
* @dev transfer ERC20 from the utility contract, for ERC20 recovery in case of stuck tokens due
* direct transfers to the contract address.
* @param token token to transfer
* @param to recipient of the transfer
* @param amount amount to send
*/
function emergencyTokenTransfer(address token, address to, uint256 amount) external onlyOwner {
IERC20(token).safeTransfer(to, amount);
}
/**
* @dev transfer native Ether from the utility contract, for native Ether recovery in case of stuck Ether
* due to selfdestructs or ether transfers to the pre-computed contract address before deployment.
* @param to recipient of the transfer
* @param amount amount to send
*/
function emergencyEtherTransfer(address to, uint256 amount) external onlyOwner {
_safeTransferETH(to, amount);
}
/**
* @dev Get WETH address used by WrappedTokenGatewayV3
*/
function getWETHAddress() external view returns (address) {
return address(WETH);
}
/**
* @dev Only WETH contract is allowed to transfer ETH here. Prevent other addresses to send Ether to this contract.
*/
receive() external payable {
require(msg.sender == address(WETH), 'Receive not allowed');
}
/**
* @dev Revert fallback calls
*/
fallback() external payable {
revert('Fallback not allowed');
}
}