Skip to content

Commit ea48670

Browse files
fix: Fix collateral behavior of zero-ltv assets (#820)
* 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 <[email protected]> Co-authored-by: miguelmtzinf <[email protected]>
1 parent ade6cf8 commit ea48670

File tree

9 files changed

+295
-44
lines changed

9 files changed

+295
-44
lines changed

contracts/protocol/libraries/helpers/Errors.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ library Errors {
6767
string public constant PRICE_ORACLE_SENTINEL_CHECK_FAILED = '59'; // 'Price oracle sentinel validation failed'
6868
string public constant ASSET_NOT_BORROWABLE_IN_ISOLATION = '60'; // 'Asset is not borrowable in isolation mode'
6969
string public constant RESERVE_ALREADY_INITIALIZED = '61'; // 'Reserve has already been initialized'
70-
string public constant USER_IN_ISOLATION_MODE = '62'; // 'User is in isolation mode'
70+
string public constant USER_IN_ISOLATION_MODE_OR_LTV_ZERO = '62'; // 'User is in isolation mode or ltv is zero'
7171
string public constant INVALID_LTV = '63'; // 'Invalid ltv parameter for the reserve'
7272
string public constant INVALID_LIQ_THRESHOLD = '64'; // 'Invalid liquidity threshold parameter for the reserve'
7373
string public constant INVALID_LIQ_BONUS = '65'; // 'Invalid liquidity bonus parameter for the reserve'

contracts/protocol/libraries/logic/BridgeLogic.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,12 @@ library BridgeLogic {
8686

8787
if (isFirstSupply) {
8888
if (
89-
ValidationLogic.validateUseAsCollateral(
89+
ValidationLogic.validateAutomaticUseAsCollateral(
9090
reservesData,
9191
reservesList,
9292
userConfig,
93-
reserveCache.reserveConfiguration
93+
reserveCache.reserveConfiguration,
94+
reserveCache.aTokenAddress
9495
)
9596
) {
9697
userConfig.setUsingAsCollateral(reserve.id, true);

contracts/protocol/libraries/logic/LiquidationLogic.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,11 +300,12 @@ library LiquidationLogic {
300300
if (liquidatorPreviousATokenBalance == 0) {
301301
DataTypes.UserConfigurationMap storage liquidatorConfig = usersConfig[msg.sender];
302302
if (
303-
ValidationLogic.validateUseAsCollateral(
303+
ValidationLogic.validateAutomaticUseAsCollateral(
304304
reservesData,
305305
reservesList,
306306
liquidatorConfig,
307-
collateralReserve.configuration
307+
collateralReserve.configuration,
308+
collateralReserve.aTokenAddress
308309
)
309310
) {
310311
liquidatorConfig.setUsingAsCollateral(collateralReserve.id, true);

contracts/protocol/libraries/logic/SupplyLogic.sol

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,12 @@ library SupplyLogic {
7575

7676
if (isFirstSupply) {
7777
if (
78-
ValidationLogic.validateUseAsCollateral(
78+
ValidationLogic.validateAutomaticUseAsCollateral(
7979
reservesData,
8080
reservesList,
8181
userConfig,
82-
reserveCache.reserveConfiguration
82+
reserveCache.reserveConfiguration,
83+
reserveCache.aTokenAddress
8384
)
8485
) {
8586
userConfig.setUsingAsCollateral(reserve.id, true);
@@ -212,11 +213,12 @@ library SupplyLogic {
212213
if (params.balanceToBefore == 0) {
213214
DataTypes.UserConfigurationMap storage toConfig = usersConfig[params.to];
214215
if (
215-
ValidationLogic.validateUseAsCollateral(
216+
ValidationLogic.validateAutomaticUseAsCollateral(
216217
reservesData,
217218
reservesList,
218219
toConfig,
219-
reserve.configuration
220+
reserve.configuration,
221+
reserve.aTokenAddress
220222
)
221223
) {
222224
toConfig.setUsingAsCollateral(reserveId, true);
@@ -270,7 +272,7 @@ library SupplyLogic {
270272
userConfig,
271273
reserveCache.reserveConfiguration
272274
),
273-
Errors.USER_IN_ISOLATION_MODE
275+
Errors.USER_IN_ISOLATION_MODE_OR_LTV_ZERO
274276
);
275277

276278
userConfig.setUsingAsCollateral(reserve.id, true);

contracts/protocol/libraries/logic/ValidationLogic.sol

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {IScaledBalanceToken} from '../../../interfaces/IScaledBalanceToken.sol';
1010
import {IPriceOracleGetter} from '../../../interfaces/IPriceOracleGetter.sol';
1111
import {IAToken} from '../../../interfaces/IAToken.sol';
1212
import {IPriceOracleSentinel} from '../../../interfaces/IPriceOracleSentinel.sol';
13+
import {IPoolAddressesProvider} from '../../../interfaces/IPoolAddressesProvider.sol';
14+
import {IAccessControl} from '../../../dependencies/openzeppelin/contracts/IAccessControl.sol';
1315
import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
1416
import {UserConfiguration} from '../configuration/UserConfiguration.sol';
1517
import {Errors} from '../helpers/Errors.sol';
@@ -19,6 +21,7 @@ import {DataTypes} from '../types/DataTypes.sol';
1921
import {ReserveLogic} from './ReserveLogic.sol';
2022
import {GenericLogic} from './GenericLogic.sol';
2123
import {SafeCast} from '../../../dependencies/openzeppelin/contracts/SafeCast.sol';
24+
import {IncentivizedERC20} from '../../tokenization/base/IncentivizedERC20.sol';
2225

2326
/**
2427
* @title ReserveLogic library
@@ -49,6 +52,12 @@ library ValidationLogic {
4952
*/
5053
uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1e18;
5154

55+
/**
56+
* @dev Role identifier for the role allowed to supply isolated reserves as collateral
57+
*/
58+
bytes32 public constant ISOLATED_COLLATERAL_SUPPLIER_ROLE =
59+
keccak256('ISOLATED_COLLATERAL_SUPPLIER');
60+
5261
/**
5362
* @notice Validates a supply action.
5463
* @param reserveCache The cached data of the reserve
@@ -664,7 +673,7 @@ library ValidationLogic {
664673
Errors.INCONSISTENT_EMODE_CATEGORY
665674
);
666675

667-
//eMode can always be enabled if the user hasn't supplied anything
676+
// eMode can always be enabled if the user hasn't supplied anything
668677
if (userConfig.isEmpty()) {
669678
return;
670679
}
@@ -688,10 +697,8 @@ library ValidationLogic {
688697
}
689698

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

712722
return (!isolationModeActive && reserveConfig.getDebtCeiling() == 0);
713723
}
724+
725+
/**
726+
* @notice Validates if an asset should be automatically activated as collateral in the following actions: supply,
727+
* transfer, mint unbacked, and liquidate
728+
* @dev This is used to ensure that isolated assets are not enabled as collateral automatically
729+
* @param reservesData The state of all the reserves
730+
* @param reservesList The addresses of all the active reserves
731+
* @param userConfig the user configuration
732+
* @param reserveConfig The reserve configuration
733+
* @return True if the asset can be activated as collateral, false otherwise
734+
*/
735+
function validateAutomaticUseAsCollateral(
736+
mapping(address => DataTypes.ReserveData) storage reservesData,
737+
mapping(uint256 => address) storage reservesList,
738+
DataTypes.UserConfigurationMap storage userConfig,
739+
DataTypes.ReserveConfigurationMap memory reserveConfig,
740+
address aTokenAddress
741+
) internal view returns (bool) {
742+
if (reserveConfig.getDebtCeiling() != 0) {
743+
// ensures only the ISOLATED_COLLATERAL_SUPPLIER_ROLE can enable collateral as side-effect of an action
744+
IPoolAddressesProvider addressesProvider = IncentivizedERC20(aTokenAddress)
745+
.POOL()
746+
.ADDRESSES_PROVIDER();
747+
if (
748+
!IAccessControl(addressesProvider.getACLManager()).hasRole(
749+
ISOLATED_COLLATERAL_SUPPLIER_ROLE,
750+
msg.sender
751+
)
752+
) return false;
753+
}
754+
return validateUseAsCollateral(reservesData, reservesList, userConfig, reserveConfig);
755+
}
714756
}

contracts/protocol/libraries/types/DataTypes.sol

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,7 @@ library DataTypes {
7878
string label;
7979
}
8080

81-
enum InterestRateMode {
82-
NONE,
83-
STABLE,
84-
VARIABLE
85-
}
81+
enum InterestRateMode {NONE, STABLE, VARIABLE}
8682

8783
struct ReserveCache {
8884
uint256 currScaledVariableDebt;

helpers/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export enum ProtocolErrors {
131131
PRICE_ORACLE_SENTINEL_CHECK_FAILED = '59', // 'Price oracle sentinel validation failed'
132132
ASSET_NOT_BORROWABLE_IN_ISOLATION = '60', // 'Asset is not borrowable in isolation mode'
133133
RESERVE_ALREADY_INITIALIZED = '61', // 'Reserve has already been initialized'
134-
USER_IN_ISOLATION_MODE = '62', // 'User is in isolation mode'
134+
USER_IN_ISOLATION_MODE_OR_LTV_ZERO = '62', // 'User is in isolation mode or ltv is zero'
135135
INVALID_LTV = '63', // 'Invalid ltv parameter for the reserve'
136136
INVALID_LIQ_THRESHOLD = '64', // 'Invalid liquidity threshold parameter for the reserve'
137137
INVALID_LIQ_BONUS = '65', // 'Invalid liquidity bonus parameter for the reserve'

0 commit comments

Comments
 (0)