Branch data Line data Source code
1 : : // SPDX-License-Identifier: BUSL-1.1
2 : : pragma solidity ^0.8.10;
3 : :
4 : : import {Ownable} from '../dependencies/openzeppelin/contracts/Ownable.sol';
5 : : import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
6 : : import {GPv2SafeERC20} from '../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
7 : : import {IWETH} from './interfaces/IWETH.sol';
8 : : import {IPool} from '../interfaces/IPool.sol';
9 : : import {IAToken} from '../interfaces/IAToken.sol';
10 : : import {ReserveConfiguration} from '../protocol/libraries/configuration/ReserveConfiguration.sol';
11 : : import {UserConfiguration} from '../protocol/libraries/configuration/UserConfiguration.sol';
12 : : import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
13 : : import {IWrappedTokenGatewayV3} from './interfaces/IWrappedTokenGatewayV3.sol';
14 : :
15 : : /**
16 : : * @dev This contract is an upgrade of the WrappedTokenGatewayV3 contract, with immutable pool address.
17 : : * This contract keeps the same interface of the deprecated WrappedTokenGatewayV3 contract.
18 : : */
19 : : contract WrappedTokenGatewayV3 is IWrappedTokenGatewayV3, Ownable {
20 : : using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
21 : : using UserConfiguration for DataTypes.UserConfigurationMap;
22 : : using GPv2SafeERC20 for IERC20;
23 : :
24 : : IWETH internal immutable WETH;
25 : : IPool internal immutable POOL;
26 : :
27 : : /**
28 : : * @dev Sets the WETH address and the PoolAddressesProvider address. Infinite approves pool.
29 : : * @param weth Address of the Wrapped Ether contract
30 : : * @param owner Address of the owner of this contract
31 : : **/
32 : : constructor(address weth, address owner, IPool pool) {
33 : 0 : WETH = IWETH(weth);
34 : 0 : POOL = pool;
35 : 0 : transferOwnership(owner);
36 : 0 : IWETH(weth).approve(address(pool), type(uint256).max);
37 : : }
38 : :
39 : : /**
40 : : * @dev deposits WETH into the reserve, using native ETH. A corresponding amount of the overlying asset (aTokens)
41 : : * is minted.
42 : : * @param onBehalfOf address of the user who will receive the aTokens representing the deposit
43 : : * @param referralCode integrators are assigned a referral code and can potentially receive rewards.
44 : : **/
45 : : function depositETH(address, address onBehalfOf, uint16 referralCode) external payable override {
46 : 8 : WETH.deposit{value: msg.value}();
47 : 8 : POOL.deposit(address(WETH), msg.value, onBehalfOf, referralCode);
48 : : }
49 : :
50 : : /**
51 : : * @dev withdraws the WETH _reserves of msg.sender.
52 : : * @param amount amount of aWETH to withdraw and receive native ETH
53 : : * @param to address of the user who will receive native ETH
54 : : */
55 : : function withdrawETH(address, uint256 amount, address to) external override {
56 : 2 : IAToken aWETH = IAToken(POOL.getReserveData(address(WETH)).aTokenAddress);
57 : 2 : uint256 userBalance = aWETH.balanceOf(msg.sender);
58 : 2 : uint256 amountToWithdraw = amount;
59 : :
60 : : // if amount is equal to uint(-1), the user wants to redeem everything
61 : 2 : if (amount == type(uint256).max) {
62 : 1 : amountToWithdraw = userBalance;
63 : : }
64 : 2 : aWETH.transferFrom(msg.sender, address(this), amountToWithdraw);
65 : 2 : POOL.withdraw(address(WETH), amountToWithdraw, address(this));
66 : 2 : WETH.withdraw(amountToWithdraw);
67 : 2 : _safeTransferETH(to, amountToWithdraw);
68 : : }
69 : :
70 : : /**
71 : : * @dev repays a borrow on the WETH reserve, for the specified amount (or for the whole amount, if uint256(-1) is specified).
72 : : * @param amount the amount to repay, or uint256(-1) if the user wants to repay everything
73 : : * @param onBehalfOf the address for which msg.sender is repaying
74 : : */
75 : : function repayETH(address, uint256 amount, address onBehalfOf) external payable override {
76 : 5 : uint256 paybackAmount = IERC20((POOL.getReserveData(address(WETH))).variableDebtTokenAddress)
77 : : .balanceOf(onBehalfOf);
78 : :
79 : 5 : if (amount < paybackAmount) {
80 : 2 : paybackAmount = amount;
81 : : }
82 : 5 : require(msg.value >= paybackAmount, 'msg.value is less than repayment amount');
83 : 5 : WETH.deposit{value: paybackAmount}();
84 : 5 : POOL.repay(
85 : : address(WETH),
86 : : paybackAmount,
87 : : uint256(DataTypes.InterestRateMode.VARIABLE),
88 : : onBehalfOf
89 : : );
90 : :
91 : : // refund remaining dust eth
92 : 5 : if (msg.value > paybackAmount) _safeTransferETH(msg.sender, msg.value - paybackAmount);
93 : : }
94 : :
95 : : /**
96 : : * @dev borrow WETH, unwraps to ETH and send both the ETH and DebtTokens to msg.sender, via `approveDelegation` and onBehalf argument in `Pool.borrow`.
97 : : * @param amount the amount of ETH to borrow
98 : : * @param referralCode integrators are assigned a referral code and can potentially receive rewards
99 : : */
100 : : function borrowETH(address, uint256 amount, uint16 referralCode) external override {
101 : 1 : POOL.borrow(
102 : : address(WETH),
103 : : amount,
104 : : uint256(DataTypes.InterestRateMode.VARIABLE),
105 : : referralCode,
106 : : msg.sender
107 : : );
108 : 1 : WETH.withdraw(amount);
109 : 1 : _safeTransferETH(msg.sender, amount);
110 : : }
111 : :
112 : : /**
113 : : * @dev withdraws the WETH _reserves of msg.sender.
114 : : * @param amount amount of aWETH to withdraw and receive native ETH
115 : : * @param to address of the user who will receive native ETH
116 : : * @param deadline validity deadline of permit and so depositWithPermit signature
117 : : * @param permitV V parameter of ERC712 permit sig
118 : : * @param permitR R parameter of ERC712 permit sig
119 : : * @param permitS S parameter of ERC712 permit sig
120 : : */
121 : : function withdrawETHWithPermit(
122 : : address,
123 : : uint256 amount,
124 : : address to,
125 : : uint256 deadline,
126 : : uint8 permitV,
127 : : bytes32 permitR,
128 : : bytes32 permitS
129 : : ) external override {
130 : 2 : IAToken aWETH = IAToken(POOL.getReserveData(address(WETH)).aTokenAddress);
131 : 2 : uint256 userBalance = aWETH.balanceOf(msg.sender);
132 : 2 : uint256 amountToWithdraw = amount;
133 : :
134 : : // if amount is equal to type(uint256).max, the user wants to redeem everything
135 : 2 : if (amount == type(uint256).max) {
136 : 1 : amountToWithdraw = userBalance;
137 : : }
138 : : // permit `amount` rather than `amountToWithdraw` to make it easier for front-ends and integrators
139 : 2 : aWETH.permit(msg.sender, address(this), amount, deadline, permitV, permitR, permitS);
140 : 2 : aWETH.transferFrom(msg.sender, address(this), amountToWithdraw);
141 : 2 : POOL.withdraw(address(WETH), amountToWithdraw, address(this));
142 : 2 : WETH.withdraw(amountToWithdraw);
143 : 2 : _safeTransferETH(to, amountToWithdraw);
144 : : }
145 : :
146 : : /**
147 : : * @dev transfer ETH to an address, revert if it fails.
148 : : * @param to recipient of the transfer
149 : : * @param value the amount to send
150 : : */
151 : : function _safeTransferETH(address to, uint256 value) internal {
152 : 7 : (bool success, ) = to.call{value: value}(new bytes(0));
153 : 7 : require(success, 'ETH_TRANSFER_FAILED');
154 : : }
155 : :
156 : : /**
157 : : * @dev transfer ERC20 from the utility contract, for ERC20 recovery in case of stuck tokens due
158 : : * direct transfers to the contract address.
159 : : * @param token token to transfer
160 : : * @param to recipient of the transfer
161 : : * @param amount amount to send
162 : : */
163 : : function emergencyTokenTransfer(address token, address to, uint256 amount) external onlyOwner {
164 : 1 : IERC20(token).safeTransfer(to, amount);
165 : : }
166 : :
167 : : /**
168 : : * @dev transfer native Ether from the utility contract, for native Ether recovery in case of stuck Ether
169 : : * due to selfdestructs or ether transfers to the pre-computed contract address before deployment.
170 : : * @param to recipient of the transfer
171 : : * @param amount amount to send
172 : : */
173 : : function emergencyEtherTransfer(address to, uint256 amount) external onlyOwner {
174 : 1 : _safeTransferETH(to, amount);
175 : : }
176 : :
177 : : /**
178 : : * @dev Get WETH address used by WrappedTokenGatewayV3
179 : : */
180 : : function getWETHAddress() external view returns (address) {
181 : 1 : return address(WETH);
182 : : }
183 : :
184 : : /**
185 : : * @dev Only WETH contract is allowed to transfer ETH here. Prevent other addresses to send Ether to this contract.
186 : : */
187 : : receive() external payable {
188 : : require(msg.sender == address(WETH), 'Receive not allowed');
189 : : }
190 : :
191 : : /**
192 : : * @dev Revert fallback calls
193 : : */
194 : : fallback() external payable {
195 : 2 : revert('Fallback not allowed');
196 : : }
197 : : }
|