diff --git a/contracts/arbitrum/connectors/aave/v3/events.sol b/contracts/arbitrum/connectors/aave/v3/events.sol index b29b4425..0324edcd 100644 --- a/contracts/arbitrum/connectors/aave/v3/events.sol +++ b/contracts/arbitrum/connectors/aave/v3/events.sol @@ -32,4 +32,34 @@ contract Events { event LogDisableCollateral(address[] tokens); event LogSwapRateMode(address indexed token, uint256 rateMode); event LogSetUserEMode(uint8 categoryId); + event LogDelegateBorrow( + address token, + uint256 amount, + uint256 rateMode, + address delegateTo, + uint256 getId, + uint256 setId + ); + event LogDepositWithoutCollateral( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ); + event LogBorrowOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ); + event LogPaybackOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ); } diff --git a/contracts/arbitrum/connectors/aave/v3/helpers.sol b/contracts/arbitrum/connectors/aave/v3/helpers.sol index 2d9243d3..61400738 100644 --- a/contracts/arbitrum/connectors/aave/v3/helpers.sol +++ b/contracts/arbitrum/connectors/aave/v3/helpers.sol @@ -50,6 +50,21 @@ abstract contract Helpers is DSMath, Basic { return rateMode == 1 ? stableDebt : variableDebt; } + /** + * @dev Get OnBehalfOf user's total debt balance & fee for an asset + * @param token token address of the debt.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param rateMode Borrow rate mode (Stable = 1, Variable = 2) + */ + function getOnBehalfOfPaybackBalance(address token, uint256 rateMode, address onBehalfOf) + internal + view + returns (uint256) + { + (, uint256 stableDebt, uint256 variableDebt, , , , , , ) = aaveData + .getUserReserveData(token, onBehalfOf); + return rateMode == 1 ? stableDebt : variableDebt; + } + /** * @dev Get total collateral balance for an asset * @param token token address of the collateral.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) @@ -64,4 +79,21 @@ abstract contract Helpers is DSMath, Basic { address(this) ); } + + /** + * @dev Get debt token address for an asset + * @param token token address of the asset + * @param rateMode Debt type: stable-1, variable-2 + */ + function getDTokenAddr(address token, uint256 rateMode) + internal + view + returns(address dToken) + { + if (rateMode == 1) { + (, dToken, ) = aaveData.getReserveTokensAddresses(token); + } else { + (, , dToken) = aaveData.getReserveTokensAddresses(token); + } + } } diff --git a/contracts/arbitrum/connectors/aave/v3/interface.sol b/contracts/arbitrum/connectors/aave/v3/interface.sol index 81553143..6de08261 100644 --- a/contracts/arbitrum/connectors/aave/v3/interface.sol +++ b/contracts/arbitrum/connectors/aave/v3/interface.sol @@ -90,3 +90,7 @@ interface AaveAddressProviderRegistryInterface { interface ATokenInterface { function balanceOf(address _user) external view returns (uint256); } + +interface DTokenInterface { + function approveDelegation(address delegatee, uint256 amount) external; +} diff --git a/contracts/arbitrum/connectors/aave/v3/main.sol b/contracts/arbitrum/connectors/aave/v3/main.sol index 150cebf0..e7365567 100644 --- a/contracts/arbitrum/connectors/aave/v3/main.sol +++ b/contracts/arbitrum/connectors/aave/v3/main.sol @@ -10,7 +10,7 @@ import { TokenInterface } from "../../../common/interfaces.sol"; import { Stores } from "../../../common/stores.sol"; import { Helpers } from "./helpers.sol"; import { Events } from "./events.sol"; -import { AaveInterface } from "./interface.sol"; +import { AaveInterface, DTokenInterface } from "./interface.sol"; abstract contract AaveResolver is Events, Helpers { /** @@ -63,6 +63,56 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, getId, setId); } + /** + * @dev Deposit ETH/ERC20_Token without collateral + * @notice Deposit a token to Aave v3 without enabling it as collateral. + * @param token The address of the token to deposit.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function depositWithoutCollateral( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isEth = token == ethAddr; + address _token = isEth ? wethAddr : token; + + TokenInterface tokenContract = TokenInterface(_token); + + if (isEth) { + _amt = _amt == uint256(-1) ? address(this).balance : _amt; + convertEthToWeth(isEth, tokenContract, _amt); + } else { + _amt = _amt == uint256(-1) + ? tokenContract.balanceOf(address(this)) + : _amt; + } + + approve(tokenContract, address(aave), _amt); + + aave.supply(_token, _amt, address(this), referralCode); + + if (getCollateralBalance(_token) > 0 && getIsColl(token)) { + aave.setUserUseReserveAsCollateral(_token, false); + } + + setUint(setId, _amt); + + _eventName = "LogDepositWithoutCollateral(address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, getId, setId); + } + /** * @dev Withdraw ETH/ERC20_Token. * @notice Withdraw deposited token from Aave v2 @@ -108,7 +158,7 @@ abstract contract AaveResolver is Events, Helpers { * @notice Borrow a token using Aave v2 * @param token The address of the token to borrow.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) * @param amt The amount of the token to borrow. - * @param rateMode The type of borrow debt. (For Stable: 1, Variable: 2) + * @param rateMode The type of debt. (For Stable: 1, Variable: 2) * @param getId ID to retrieve amt. * @param setId ID stores the amount of tokens borrowed. */ @@ -139,6 +189,44 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, rateMode, getId, setId); } + /** + * @dev Borrow ETH/ERC20_Token on behalf of a user. + * @notice Borrow a token using Aave v3 on behalf of a user + * @param token The address of the token to borrow.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to borrow. + * @param rateMode The type of debt. (For Stable: 1, Variable: 2) + * @param onBehalfOf The user who will incur the debt + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens borrowed. + */ + function borrowOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isEth = token == ethAddr; + address _token = isEth ? wethAddr : token; + + aave.borrow(_token, _amt, rateMode, referralCode, onBehalfOf); + convertWethToEth(isEth, TokenInterface(_token), _amt); + + setUint(setId, _amt); + + _eventName = "LogBorrowOnBehalfOf(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, onBehalfOf, getId, setId); + } + /** * @dev Payback borrowed ETH/ERC20_Token. * @notice Payback debt owed. @@ -225,6 +313,51 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, rateMode, getId, setId); } + /** + * @dev Payback borrowed ETH/ERC20_Token on behalf of a user. + * @notice Payback debt owed on behalf os a user. + * @param token The address of the token to payback.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to payback. (For max: `uint256(-1)`) + * @param rateMode The type of debt paying back. (For Stable: 1, Variable: 2) + * @param onBehalfOf Address of user who's debt to repay. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function paybackOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isEth = token == ethAddr; + address _token = isEth ? wethAddr : token; + + TokenInterface tokenContract = TokenInterface(_token); + + _amt = _amt == uint256(-1) ? getOnBehalfOfPaybackBalance(_token, rateMode, onBehalfOf) : _amt; + + if (isEth) convertEthToWeth(isEth, tokenContract, _amt); + + approve(tokenContract, address(aave), _amt); + + aave.repay(_token, _amt, rateMode, onBehalfOf); + + setUint(setId, _amt); + + _eventName = "LogPaybackOnBehalfOf(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, onBehalfOf, getId, setId); + } + /** * @dev Enable collateral * @notice Enable an array of tokens as collateral @@ -316,8 +449,45 @@ abstract contract AaveResolver is Events, Helpers { _eventName = "LogSetUserEMode(uint8)"; _eventParam = abi.encode(categoryId); } + + /** + * @dev Approve Delegation + * @notice Gives approval to delegate debt tokens + * @param token The address of token + * @param amount The amount + * @param rateMode The type of debt + * @param delegateTo The address to whom the user is delegating + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens delegated. + */ + function delegateBorrow( + address token, + uint256 amount, + uint256 rateMode, + address delegateTo, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + require(rateMode == 1 || rateMode == 2, "Invalid debt type"); + uint256 _amt = getUint(getId, amount); + + bool isEth = token == ethAddr; + address _token = isEth ? wethAddr : token; + + address _dToken = getDTokenAddr(_token, rateMode); + DTokenInterface(_dToken).approveDelegation(delegateTo, _amt); + + setUint(setId, _amt); + + _eventName = "LogDelegateBorrow(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, delegateTo, getId, setId); + } } contract ConnectV2AaveV3Arbitrum is AaveResolver { - string public constant name = "AaveV3-v1.1"; + string public constant name = "AaveV3-v1.2"; } diff --git a/contracts/avalanche/connectors/aave/v3/events.sol b/contracts/avalanche/connectors/aave/v3/events.sol index b29b4425..0324edcd 100644 --- a/contracts/avalanche/connectors/aave/v3/events.sol +++ b/contracts/avalanche/connectors/aave/v3/events.sol @@ -32,4 +32,34 @@ contract Events { event LogDisableCollateral(address[] tokens); event LogSwapRateMode(address indexed token, uint256 rateMode); event LogSetUserEMode(uint8 categoryId); + event LogDelegateBorrow( + address token, + uint256 amount, + uint256 rateMode, + address delegateTo, + uint256 getId, + uint256 setId + ); + event LogDepositWithoutCollateral( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ); + event LogBorrowOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ); + event LogPaybackOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ); } diff --git a/contracts/avalanche/connectors/aave/v3/helpers.sol b/contracts/avalanche/connectors/aave/v3/helpers.sol index d4c06017..08c68889 100644 --- a/contracts/avalanche/connectors/aave/v3/helpers.sol +++ b/contracts/avalanche/connectors/aave/v3/helpers.sol @@ -25,7 +25,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Checks if collateral is enabled for an asset - * @param token token address of the asset.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param token token address of the asset.(For avax: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) */ function getIsColl(address token) internal view returns (bool isCol) { @@ -37,7 +37,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Get total debt balance & fee for an asset - * @param token token address of the debt.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param token token address of the debt.(For avax: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) * @param rateMode Borrow rate mode (Stable = 1, Variable = 2) */ function getPaybackBalance(address token, uint256 rateMode) @@ -50,9 +50,24 @@ abstract contract Helpers is DSMath, Basic { return rateMode == 1 ? stableDebt : variableDebt; } + /** + * @dev Get OnBehalfOf user's total debt balance & fee for an asset + * @param token token address of the debt.(For avax: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param rateMode Borrow rate mode (Stable = 1, Variable = 2) + */ + function getOnBehalfOfPaybackBalance(address token, uint256 rateMode, address onBehalfOf) + internal + view + returns (uint256) + { + (, uint256 stableDebt, uint256 variableDebt, , , , , , ) = aaveData + .getUserReserveData(token, onBehalfOf); + return rateMode == 1 ? stableDebt : variableDebt; + } + /** * @dev Get total collateral balance for an asset - * @param token token address of the collateral.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param token token address of the collateral.(For avax: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) */ function getCollateralBalance(address token) internal @@ -64,4 +79,21 @@ abstract contract Helpers is DSMath, Basic { address(this) ); } + + /** + * @dev Get debt token address for an asset + * @param token token address of the asset + * @param rateMode Debt type: stable-1, variable-2 + */ + function getDTokenAddr(address token, uint256 rateMode) + internal + view + returns(address dToken) + { + if (rateMode == 1) { + (, dToken, ) = aaveData.getReserveTokensAddresses(token); + } else { + (, , dToken) = aaveData.getReserveTokensAddresses(token); + } + } } diff --git a/contracts/avalanche/connectors/aave/v3/interface.sol b/contracts/avalanche/connectors/aave/v3/interface.sol index 81553143..6de08261 100644 --- a/contracts/avalanche/connectors/aave/v3/interface.sol +++ b/contracts/avalanche/connectors/aave/v3/interface.sol @@ -90,3 +90,7 @@ interface AaveAddressProviderRegistryInterface { interface ATokenInterface { function balanceOf(address _user) external view returns (uint256); } + +interface DTokenInterface { + function approveDelegation(address delegatee, uint256 amount) external; +} diff --git a/contracts/avalanche/connectors/aave/v3/main.sol b/contracts/avalanche/connectors/aave/v3/main.sol index 611d12c6..beec94a7 100644 --- a/contracts/avalanche/connectors/aave/v3/main.sol +++ b/contracts/avalanche/connectors/aave/v3/main.sol @@ -10,7 +10,7 @@ import { TokenInterface } from "../../../common/interfaces.sol"; import { Stores } from "../../../common/stores.sol"; import { Helpers } from "./helpers.sol"; import { Events } from "./events.sol"; -import { AaveInterface } from "./interface.sol"; +import { AaveInterface, DTokenInterface } from "./interface.sol"; abstract contract AaveResolver is Events, Helpers { /** @@ -63,6 +63,56 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, getId, setId); } + /** + * @dev Deposit avax/ERC20_Token without collateral + * @notice Deposit a token to Aave v3 without enabling it as collateral. + * @param token The address of the token to deposit.(For avax: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function depositWithoutCollateral( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isAVAX = token == avaxAddr; + address _token = isAVAX ? wavaxAddr : token; + + TokenInterface tokenContract = TokenInterface(_token); + + if (isAVAX) { + _amt = _amt == uint256(-1) ? address(this).balance : _amt; + convertAvaxToWavax(isAVAX, tokenContract, _amt); + } else { + _amt = _amt == uint256(-1) + ? tokenContract.balanceOf(address(this)) + : _amt; + } + + approve(tokenContract, address(aave), _amt); + + aave.supply(_token, _amt, address(this), referralCode); + + if (getCollateralBalance(_token) > 0 && getIsColl(token)) { + aave.setUserUseReserveAsCollateral(_token, false); + } + + setUint(setId, _amt); + + _eventName = "LogDepositWithoutCollateral(address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, getId, setId); + } + /** * @dev Withdraw avax/ERC20_Token. * @notice Withdraw deposited token from Aave v3 @@ -108,7 +158,7 @@ abstract contract AaveResolver is Events, Helpers { * @notice Borrow a token using Aave v3 * @param token The address of the token to borrow.(For avax: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) * @param amt The amount of the token to borrow. - * @param rateMode The type of borrow debt. (For Stable: 1, Variable: 2) + * @param rateMode The type of debt. (For Stable: 1, Variable: 2) * @param getId ID to retrieve amt. * @param setId ID stores the amount of tokens borrowed. */ @@ -139,6 +189,44 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, rateMode, getId, setId); } + /** + * @dev Borrow avax/ERC20_Token on behalf of a user. + * @notice Borrow a token using Aave v3 on behalf of a user + * @param token The address of the token to borrow.(For avax: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to borrow. + * @param rateMode The type of debt. (For Stable: 1, Variable: 2) + * @param onBehalfOf The user who will incur the debt + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens borrowed. + */ + function borrowOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isAVAX = token == avaxAddr; + address _token = isAVAX ? wavaxAddr : token; + + aave.borrow(_token, _amt, rateMode, referralCode, onBehalfOf); + convertWavaxToAvax(isAVAX, TokenInterface(_token), _amt); + + setUint(setId, _amt); + + _eventName = "LogBorrowOnBehalfOf(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, onBehalfOf, getId, setId); + } + /** * @dev Payback borrowed avax/ERC20_Token. * @notice Payback debt owed. @@ -225,6 +313,51 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, rateMode, getId, setId); } + /** + * @dev Payback borrowed avax/ERC20_Token on behalf of a user. + * @notice Payback debt owed on behalf os a user. + * @param token The address of the token to payback.(For avax: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to payback. (For max: `uint256(-1)`) + * @param rateMode The type of debt paying back. (For Stable: 1, Variable: 2) + * @param onBehalfOf Address of user who's debt to repay. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function paybackOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isAVAX = token == avaxAddr; + address _token = isAVAX ? wavaxAddr : token; + + TokenInterface tokenContract = TokenInterface(_token); + + _amt = _amt == uint256(-1) ? getOnBehalfOfPaybackBalance(_token, rateMode, onBehalfOf) : _amt; + + if (isAVAX) convertAvaxToWavax(isAVAX, tokenContract, _amt); + + approve(tokenContract, address(aave), _amt); + + aave.repay(_token, _amt, rateMode, onBehalfOf); + + setUint(setId, _amt); + + _eventName = "LogPaybackOnBehalfOf(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, onBehalfOf, getId, setId); + } + /** * @dev Enable collateral * @notice Enable an array of tokens as collateral @@ -315,8 +448,45 @@ abstract contract AaveResolver is Events, Helpers { _eventName = "LogSetUserEMode(uint8)"; _eventParam = abi.encode(categoryId); } + + /** + * @dev Approve Delegation + * @notice Gives approval to delegate debt tokens + * @param token The address of token + * @param amount The amount + * @param rateMode The type of debt + * @param delegateTo The address to whom the user is delegating + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens delegated. + */ + function approveDelegation( + address token, + uint256 amount, + uint256 rateMode, + address delegateTo, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + require(rateMode == 1 || rateMode == 2, "Invalid debt type"); + uint256 _amt = getUint(getId, amount); + + bool isAVAX = token == avaxAddr; + address _token = isAVAX ? wavaxAddr : token; + + address _dToken = getDTokenAddr(_token, rateMode); + DTokenInterface(_dToken).approveDelegation(delegateTo, _amt); + + setUint(setId, _amt); + + _eventName = "LogDelegateBorrow(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, delegateTo, getId, setId); + } } contract ConnectV2AaveV3Avalanche is AaveResolver { - string public constant name = "AaveV3-v1.1"; + string public constant name = "AaveV3-v1.2"; } diff --git a/contracts/fantom/connectors/aave/v3/events.sol b/contracts/fantom/connectors/aave/v3/events.sol index b29b4425..0324edcd 100644 --- a/contracts/fantom/connectors/aave/v3/events.sol +++ b/contracts/fantom/connectors/aave/v3/events.sol @@ -32,4 +32,34 @@ contract Events { event LogDisableCollateral(address[] tokens); event LogSwapRateMode(address indexed token, uint256 rateMode); event LogSetUserEMode(uint8 categoryId); + event LogDelegateBorrow( + address token, + uint256 amount, + uint256 rateMode, + address delegateTo, + uint256 getId, + uint256 setId + ); + event LogDepositWithoutCollateral( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ); + event LogBorrowOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ); + event LogPaybackOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ); } diff --git a/contracts/fantom/connectors/aave/v3/helpers.sol b/contracts/fantom/connectors/aave/v3/helpers.sol index 537db40a..e0605c8d 100644 --- a/contracts/fantom/connectors/aave/v3/helpers.sol +++ b/contracts/fantom/connectors/aave/v3/helpers.sol @@ -25,7 +25,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Checks if collateral is enabled for an asset - * @param token token address of the asset.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param token token address of the asset.(For Ftm: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) */ function getIsColl(address token) internal view returns (bool isCol) { @@ -37,7 +37,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Get total debt balance & fee for an asset - * @param token token address of the debt.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param token token address of the debt.(For Ftm: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) * @param rateMode Borrow rate mode (Stable = 1, Variable = 2) */ function getPaybackBalance(address token, uint256 rateMode) @@ -50,9 +50,24 @@ abstract contract Helpers is DSMath, Basic { return rateMode == 1 ? stableDebt : variableDebt; } + /** + * @dev Get OnBehalfOf user's total debt balance & fee for an asset + * @param token token address of the debt.(For Ftm: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param rateMode Borrow rate mode (Stable = 1, Variable = 2) + */ + function getOnBehalfOfPaybackBalance(address token, uint256 rateMode, address onBehalfOf) + internal + view + returns (uint256) + { + (, uint256 stableDebt, uint256 variableDebt, , , , , , ) = aaveData + .getUserReserveData(token, onBehalfOf); + return rateMode == 1 ? stableDebt : variableDebt; + } + /** * @dev Get total collateral balance for an asset - * @param token token address of the collateral.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param token token address of the collateral.(For Ftm: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) */ function getCollateralBalance(address token) internal @@ -64,4 +79,21 @@ abstract contract Helpers is DSMath, Basic { address(this) ); } + + /** + * @dev Get debt token address for an asset + * @param token token address of the asset + * @param rateMode Debt type: stable-1, variable-2 + */ + function getDTokenAddr(address token, uint256 rateMode) + internal + view + returns(address dToken) + { + if (rateMode == 1) { + (, dToken, ) = aaveData.getReserveTokensAddresses(token); + } else { + (, , dToken) = aaveData.getReserveTokensAddresses(token); + } + } } diff --git a/contracts/fantom/connectors/aave/v3/interface.sol b/contracts/fantom/connectors/aave/v3/interface.sol index 81553143..6de08261 100644 --- a/contracts/fantom/connectors/aave/v3/interface.sol +++ b/contracts/fantom/connectors/aave/v3/interface.sol @@ -90,3 +90,7 @@ interface AaveAddressProviderRegistryInterface { interface ATokenInterface { function balanceOf(address _user) external view returns (uint256); } + +interface DTokenInterface { + function approveDelegation(address delegatee, uint256 amount) external; +} diff --git a/contracts/fantom/connectors/aave/v3/main.sol b/contracts/fantom/connectors/aave/v3/main.sol index 75f1a9b6..2a35f3dd 100644 --- a/contracts/fantom/connectors/aave/v3/main.sol +++ b/contracts/fantom/connectors/aave/v3/main.sol @@ -10,7 +10,7 @@ import { TokenInterface } from "../../../common/interfaces.sol"; import { Stores } from "../../../common/stores.sol"; import { Helpers } from "./helpers.sol"; import { Events } from "./events.sol"; -import { AaveInterface } from "./interface.sol"; +import { AaveInterface, DTokenInterface } from "./interface.sol"; abstract contract AaveResolver is Events, Helpers { /** @@ -63,6 +63,56 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, getId, setId); } + /** + * @dev Deposit Ftm/ERC20_Token without collateral + * @notice Deposit a token to Aave v3 without enabling it as collateral. + * @param token The address of the token to deposit.(For FTM: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function depositWithoutCollateral( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isFTM = token == ftmAddr; + address _token = isFTM ? wftmAddr : token; + + TokenInterface tokenContract = TokenInterface(_token); + + if (isFTM) { + _amt = _amt == uint256(-1) ? address(this).balance : _amt; + convertFtmToWftm(isFTM, tokenContract, _amt); + } else { + _amt = _amt == uint256(-1) + ? tokenContract.balanceOf(address(this)) + : _amt; + } + + approve(tokenContract, address(aave), _amt); + + aave.supply(_token, _amt, address(this), referralCode); + + if (getCollateralBalance(_token) > 0 && getIsColl(token)) { + aave.setUserUseReserveAsCollateral(_token, false); + } + + setUint(setId, _amt); + + _eventName = "LogDepositWithoutCollateral(address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, getId, setId); + } + /** * @dev Withdraw ftm/ERC20_Token. * @notice Withdraw deposited token from Aave v3 @@ -108,7 +158,7 @@ abstract contract AaveResolver is Events, Helpers { * @notice Borrow a token using Aave v3 * @param token The address of the token to borrow.(For ftm: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) * @param amt The amount of the token to borrow. - * @param rateMode The type of borrow debt. (For Stable: 1, Variable: 2) + * @param rateMode The type of debt. (For Stable: 1, Variable: 2) * @param getId ID to retrieve amt. * @param setId ID stores the amount of tokens borrowed. */ @@ -139,6 +189,44 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, rateMode, getId, setId); } + /** + * @dev Borrow Ftm/ERC20_Token on behalf of a user. + * @notice Borrow a token using Aave v3 on behalf of a user + * @param token The address of the token to borrow.(For FTM: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to borrow. + * @param rateMode The type of debt. (For Stable: 1, Variable: 2) + * @param onBehalfOf The user who will incur the debt + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens borrowed. + */ + function borrowOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isFTM = token == ftmAddr; + address _token = isFTM ? wftmAddr : token; + + aave.borrow(_token, _amt, rateMode, referralCode, onBehalfOf); + convertWftmToFtm(isFTM, TokenInterface(_token), _amt); + + setUint(setId, _amt); + + _eventName = "LogBorrowOnBehalfOf(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, onBehalfOf, getId, setId); + } + /** * @dev Payback borrowed ftm/ERC20_Token. * @notice Payback debt owed. @@ -225,6 +313,51 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, rateMode, getId, setId); } + /** + * @dev Payback borrowed ftm/ERC20_Token on behalf of a user. + * @notice Payback debt owed on behalf os a user. + * @param token The address of the token to payback.(For ftm: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to payback. (For max: `uint256(-1)`) + * @param rateMode The type of debt paying back. (For Stable: 1, Variable: 2) + * @param onBehalfOf Address of user who's debt to repay. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function paybackOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isFTM = token == ftmAddr; + address _token = isFTM ? wftmAddr : token; + + TokenInterface tokenContract = TokenInterface(_token); + + _amt = _amt == uint256(-1) ? getOnBehalfOfPaybackBalance(_token, rateMode, onBehalfOf) : _amt; + + if (isFTM) convertFtmToWftm(isFTM, tokenContract, _amt); + + approve(tokenContract, address(aave), _amt); + + aave.repay(_token, _amt, rateMode, onBehalfOf); + + setUint(setId, _amt); + + _eventName = "LogPaybackOnBehalfOf(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, onBehalfOf, getId, setId); + } + /** * @dev Enable collateral * @notice Enable an array of tokens as collateral @@ -316,8 +449,46 @@ abstract contract AaveResolver is Events, Helpers { _eventName = "LogSetUserEMode(uint8)"; _eventParam = abi.encode(categoryId); } + + /** + * @dev Approve Delegation + * @notice Gives approval to delegate debt tokens + * @param token The address of token + * @param amount The amount + * @param rateMode The type of debt + * @param delegateTo The address to whom the user is delegating + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens delegated. + */ + function delegateBorrow( + address token, + uint256 amount, + uint256 rateMode, + address delegateTo, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + require(rateMode == 1 || rateMode == 2, "Invalid debt type"); + uint256 _amt = getUint(getId, amount); + + bool isFTM = token == ftmAddr; + address _token = isFTM ? wftmAddr : token; + + address _dToken = getDTokenAddr(_token, rateMode); + DTokenInterface(_dToken).approveDelegation(delegateTo, _amt); + + setUint(setId, _amt); + + _eventName = "LogDelegateBorrow(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, delegateTo, getId, setId); + + } } contract ConnectV2AaveV3Fantom is AaveResolver { - string public constant name = "AaveV3-v1.1"; + string public constant name = "AaveV3-v1.2"; } diff --git a/contracts/mainnet/connectors/aave/v3/events.sol b/contracts/mainnet/connectors/aave/v3/events.sol index 09c88ea7..e60aaa12 100644 --- a/contracts/mainnet/connectors/aave/v3/events.sol +++ b/contracts/mainnet/connectors/aave/v3/events.sol @@ -31,4 +31,34 @@ contract Events { event LogEnableCollateral(address[] tokens); event LogSwapRateMode(address indexed token, uint256 rateMode); event LogSetUserEMode(uint8 categoryId); + event LogDelegateBorrow( + address token, + uint256 amount, + uint256 rateMode, + address delegateTo, + uint256 getId, + uint256 setId + ); + event LogDepositWithoutCollateral( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ); + event LogBorrowOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ); + event LogPaybackOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ); } diff --git a/contracts/mainnet/connectors/aave/v3/helpers.sol b/contracts/mainnet/connectors/aave/v3/helpers.sol index e14e0fbe..1927aaa5 100644 --- a/contracts/mainnet/connectors/aave/v3/helpers.sol +++ b/contracts/mainnet/connectors/aave/v3/helpers.sol @@ -50,6 +50,21 @@ abstract contract Helpers is DSMath, Basic { return rateMode == 1 ? stableDebt : variableDebt; } + /** + * @dev Get OnBehalfOf user's total debt balance & fee for an asset + * @param token token address of the debt.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param rateMode Borrow rate mode (Stable = 1, Variable = 2) + */ + function getOnBehalfOfPaybackBalance(address token, uint256 rateMode, address onBehalfOf) + internal + view + returns (uint256) + { + (, uint256 stableDebt, uint256 variableDebt, , , , , , ) = aaveData + .getUserReserveData(token, onBehalfOf); + return rateMode == 1 ? stableDebt : variableDebt; + } + /** * @dev Get total collateral balance for an asset * @param token token address of the collateral.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) @@ -64,4 +79,21 @@ abstract contract Helpers is DSMath, Basic { address(this) ); } + + /** + * @dev Get debt token address for an asset + * @param token token address of the asset + * @param rateMode Debt type: stable-1, variable-2 + */ + function getDTokenAddr(address token, uint256 rateMode) + internal + view + returns(address dToken) + { + if (rateMode == 1) { + (, dToken, ) = aaveData.getReserveTokensAddresses(token); + } else { + (, , dToken) = aaveData.getReserveTokensAddresses(token); + } + } } diff --git a/contracts/mainnet/connectors/aave/v3/interface.sol b/contracts/mainnet/connectors/aave/v3/interface.sol index 81553143..6de08261 100644 --- a/contracts/mainnet/connectors/aave/v3/interface.sol +++ b/contracts/mainnet/connectors/aave/v3/interface.sol @@ -90,3 +90,7 @@ interface AaveAddressProviderRegistryInterface { interface ATokenInterface { function balanceOf(address _user) external view returns (uint256); } + +interface DTokenInterface { + function approveDelegation(address delegatee, uint256 amount) external; +} diff --git a/contracts/mainnet/connectors/aave/v3/main.sol b/contracts/mainnet/connectors/aave/v3/main.sol index 2ac93267..dd78cd6e 100644 --- a/contracts/mainnet/connectors/aave/v3/main.sol +++ b/contracts/mainnet/connectors/aave/v3/main.sol @@ -10,7 +10,7 @@ import { TokenInterface } from "../../../common/interfaces.sol"; import { Stores } from "../../../common/stores.sol"; import { Helpers } from "./helpers.sol"; import { Events } from "./events.sol"; -import { AaveInterface } from "./interface.sol"; +import { AaveInterface, DTokenInterface } from "./interface.sol"; abstract contract AaveResolver is Events, Helpers { /** @@ -63,6 +63,56 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, getId, setId); } + /** + * @dev Deposit ETH/ERC20_Token without collateral + * @notice Deposit a token to Aave v3 without enabling it as collateral. + * @param token The address of the token to deposit.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function depositWithoutCollateral( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isEth = token == ethAddr; + address _token = isEth ? wethAddr : token; + + TokenInterface tokenContract = TokenInterface(_token); + + if (isEth) { + _amt = _amt == uint256(-1) ? address(this).balance : _amt; + convertEthToWeth(isEth, tokenContract, _amt); + } else { + _amt = _amt == uint256(-1) + ? tokenContract.balanceOf(address(this)) + : _amt; + } + + approve(tokenContract, address(aave), _amt); + + aave.supply(_token, _amt, address(this), referralCode); + + if (getCollateralBalance(_token) > 0 && getIsColl(token)) { + aave.setUserUseReserveAsCollateral(_token, false); + } + + setUint(setId, _amt); + + _eventName = "LogDepositWithoutCollateral(address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, getId, setId); + } + /** * @dev Withdraw ETH/ERC20_Token. * @notice Withdraw deposited token from Aave v3 @@ -108,7 +158,7 @@ abstract contract AaveResolver is Events, Helpers { * @notice Borrow a token using Aave v3 * @param token The address of the token to borrow.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) * @param amt The amount of the token to borrow. - * @param rateMode The type of borrow debt. (For Stable: 1, Variable: 2) + * @param rateMode The type of debt. (For Stable: 1, Variable: 2) * @param getId ID to retrieve amt. * @param setId ID stores the amount of tokens borrowed. */ @@ -139,6 +189,44 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, rateMode, getId, setId); } + /** + * @dev Borrow ETH/ERC20_Token on behalf of a user. + * @notice Borrow a token using Aave v3 on behalf of a user + * @param token The address of the token to borrow.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to borrow. + * @param rateMode The type of debt. (For Stable: 1, Variable: 2) + * @param onBehalfOf The user who will incur the debt + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens borrowed. + */ + function borrowOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isEth = token == ethAddr; + address _token = isEth ? wethAddr : token; + + aave.borrow(_token, _amt, rateMode, referralCode, onBehalfOf); + convertWethToEth(isEth, TokenInterface(_token), _amt); + + setUint(setId, _amt); + + _eventName = "LogBorrowOnBehalfOf(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, onBehalfOf, getId, setId); + } + /** * @dev Payback borrowed ETH/ERC20_Token. * @notice Payback debt owed. @@ -225,6 +313,52 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, rateMode, getId, setId); } + /** + * @dev Payback borrowed ETH/ERC20_Token on behalf of a user. + * @notice Payback debt owed on behalf os a user. + * @param token The address of the token to payback.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to payback. (For max: `uint256(-1)`) + * @param rateMode The type of debt paying back. (For Stable: 1, Variable: 2) + * @param onBehalfOf Address of user who's debt to repay. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function paybackOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isEth = token == ethAddr; + address _token = isEth ? wethAddr : token; + + TokenInterface tokenContract = TokenInterface(_token); + + _amt = _amt == uint256(-1) ? getOnBehalfOfPaybackBalance(_token, rateMode, onBehalfOf) : _amt; + + if (isEth) convertEthToWeth(isEth, tokenContract, _amt); + + approve(tokenContract, address(aave), _amt); + + aave.repay(_token, _amt, rateMode, onBehalfOf); + + setUint(setId, _amt); + + _eventName = "LogPaybackOnBehalfOf(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, onBehalfOf, getId, setId); + } + + /** * @dev Enable collateral * @notice Enable an array of tokens as collateral @@ -291,6 +425,44 @@ abstract contract AaveResolver is Events, Helpers { _eventName = "LogSetUserEMode(uint8)"; _eventParam = abi.encode(categoryId); } + + /** + * @dev Approve Delegation + * @notice Gives approval to delegate debt tokens + * @param token The address of token + * @param amount The amount + * @param rateMode The type of debt + * @param delegateTo The address to whom the user is delegating + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens delegated. + */ + function delegateBorrow( + address token, + uint256 amount, + uint256 rateMode, + address delegateTo, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + require(rateMode == 1 || rateMode == 2, "Invalid debt type"); + uint256 _amt = getUint(getId, amount); + + bool isEth = token == ethAddr; + address _token = isEth ? wethAddr : token; + + address _dToken = getDTokenAddr(_token, rateMode); + DTokenInterface(_dToken).approveDelegation(delegateTo, _amt); + + setUint(setId, _amt); + + _eventName = "LogDelegateBorrow(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, delegateTo, getId, setId); + + } } contract ConnectV2AaveV3 is AaveResolver { diff --git a/contracts/optimism/connectors/aave/v3/events.sol b/contracts/optimism/connectors/aave/v3/events.sol index b29b4425..0324edcd 100644 --- a/contracts/optimism/connectors/aave/v3/events.sol +++ b/contracts/optimism/connectors/aave/v3/events.sol @@ -32,4 +32,34 @@ contract Events { event LogDisableCollateral(address[] tokens); event LogSwapRateMode(address indexed token, uint256 rateMode); event LogSetUserEMode(uint8 categoryId); + event LogDelegateBorrow( + address token, + uint256 amount, + uint256 rateMode, + address delegateTo, + uint256 getId, + uint256 setId + ); + event LogDepositWithoutCollateral( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ); + event LogBorrowOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ); + event LogPaybackOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ); } diff --git a/contracts/optimism/connectors/aave/v3/helpers.sol b/contracts/optimism/connectors/aave/v3/helpers.sol index ae72fa02..35cebed8 100644 --- a/contracts/optimism/connectors/aave/v3/helpers.sol +++ b/contracts/optimism/connectors/aave/v3/helpers.sol @@ -50,6 +50,21 @@ abstract contract Helpers is DSMath, Basic { return rateMode == 1 ? stableDebt : variableDebt; } + /** + * @dev Get OnBehalfOf user's total debt balance & fee for an asset + * @param token token address of the debt.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param rateMode Borrow rate mode (Stable = 1, Variable = 2) + */ + function getOnBehalfOfPaybackBalance(address token, uint256 rateMode, address onBehalfOf) + internal + view + returns (uint256) + { + (, uint256 stableDebt, uint256 variableDebt, , , , , , ) = aaveData + .getUserReserveData(token, onBehalfOf); + return rateMode == 1 ? stableDebt : variableDebt; + } + /** * @dev Get total collateral balance for an asset * @param token token address of the collateral.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) @@ -64,4 +79,21 @@ abstract contract Helpers is DSMath, Basic { address(this) ); } + + /** + * @dev Get debt token address for an asset + * @param token token address of the asset + * @param rateMode Debt type: stable-1, variable-2 + */ + function getDTokenAddr(address token, uint256 rateMode) + internal + view + returns(address dToken) + { + if (rateMode == 1) { + (, dToken, ) = aaveData.getReserveTokensAddresses(token); + } else { + (, , dToken) = aaveData.getReserveTokensAddresses(token); + } + } } diff --git a/contracts/optimism/connectors/aave/v3/interface.sol b/contracts/optimism/connectors/aave/v3/interface.sol index 81553143..6de08261 100644 --- a/contracts/optimism/connectors/aave/v3/interface.sol +++ b/contracts/optimism/connectors/aave/v3/interface.sol @@ -90,3 +90,7 @@ interface AaveAddressProviderRegistryInterface { interface ATokenInterface { function balanceOf(address _user) external view returns (uint256); } + +interface DTokenInterface { + function approveDelegation(address delegatee, uint256 amount) external; +} diff --git a/contracts/optimism/connectors/aave/v3/main.sol b/contracts/optimism/connectors/aave/v3/main.sol index e98ae77e..04992f43 100644 --- a/contracts/optimism/connectors/aave/v3/main.sol +++ b/contracts/optimism/connectors/aave/v3/main.sol @@ -10,7 +10,7 @@ import { TokenInterface } from "../../../common/interfaces.sol"; import { Stores } from "../../../common/stores.sol"; import { Helpers } from "./helpers.sol"; import { Events } from "./events.sol"; -import { AaveInterface } from "./interface.sol"; +import { AaveInterface, DTokenInterface } from "./interface.sol"; abstract contract AaveResolver is Events, Helpers { /** @@ -63,6 +63,56 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, getId, setId); } + /** + * @dev Deposit ETH/ERC20_Token without collateral + * @notice Deposit a token to Aave v3 without enabling it as collateral. + * @param token The address of the token to deposit.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function depositWithoutCollateral( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isEth = token == ethAddr; + address _token = isEth ? wethAddr : token; + + TokenInterface tokenContract = TokenInterface(_token); + + if (isEth) { + _amt = _amt == uint256(-1) ? address(this).balance : _amt; + convertEthToWeth(isEth, tokenContract, _amt); + } else { + _amt = _amt == uint256(-1) + ? tokenContract.balanceOf(address(this)) + : _amt; + } + + approve(tokenContract, address(aave), _amt); + + aave.supply(_token, _amt, address(this), referralCode); + + if (getCollateralBalance(_token) > 0 && getIsColl(token)) { + aave.setUserUseReserveAsCollateral(_token, false); + } + + setUint(setId, _amt); + + _eventName = "LogDepositWithoutCollateral(address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, getId, setId); + } + /** * @dev Withdraw ETH/ERC20_Token. * @notice Withdraw deposited token from Aave v3 @@ -108,7 +158,7 @@ abstract contract AaveResolver is Events, Helpers { * @notice Borrow a token using Aave v3 * @param token The address of the token to borrow.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) * @param amt The amount of the token to borrow. - * @param rateMode The type of borrow debt. (For Stable: 1, Variable: 2) + * @param rateMode The type of debt. (For Stable: 1, Variable: 2) * @param getId ID to retrieve amt. * @param setId ID stores the amount of tokens borrowed. */ @@ -139,6 +189,44 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, rateMode, getId, setId); } + /** + * @dev Borrow ETH/ERC20_Token on behalf of a user. + * @notice Borrow a token using Aave v3 on behalf of a user + * @param token The address of the token to borrow.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to borrow. + * @param rateMode The type of debt. (For Stable: 1, Variable: 2) + * @param onBehalfOf The user who will incur the debt + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens borrowed. + */ + function borrowOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isEth = token == ethAddr; + address _token = isEth ? wethAddr : token; + + aave.borrow(_token, _amt, rateMode, referralCode, onBehalfOf); + convertWethToEth(isEth, TokenInterface(_token), _amt); + + setUint(setId, _amt); + + _eventName = "LogBorrowOnBehalfOf(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, onBehalfOf, getId, setId); + } + /** * @dev Payback borrowed ETH/ERC20_Token. * @notice Payback debt owed. @@ -225,6 +313,51 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, rateMode, getId, setId); } + /** + * @dev Payback borrowed ETH/ERC20_Token on behalf of a user. + * @notice Payback debt owed on behalf os a user. + * @param token The address of the token to payback.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to payback. (For max: `uint256(-1)`) + * @param rateMode The type of debt paying back. (For Stable: 1, Variable: 2) + * @param onBehalfOf Address of user who's debt to repay. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function paybackOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isEth = token == ethAddr; + address _token = isEth ? wethAddr : token; + + TokenInterface tokenContract = TokenInterface(_token); + + _amt = _amt == uint256(-1) ? getOnBehalfOfPaybackBalance(_token, rateMode, onBehalfOf) : _amt; + + if (isEth) convertEthToWeth(isEth, tokenContract, _amt); + + approve(tokenContract, address(aave), _amt); + + aave.repay(_token, _amt, rateMode, onBehalfOf); + + setUint(setId, _amt); + + _eventName = "LogPaybackOnBehalfOf(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, onBehalfOf, getId, setId); + } + /** * @dev Enable collateral * @notice Enable an array of tokens as collateral @@ -316,8 +449,45 @@ abstract contract AaveResolver is Events, Helpers { _eventName = "LogSetUserEMode(uint8)"; _eventParam = abi.encode(categoryId); } + + /** + * @dev Approve Delegation + * @notice Gives approval to delegate debt tokens + * @param token The address of token + * @param amount The amount + * @param rateMode The type of debt + * @param delegateTo The address to whom the user is delegating + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens delegated. + */ + function delegateBorrow( + address token, + uint256 amount, + uint256 rateMode, + address delegateTo, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + require(rateMode == 1 || rateMode == 2, "Invalid debt type"); + uint256 _amt = getUint(getId, amount); + + bool isEth = token == ethAddr; + address _token = isEth ? wethAddr : token; + + address _dToken = getDTokenAddr(_token, rateMode); + DTokenInterface(_dToken).approveDelegation(delegateTo, _amt); + + setUint(setId, _amt); + + _eventName = "LogDelegateBorrow(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, delegateTo, getId, setId); + } } contract ConnectV2AaveV3Optimism is AaveResolver { - string public constant name = "AaveV3-v1.1"; + string public constant name = "AaveV3-v1.2"; } diff --git a/contracts/polygon/connectors/aave/v3/events.sol b/contracts/polygon/connectors/aave/v3/events.sol index b29b4425..0324edcd 100644 --- a/contracts/polygon/connectors/aave/v3/events.sol +++ b/contracts/polygon/connectors/aave/v3/events.sol @@ -32,4 +32,34 @@ contract Events { event LogDisableCollateral(address[] tokens); event LogSwapRateMode(address indexed token, uint256 rateMode); event LogSetUserEMode(uint8 categoryId); + event LogDelegateBorrow( + address token, + uint256 amount, + uint256 rateMode, + address delegateTo, + uint256 getId, + uint256 setId + ); + event LogDepositWithoutCollateral( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ); + event LogBorrowOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ); + event LogPaybackOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ); } diff --git a/contracts/polygon/connectors/aave/v3/helpers.sol b/contracts/polygon/connectors/aave/v3/helpers.sol index 567e9ddd..1f21db85 100644 --- a/contracts/polygon/connectors/aave/v3/helpers.sol +++ b/contracts/polygon/connectors/aave/v3/helpers.sol @@ -25,7 +25,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Checks if collateral is enabled for an asset - * @param token token address of the asset.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param token token address of the asset.(For matic: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) */ function getIsColl(address token) internal view returns (bool isCol) { @@ -37,7 +37,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Get total debt balance & fee for an asset - * @param token token address of the debt.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param token token address of the debt.(For matic: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) * @param rateMode Borrow rate mode (Stable = 1, Variable = 2) */ function getPaybackBalance(address token, uint256 rateMode) @@ -50,9 +50,24 @@ abstract contract Helpers is DSMath, Basic { return rateMode == 1 ? stableDebt : variableDebt; } + /** + * @dev Get OnBehalfOf user's total debt balance & fee for an asset + * @param token token address of the debt.(For matic: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param rateMode Borrow rate mode (Stable = 1, Variable = 2) + */ + function getOnBehalfOfPaybackBalance(address token, uint256 rateMode, address onBehalfOf) + internal + view + returns (uint256) + { + (, uint256 stableDebt, uint256 variableDebt, , , , , , ) = aaveData + .getUserReserveData(token, onBehalfOf); + return rateMode == 1 ? stableDebt : variableDebt; + } + /** * @dev Get total collateral balance for an asset - * @param token token address of the collateral.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param token token address of the collateral.(For matic: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) */ function getCollateralBalance(address token) internal @@ -64,4 +79,21 @@ abstract contract Helpers is DSMath, Basic { address(this) ); } + + /** + * @dev Get debt token address for an asset + * @param token token address of the asset + * @param rateMode Debt type: stable-1, variable-2 + */ + function getDTokenAddr(address token, uint256 rateMode) + internal + view + returns(address dToken) + { + if (rateMode == 1) { + (, dToken, ) = aaveData.getReserveTokensAddresses(token); + } else { + (, , dToken) = aaveData.getReserveTokensAddresses(token); + } + } } diff --git a/contracts/polygon/connectors/aave/v3/interface.sol b/contracts/polygon/connectors/aave/v3/interface.sol index 81553143..6de08261 100644 --- a/contracts/polygon/connectors/aave/v3/interface.sol +++ b/contracts/polygon/connectors/aave/v3/interface.sol @@ -90,3 +90,7 @@ interface AaveAddressProviderRegistryInterface { interface ATokenInterface { function balanceOf(address _user) external view returns (uint256); } + +interface DTokenInterface { + function approveDelegation(address delegatee, uint256 amount) external; +} diff --git a/contracts/polygon/connectors/aave/v3/main.sol b/contracts/polygon/connectors/aave/v3/main.sol index 44c5c57a..d60d1b21 100644 --- a/contracts/polygon/connectors/aave/v3/main.sol +++ b/contracts/polygon/connectors/aave/v3/main.sol @@ -10,7 +10,7 @@ import { TokenInterface } from "../../../common/interfaces.sol"; import { Stores } from "../../../common/stores.sol"; import { Helpers } from "./helpers.sol"; import { Events } from "./events.sol"; -import { AaveInterface } from "./interface.sol"; +import { AaveInterface, DTokenInterface } from "./interface.sol"; abstract contract AaveResolver is Events, Helpers { /** @@ -63,6 +63,56 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, getId, setId); } + /** + ** @dev Deposit Matic/ERC20_Token without collateral + * @notice Deposit a token to Aave v3 without enabling it as collateral. + * @param token The address of the token to deposit.(For Matic: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function depositWithoutCollateral( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isMatic = token == maticAddr; + address _token = isMatic ? wmaticAddr : token; + + TokenInterface tokenContract = TokenInterface(_token); + + if (isMatic) { + _amt = _amt == uint256(-1) ? address(this).balance : _amt; + convertMaticToWmatic(isMatic, tokenContract, _amt); + } else { + _amt = _amt == uint256(-1) + ? tokenContract.balanceOf(address(this)) + : _amt; + } + + approve(tokenContract, address(aave), _amt); + + aave.supply(_token, _amt, address(this), referralCode); + + if (getCollateralBalance(_token) > 0 && getIsColl(token)) { + aave.setUserUseReserveAsCollateral(_token, false); + } + + setUint(setId, _amt); + + _eventName = "LogDepositWithoutCollateral(address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, getId, setId); + } + /** * @dev Withdraw matic/ERC20_Token. * @notice Withdraw deposited token from Aave v3 @@ -139,6 +189,44 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, rateMode, getId, setId); } + /** + * @dev Borrow matic/ERC20_Token on behalf of a user. + * @notice Borrow a token using Aave v3 on behalf of a user + * @param token The address of the token to borrow.(For matic: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to borrow. + * @param rateMode The type of borrow debt. (For Stable: 1, Variable: 2) + * @param onBehalfOf The user who will incur the debt + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens borrowed. + */ + function borrowOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isMatic = token == maticAddr; + address _token = isMatic ? wmaticAddr : token; + + aave.borrow(_token, _amt, rateMode, referralCode, onBehalfOf); + convertWmaticToMatic(isMatic, TokenInterface(_token), _amt); + + setUint(setId, _amt); + + _eventName = "LogBorrowOnBehalfOf(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, onBehalfOf, getId, setId); + } + /** * @dev Payback borrowed matic/ERC20_Token. * @notice Payback debt owed. @@ -225,6 +313,51 @@ abstract contract AaveResolver is Events, Helpers { _eventParam = abi.encode(token, _amt, rateMode, getId, setId); } + /** + * @dev Payback borrowed matic/ERC20_Token on behalf of a user. + * @notice Payback debt owed on behalf os a user. + * @param token The address of the token to payback.(For matic: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to payback. (For max: `uint256(-1)`) + * @param rateMode The type of debt paying back. (For Stable: 1, Variable: 2) + * @param onBehalfOf Address of user who's debt to repay. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function paybackOnBehalfOf( + address token, + uint256 amt, + uint256 rateMode, + address onBehalfOf, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + bool isMatic = token == maticAddr; + address _token = isMatic ? wmaticAddr : token; + + TokenInterface tokenContract = TokenInterface(_token); + + _amt = _amt == uint256(-1) ? getOnBehalfOfPaybackBalance(_token, rateMode, onBehalfOf) : _amt; + + if (isMatic) convertMaticToWmatic(isMatic, tokenContract, _amt); + + approve(tokenContract, address(aave), _amt); + + aave.repay(_token, _amt, rateMode, onBehalfOf); + + setUint(setId, _amt); + + _eventName = "LogPaybackOnBehalfOf(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, onBehalfOf, getId, setId); + } + /** * @dev Enable collateral * @notice Enable an array of tokens as collateral @@ -317,8 +450,45 @@ abstract contract AaveResolver is Events, Helpers { _eventName = "LogSetUserEMode(uint8)"; _eventParam = abi.encode(categoryId); } + + /** + * @dev Approve Delegation + * @notice Gives approval to delegate debt tokens + * @param token The address of token + * @param amount The amount + * @param rateMode The type of borrow debt + * @param delegateTo The address to whom the user is delegating + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function delegateBorrow( + address token, + uint256 amount, + uint256 rateMode, + address delegateTo, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + require(rateMode == 1 || rateMode == 2, "Invalid debt type"); + uint256 _amt = getUint(getId, amount); + + bool isMatic = token == maticAddr; + address _token = isMatic ? wmaticAddr : token; + + address _dToken = getDTokenAddr(_token, rateMode); + DTokenInterface(_dToken).approveDelegation(delegateTo, _amt); + + setUint(setId, _amt); + + _eventName = "LogDelegateBorrow(address,uint256,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, _amt, rateMode, delegateTo, getId, setId); + } } contract ConnectV2AaveV3Polygon is AaveResolver { - string public constant name = "AaveV3-v1.1"; + string public constant name = "AaveV3-v1.2"; } diff --git a/hardhat.config.ts b/hardhat.config.ts index 4a4e7a21..12280e70 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -40,7 +40,7 @@ const mnemonic = process.env.MNEMONIC ?? "test test test test test test test tes const networkGasPriceConfig: Record = { mainnet: 100, polygon: 50, - avalanche: 30, + avalanche: 40, arbitrum: 1, optimism: 0.001, fantom: 300