diff --git a/contracts/polygon/connectors/gelato/aave-services/protection/helpers.sol b/contracts/polygon/connectors/gelato/aave-services/protection/helpers.sol new file mode 100644 index 00000000..1f43b799 --- /dev/null +++ b/contracts/polygon/connectors/gelato/aave-services/protection/helpers.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.7.6; + +import {LendingPoolInterface, AaveServicesInterface} from "./interface.sol"; + +abstract contract Helpers { + // solhint-disable-next-line const-name-snakecase + LendingPoolInterface internal constant _lendingPool = + LendingPoolInterface(0x8dFf5E27EA6b7AC08EbFdf9eB090F32ee9a30fcf); + + // solhint-disable-next-line const-name-snakecase + AaveServicesInterface internal constant _aaveServices = + AaveServicesInterface(0x18FAbC997fDd624764E1974b283B1b904b66d613); + + // solhint-disable-next-line const-name-snakecase + address internal constant _protectionAction = + 0xc38b6dbd0F84777AA4fae2d36FE1506428A22b9B; +} diff --git a/contracts/polygon/connectors/gelato/aave-services/protection/interface.sol b/contracts/polygon/connectors/gelato/aave-services/protection/interface.sol new file mode 100644 index 00000000..097afb22 --- /dev/null +++ b/contracts/polygon/connectors/gelato/aave-services/protection/interface.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.7.6; +pragma abicoder v2; + +struct ReserveData { + //stores the reserve configuration + ReserveConfigurationMap configuration; + //the liquidity index. Expressed in ray + uint128 liquidityIndex; + //variable borrow index. Expressed in ray + uint128 variableBorrowIndex; + //the current supply rate. Expressed in ray + uint128 currentLiquidityRate; + //the current variable borrow rate. Expressed in ray + uint128 currentVariableBorrowRate; + //the current stable borrow rate. Expressed in ray + uint128 currentStableBorrowRate; + uint40 lastUpdateTimestamp; + //tokens addresses + address aTokenAddress; + address stableDebtTokenAddress; + address variableDebtTokenAddress; + //address of the interest rate strategy + address interestRateStrategyAddress; + //the id of the reserve. Represents the position in the list of the active reserves + uint8 id; +} + +struct ReserveConfigurationMap { + //bit 0-15: LTV + //bit 16-31: Liq. threshold + //bit 32-47: Liq. bonus + //bit 48-55: Decimals + //bit 56: Reserve is active + //bit 57: reserve is frozen + //bit 58: borrowing is enabled + //bit 59: stable rate borrowing enabled + //bit 60-63: reserved + //bit 64-79: reserve factor + uint256 data; +} + +interface LendingPoolInterface { + function getReservesList() external view returns (address[] memory); + + function getReserveData(address asset) + external + view + returns (ReserveData memory); +} + +interface AaveServicesInterface { + function submitTask( + address _action, + bytes memory _taskData, + bool _isPermanent + ) external; + + function cancelTask(address _action) external; + + function updateTask( + address _action, + bytes memory _data, + bool _isPermanent + ) external; + + function taskByUsersAction(address _user, address _action) + external + view + returns (bytes32); +} + +interface IERC20 { + function approve(address spender, uint256 amount) external returns (bool); + + function allowance(address owner, address spender) + external + view + returns (uint256); +} diff --git a/contracts/polygon/connectors/gelato/aave-services/protection/main.sol b/contracts/polygon/connectors/gelato/aave-services/protection/main.sol new file mode 100644 index 00000000..7ed7bc9a --- /dev/null +++ b/contracts/polygon/connectors/gelato/aave-services/protection/main.sol @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.7.6; +pragma abicoder v2; + +/** + * @title Aave Protection. + * @dev Protect DSA against Liquidation risk on Aave with Gelato. + */ + + +import {IERC20} from "./interface.sol"; +import {Helpers} from "./helpers.sol"; + +abstract contract GAaveProtectionResolver is Helpers { + /// @dev Function for submitting a protection task + /// @param _wantedHealthFactor targeted health after protection. + /// @param _minimumHealthFactor trigger protection when current health + /// factor is below _minimumHealthFactor. + /// @param _isPermanent boolean to set a protection as permanent + function submitProtection( + uint256 _wantedHealthFactor, + uint256 _minimumHealthFactor, + bool _isPermanent + ) external payable { + _submitProtection( + _wantedHealthFactor, + _minimumHealthFactor, + _isPermanent + ); + } + + /// @dev Function for modifying a protection task + /// @param _wantedHealthFactor targeted health after protection. + /// @param _minimumHealthFactor trigger protection when current health + /// factor is below _minimumHealthFactor. + /// @param _isPermanent boolean to set a protection as permanent + function updateProtection( + uint256 _wantedHealthFactor, + uint256 _minimumHealthFactor, + bool _isPermanent + ) external payable { + _updateProtection( + _wantedHealthFactor, + _minimumHealthFactor, + _isPermanent + ); + } + + /// @dev Function for cancelling a protection task + function cancelProtection() external payable { + _cancelProtection(); + } + + /// @dev Function for cancelling and removing allowance + /// of aToken to _protectionAction + function cancelAndRevoke() external payable { + if (_dsaHasProtection()) _cancelProtection(); + _revokeAllowance(); + } + + function _submitProtection( + uint256 _wantedHealthFactor, + uint256 _minimumHealthFactor, + bool _isPermanent + ) internal { + _giveAllowance(); + + _aaveServices.submitTask( + _protectionAction, + abi.encode( + _wantedHealthFactor, + _minimumHealthFactor, + address(this) + ), + _isPermanent + ); + } + + function _updateProtection( + uint256 _wantedHealthFactor, + uint256 _minimumHealthFactor, + bool _isPermanent + ) internal { + _giveAllowance(); + + _aaveServices.updateTask( + _protectionAction, + abi.encode( + _wantedHealthFactor, + _minimumHealthFactor, + address(this) + ), + _isPermanent + ); + } + + function _cancelProtection() internal { + _aaveServices.cancelTask(_protectionAction); + } + + function _giveAllowance() internal { + address[] memory aTokenList = _getATokenList(); + for (uint256 i = 0; i < aTokenList.length; i++) { + if ( + !(IERC20(aTokenList[i]).allowance( + address(this), + _protectionAction + ) == type(uint256).max) + ) { + IERC20(aTokenList[i]).approve( + _protectionAction, + type(uint256).max + ); + } + } + } + + function _revokeAllowance() internal { + address[] memory aTokenList = _getATokenList(); + for (uint256 i = 0; i < aTokenList.length; i++) { + if ( + !(IERC20(aTokenList[i]).allowance( + address(this), + _protectionAction + ) == 0) + ) { + IERC20(aTokenList[i]).approve(_protectionAction, 0); + } + } + } + + function _getATokenList() + internal + view + returns (address[] memory aTokenList) + { + address[] memory underlyingsList = _lendingPool.getReservesList(); + aTokenList = new address[](underlyingsList.length); + for (uint256 i = 0; i < underlyingsList.length; i++) { + aTokenList[i] = (_lendingPool.getReserveData(underlyingsList[i])) + .aTokenAddress; + } + } + + function _dsaHasProtection() internal view returns (bool) { + return + _aaveServices.taskByUsersAction(address(this), _protectionAction) != + bytes32(0); + } +} + +contract GAaveProtectionPolygonConnector is GAaveProtectionResolver { + // solhint-disable-next-line const-name-snakecase + string public constant name = "GelatoAaveProtectionPolygonConnector-v1"; +}