33pragma solidity 0.8.28 ;
44
55import {ReentrancyGuardTransient} from 'src/dependencies/openzeppelin/ReentrancyGuardTransient.sol ' ;
6- import {Ownable2Step, Ownable} from 'src/dependencies/openzeppelin/Ownable2Step.sol ' ;
76import {SafeERC20, IERC20 } from 'src/dependencies/openzeppelin/SafeERC20.sol ' ;
87import {Address} from 'src/dependencies/openzeppelin/Address.sol ' ;
98import {MathUtils} from 'src/libraries/math/MathUtils.sol ' ;
10- import {Rescuable} from 'src/utils/Rescuable.sol ' ;
119import {ISpoke} from 'src/spoke/interfaces/ISpoke.sol ' ;
1210import {INativeWrapper} from 'src/position-manager/interfaces/INativeWrapper.sol ' ;
11+ import {GatewayBase} from 'src/position-manager/GatewayBase.sol ' ;
1312import {INativeTokenGateway} from 'src/position-manager/interfaces/INativeTokenGateway.sol ' ;
1413
1514/// @title NativeTokenGateway
1615/// @author Aave Labs
1716/// @notice Gateway to interact with a spoke using the native coin of a chain.
1817/// @dev Contract must be an active & approved user position manager in order to execute spoke actions on a user's behalf.
19- contract NativeTokenGateway is
20- INativeTokenGateway ,
21- ReentrancyGuardTransient ,
22- Rescuable ,
23- Ownable2Step
24- {
18+ contract NativeTokenGateway is INativeTokenGateway , GatewayBase , ReentrancyGuardTransient {
2519 using SafeERC20 for * ;
2620
2721 INativeWrapper internal immutable _nativeWrapper;
28- ISpoke internal immutable _spoke;
2922
3023 /// @dev Constructor.
3124 /// @param nativeWrapper_ The address of the native wrapper contract.
32- /// @param spoke_ The address of the connected spoke.
3325 /// @param initialOwner_ The address of the initial owner.
34- constructor (
35- address nativeWrapper_ ,
36- address spoke_ ,
37- address initialOwner_
38- ) Ownable (initialOwner_) {
39- require (nativeWrapper_ != address (0 ) && spoke_ != address (0 ), InvalidAddress ());
26+ constructor (address nativeWrapper_ , address initialOwner_ ) GatewayBase (initialOwner_) {
27+ require (nativeWrapper_ != address (0 ), InvalidAddress ());
4028 _nativeWrapper = INativeWrapper (payable (nativeWrapper_));
41- _spoke = ISpoke (spoke_);
4229 }
4330
4431 /// @dev Checks only 'nativeWrapper' can transfer native tokens.
@@ -52,95 +39,103 @@ contract NativeTokenGateway is
5239 }
5340
5441 /// @inheritdoc INativeTokenGateway
55- function supplyNative (uint256 reserveId , uint256 amount ) external payable nonReentrant {
56- (IERC20 underlying , address hub ) = _getReserveData (reserveId);
57- _validateParams (underlying, amount);
42+ function supplyNative (
43+ address spoke ,
44+ uint256 reserveId ,
45+ uint256 amount
46+ ) external payable nonReentrant onlyRegisteredSpoke (spoke) {
5847 require (msg .value == amount, NativeAmountMismatch ());
48+ _supplyNative (spoke, reserveId, msg .sender , amount);
49+ }
5950
60- _nativeWrapper.deposit {value: amount}();
61- _nativeWrapper.forceApprove (hub, amount);
62- _spoke.supply (reserveId, amount, msg .sender );
51+ /// @inheritdoc INativeTokenGateway
52+ function supplyAsCollateralNative (
53+ address spoke ,
54+ uint256 reserveId ,
55+ uint256 amount
56+ ) external payable nonReentrant onlyRegisteredSpoke (spoke) {
57+ require (msg .value == amount, NativeAmountMismatch ());
58+ _supplyNative (spoke, reserveId, msg .sender , amount);
59+ ISpoke (spoke).setUsingAsCollateral (reserveId, true , msg .sender );
6360 }
6461
6562 /// @inheritdoc INativeTokenGateway
66- function withdrawNative (uint256 reserveId , uint256 amount , address receiver ) external {
67- (IERC20 underlying , ) = _getReserveData (reserveId);
63+ function withdrawNative (
64+ address spoke ,
65+ uint256 reserveId ,
66+ uint256 amount
67+ ) external onlyRegisteredSpoke (spoke) {
68+ (address underlying , ) = _getReserveData (spoke, reserveId);
6869 _validateParams (underlying, amount);
69- require (receiver != address (0 ), InvalidAddress ());
7070
7171 uint256 withdrawAmount = MathUtils.min (
7272 amount,
73- _spoke .getUserSuppliedAssets (reserveId, msg .sender )
73+ ISpoke (spoke) .getUserSuppliedAssets (reserveId, msg .sender )
7474 );
7575
76- _spoke .withdraw (reserveId, withdrawAmount, msg .sender );
76+ ISpoke (spoke) .withdraw (reserveId, withdrawAmount, msg .sender );
7777 _nativeWrapper.withdraw (withdrawAmount);
78- Address.sendValue (payable (receiver ), withdrawAmount);
78+ Address.sendValue (payable (msg . sender ), withdrawAmount);
7979 }
8080
8181 /// @inheritdoc INativeTokenGateway
82- function borrowNative (uint256 reserveId , uint256 amount , address receiver ) external {
83- (IERC20 underlying , ) = _getReserveData (reserveId);
82+ function borrowNative (
83+ address spoke ,
84+ uint256 reserveId ,
85+ uint256 amount
86+ ) external onlyRegisteredSpoke (spoke) {
87+ (address underlying , ) = _getReserveData (spoke, reserveId);
8488 _validateParams (underlying, amount);
85- require (receiver != address (0 ), InvalidAddress ());
8689
87- _spoke .borrow (reserveId, amount, msg .sender );
90+ ISpoke (spoke) .borrow (reserveId, amount, msg .sender );
8891 _nativeWrapper.withdraw (amount);
89- Address.sendValue (payable (receiver ), amount);
92+ Address.sendValue (payable (msg . sender ), amount);
9093 }
9194
9295 /// @inheritdoc INativeTokenGateway
93- function repayNative (uint256 reserveId , uint256 amount ) external payable nonReentrant {
94- (IERC20 underlying , address hub ) = _getReserveData (reserveId);
95- _validateParams (underlying, amount);
96+ function repayNative (
97+ address spoke ,
98+ uint256 reserveId ,
99+ uint256 amount
100+ ) external payable nonReentrant onlyRegisteredSpoke (spoke) {
96101 require (msg .value == amount, NativeAmountMismatch ());
102+ (address underlying , address hub ) = _getReserveData (spoke, reserveId);
103+ _validateParams (underlying, amount);
97104
98- uint256 userDebtAmount = _spoke .getUserTotalDebt (reserveId, msg .sender );
105+ uint256 userTotalDebt = ISpoke (spoke) .getUserTotalDebt (reserveId, msg .sender );
99106 uint256 repayAmount = amount;
100107 uint256 leftovers;
101- if (amount > userDebtAmount ) {
102- leftovers = amount - userDebtAmount ;
103- repayAmount = userDebtAmount ;
108+ if (amount > userTotalDebt ) {
109+ leftovers = amount - userTotalDebt ;
110+ repayAmount = userTotalDebt ;
104111 }
105112
106113 _nativeWrapper.deposit {value: repayAmount}();
107114 _nativeWrapper.forceApprove (hub, repayAmount);
108- _spoke .repay (reserveId, repayAmount, msg .sender );
115+ ISpoke (spoke) .repay (reserveId, repayAmount, msg .sender );
109116
110117 if (leftovers > 0 ) {
111118 Address.sendValue (payable (msg .sender ), leftovers);
112119 }
113120 }
114121
115- /// @inheritdoc INativeTokenGateway
116- function renouncePositionManagerRole (address user ) external onlyOwner {
117- _spoke.renouncePositionManagerRole (user);
118- }
119-
120122 /// @inheritdoc INativeTokenGateway
121123 function NATIVE_WRAPPER () external view returns (address ) {
122124 return address (_nativeWrapper);
123125 }
124126
125- /// @inheritdoc INativeTokenGateway
126- function SPOKE () external view returns ( address ) {
127- return address (_spoke );
128- }
127+ /// @dev `msg.value` verification must be done before calling this.
128+ function _supplyNative ( address spoke , uint256 reserveId , address user , uint256 amount ) internal {
129+ ( address underlying , address hub ) = _getReserveData (spoke, reserveId );
130+ _validateParams (underlying, amount);
129131
130- /// @dev RescueGuardian is the owner of the contract.
131- function _rescueGuardian () internal view override returns ( address ) {
132- return owner ( );
132+ _nativeWrapper. deposit {value: amount}();
133+ _nativeWrapper. forceApprove (hub, amount);
134+ ISpoke (spoke). supply (reserveId, amount, user );
133135 }
134136
135- function _validateParams (IERC20 underlying , uint256 amount ) internal view {
136- require (address (underlying ) == address (_nativeWrapper) , NotNativeWrappedAsset ());
137+ function _validateParams (address underlying , uint256 amount ) internal view {
138+ require (address (_nativeWrapper ) == underlying , NotNativeWrappedAsset ());
137139 require (amount > 0 , InvalidAmount ());
138140 }
139-
140- /// @return The underlying asset for `reserveId` on connected spoke.
141- /// @return The corresponding hub address.
142- function _getReserveData (uint256 reserveId ) internal view returns (IERC20 , address ) {
143- ISpoke.Reserve memory reserveData = _spoke.getReserve (reserveId);
144- return (IERC20 (reserveData.underlying), address (reserveData.hub));
145- }
146141}
0 commit comments