Skip to content

Commit

Permalink
fix: Fix collateral behavior of zero-ltv assets (#820)
Browse files Browse the repository at this point in the history
* fix: patch zero ltv transfer

* fix: revert undesired changes

* fix: change implementation

* fix: add docs

* fix: rename error

* fix: improved isolation mode enter mechanic

* fix: improve tests

* fix: remove check from bridge as anotehr role is used already

* fix: use acl manager

* fix: flashloan receiver.executeOperation params

* fix: fix comment

* fix: move role to constant

* fix: commit broken test

* fix: add additional test

* fix: add flashloan test

* fix: add additional test

* fix: fix tests

* fix: prune fl fix

* Update package.json

* fix: resolve conflicts

* fix: add comments

* fix: also add automatic isolation logic to mintUnbacked

fix: update docs

* fix: update test

* fix: add some more ltv0 tests

* feat: fix tests & add another one

* fix: Fetch addressesProvider from AToken

---------

Co-authored-by: miguelmtz <36620902+miguelmtzinf@users.noreply.github.com>
Co-authored-by: miguelmtzinf <miguelmtz.mail@gmail.com>
  • Loading branch information
3 people authored Mar 23, 2023
1 parent ade6cf8 commit ea48670
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 44 deletions.
2 changes: 1 addition & 1 deletion contracts/protocol/libraries/helpers/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ library Errors {
string public constant PRICE_ORACLE_SENTINEL_CHECK_FAILED = '59'; // 'Price oracle sentinel validation failed'
string public constant ASSET_NOT_BORROWABLE_IN_ISOLATION = '60'; // 'Asset is not borrowable in isolation mode'
string public constant RESERVE_ALREADY_INITIALIZED = '61'; // 'Reserve has already been initialized'
string public constant USER_IN_ISOLATION_MODE = '62'; // 'User is in isolation mode'
string public constant USER_IN_ISOLATION_MODE_OR_LTV_ZERO = '62'; // 'User is in isolation mode or ltv is zero'
string public constant INVALID_LTV = '63'; // 'Invalid ltv parameter for the reserve'
string public constant INVALID_LIQ_THRESHOLD = '64'; // 'Invalid liquidity threshold parameter for the reserve'
string public constant INVALID_LIQ_BONUS = '65'; // 'Invalid liquidity bonus parameter for the reserve'
Expand Down
5 changes: 3 additions & 2 deletions contracts/protocol/libraries/logic/BridgeLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,12 @@ library BridgeLogic {

if (isFirstSupply) {
if (
ValidationLogic.validateUseAsCollateral(
ValidationLogic.validateAutomaticUseAsCollateral(
reservesData,
reservesList,
userConfig,
reserveCache.reserveConfiguration
reserveCache.reserveConfiguration,
reserveCache.aTokenAddress
)
) {
userConfig.setUsingAsCollateral(reserve.id, true);
Expand Down
5 changes: 3 additions & 2 deletions contracts/protocol/libraries/logic/LiquidationLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,12 @@ library LiquidationLogic {
if (liquidatorPreviousATokenBalance == 0) {
DataTypes.UserConfigurationMap storage liquidatorConfig = usersConfig[msg.sender];
if (
ValidationLogic.validateUseAsCollateral(
ValidationLogic.validateAutomaticUseAsCollateral(
reservesData,
reservesList,
liquidatorConfig,
collateralReserve.configuration
collateralReserve.configuration,
collateralReserve.aTokenAddress
)
) {
liquidatorConfig.setUsingAsCollateral(collateralReserve.id, true);
Expand Down
12 changes: 7 additions & 5 deletions contracts/protocol/libraries/logic/SupplyLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,12 @@ library SupplyLogic {

if (isFirstSupply) {
if (
ValidationLogic.validateUseAsCollateral(
ValidationLogic.validateAutomaticUseAsCollateral(
reservesData,
reservesList,
userConfig,
reserveCache.reserveConfiguration
reserveCache.reserveConfiguration,
reserveCache.aTokenAddress
)
) {
userConfig.setUsingAsCollateral(reserve.id, true);
Expand Down Expand Up @@ -212,11 +213,12 @@ library SupplyLogic {
if (params.balanceToBefore == 0) {
DataTypes.UserConfigurationMap storage toConfig = usersConfig[params.to];
if (
ValidationLogic.validateUseAsCollateral(
ValidationLogic.validateAutomaticUseAsCollateral(
reservesData,
reservesList,
toConfig,
reserve.configuration
reserve.configuration,
reserve.aTokenAddress
)
) {
toConfig.setUsingAsCollateral(reserveId, true);
Expand Down Expand Up @@ -270,7 +272,7 @@ library SupplyLogic {
userConfig,
reserveCache.reserveConfiguration
),
Errors.USER_IN_ISOLATION_MODE
Errors.USER_IN_ISOLATION_MODE_OR_LTV_ZERO
);

userConfig.setUsingAsCollateral(reserve.id, true);
Expand Down
52 changes: 47 additions & 5 deletions contracts/protocol/libraries/logic/ValidationLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {IScaledBalanceToken} from '../../../interfaces/IScaledBalanceToken.sol';
import {IPriceOracleGetter} from '../../../interfaces/IPriceOracleGetter.sol';
import {IAToken} from '../../../interfaces/IAToken.sol';
import {IPriceOracleSentinel} from '../../../interfaces/IPriceOracleSentinel.sol';
import {IPoolAddressesProvider} from '../../../interfaces/IPoolAddressesProvider.sol';
import {IAccessControl} from '../../../dependencies/openzeppelin/contracts/IAccessControl.sol';
import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../configuration/UserConfiguration.sol';
import {Errors} from '../helpers/Errors.sol';
Expand All @@ -19,6 +21,7 @@ import {DataTypes} from '../types/DataTypes.sol';
import {ReserveLogic} from './ReserveLogic.sol';
import {GenericLogic} from './GenericLogic.sol';
import {SafeCast} from '../../../dependencies/openzeppelin/contracts/SafeCast.sol';
import {IncentivizedERC20} from '../../tokenization/base/IncentivizedERC20.sol';

/**
* @title ReserveLogic library
Expand Down Expand Up @@ -49,6 +52,12 @@ library ValidationLogic {
*/
uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1e18;

/**
* @dev Role identifier for the role allowed to supply isolated reserves as collateral
*/
bytes32 public constant ISOLATED_COLLATERAL_SUPPLIER_ROLE =
keccak256('ISOLATED_COLLATERAL_SUPPLIER');

/**
* @notice Validates a supply action.
* @param reserveCache The cached data of the reserve
Expand Down Expand Up @@ -664,7 +673,7 @@ library ValidationLogic {
Errors.INCONSISTENT_EMODE_CATEGORY
);

//eMode can always be enabled if the user hasn't supplied anything
// eMode can always be enabled if the user hasn't supplied anything
if (userConfig.isEmpty()) {
return;
}
Expand All @@ -688,10 +697,8 @@ library ValidationLogic {
}

/**
* @notice Validates if an asset can be activated as collateral in the following actions: supply, transfer,
* set as collateral, mint unbacked, and liquidate
* @dev This is used to ensure that the constraints for isolated assets are respected by all the actions that
* generate transfers of aTokens
* @notice Validates the action of activating the asset as collateral.
* @dev Only possible if the asset has non-zero LTV and the user is not in isolation mode
* @param reservesData The state of all the reserves
* @param reservesList The addresses of all the active reserves
* @param userConfig the user configuration
Expand All @@ -704,11 +711,46 @@ library ValidationLogic {
DataTypes.UserConfigurationMap storage userConfig,
DataTypes.ReserveConfigurationMap memory reserveConfig
) internal view returns (bool) {
if (reserveConfig.getLtv() == 0) {
return false;
}
if (!userConfig.isUsingAsCollateralAny()) {
return true;
}
(bool isolationModeActive, , ) = userConfig.getIsolationModeState(reservesData, reservesList);

return (!isolationModeActive && reserveConfig.getDebtCeiling() == 0);
}

/**
* @notice Validates if an asset should be automatically activated as collateral in the following actions: supply,
* transfer, mint unbacked, and liquidate
* @dev This is used to ensure that isolated assets are not enabled as collateral automatically
* @param reservesData The state of all the reserves
* @param reservesList The addresses of all the active reserves
* @param userConfig the user configuration
* @param reserveConfig The reserve configuration
* @return True if the asset can be activated as collateral, false otherwise
*/
function validateAutomaticUseAsCollateral(
mapping(address => DataTypes.ReserveData) storage reservesData,
mapping(uint256 => address) storage reservesList,
DataTypes.UserConfigurationMap storage userConfig,
DataTypes.ReserveConfigurationMap memory reserveConfig,
address aTokenAddress
) internal view returns (bool) {
if (reserveConfig.getDebtCeiling() != 0) {
// ensures only the ISOLATED_COLLATERAL_SUPPLIER_ROLE can enable collateral as side-effect of an action
IPoolAddressesProvider addressesProvider = IncentivizedERC20(aTokenAddress)
.POOL()
.ADDRESSES_PROVIDER();
if (
!IAccessControl(addressesProvider.getACLManager()).hasRole(
ISOLATED_COLLATERAL_SUPPLIER_ROLE,
msg.sender
)
) return false;
}
return validateUseAsCollateral(reservesData, reservesList, userConfig, reserveConfig);
}
}
6 changes: 1 addition & 5 deletions contracts/protocol/libraries/types/DataTypes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,7 @@ library DataTypes {
string label;
}

enum InterestRateMode {
NONE,
STABLE,
VARIABLE
}
enum InterestRateMode {NONE, STABLE, VARIABLE}

struct ReserveCache {
uint256 currScaledVariableDebt;
Expand Down
2 changes: 1 addition & 1 deletion helpers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export enum ProtocolErrors {
PRICE_ORACLE_SENTINEL_CHECK_FAILED = '59', // 'Price oracle sentinel validation failed'
ASSET_NOT_BORROWABLE_IN_ISOLATION = '60', // 'Asset is not borrowable in isolation mode'
RESERVE_ALREADY_INITIALIZED = '61', // 'Reserve has already been initialized'
USER_IN_ISOLATION_MODE = '62', // 'User is in isolation mode'
USER_IN_ISOLATION_MODE_OR_LTV_ZERO = '62', // 'User is in isolation mode or ltv is zero'
INVALID_LTV = '63', // 'Invalid ltv parameter for the reserve'
INVALID_LIQ_THRESHOLD = '64', // 'Invalid liquidity threshold parameter for the reserve'
INVALID_LIQ_BONUS = '65', // 'Invalid liquidity bonus parameter for the reserve'
Expand Down
Loading

0 comments on commit ea48670

Please sign in to comment.