Skip to content

Commit

Permalink
Merge pull request #15 from bgd-labs/fix/ltv-0
Browse files Browse the repository at this point in the history
fix: ltv = 0 changes
  • Loading branch information
eboadom authored May 27, 2024
2 parents eaf0b1e + 256161a commit 17915df
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 78 deletions.
10 changes: 2 additions & 8 deletions src/core/contracts/interfaces/IPoolConfigurator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,6 @@ interface IPoolConfigurator {
*/
event PendingLtvChanged(address indexed asset, uint256 ltv);

/**
* @dev Emitted when the asset is unfrozen and pending ltv is removed.
* @param asset The address of the underlying asset of the reserve
*/
event PendingLtvRemoved(address indexed asset);

/**
* @dev Emitted when the collateralization risk parameters for the specified asset are updated.
* @param asset The address of the underlying asset of the reserve
Expand Down Expand Up @@ -564,10 +558,10 @@ interface IPoolConfigurator {
function setSiloedBorrowing(address asset, bool siloed) external;

/**
* @notice Gets pending ltv value and flag if it is set
* @notice Gets pending ltv value
* @param asset The new siloed borrowing state
*/
function getPendingLtv(address asset) external returns (uint256, bool);
function getPendingLtv(address asset) external returns (uint256);

/**
* @notice Gets the address of the external ConfiguratorLogic
Expand Down
1 change: 1 addition & 0 deletions src/core/contracts/protocol/libraries/helpers/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,5 @@ library Errors {
string public constant CALLER_NOT_RISK_OR_POOL_OR_EMERGENCY_ADMIN = '96'; // 'The caller of the function is not a risk, pool or emergency admin'
string public constant LIQUIDATION_GRACE_SENTINEL_CHECK_FAILED = '97'; // 'Liquidation grace sentinel validation failed'
string public constant INVALID_GRACE_PERIOD = '98'; // Grace period above a valid range
string public constant INVALID_FREEZE_STATE = '99'; // Reserve is already in the passed freeze state
}
48 changes: 29 additions & 19 deletions src/core/contracts/protocol/pool/PoolConfigurator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator
IPool internal _pool;

mapping(address => uint256) internal _pendingLtv;
mapping(address => bool) internal _isPendingLtvSet;

uint40 public constant MAX_GRACE_PERIOD = 4 hours;

Expand Down Expand Up @@ -165,13 +164,11 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator

if (currentConfig.getFrozen()) {
_pendingLtv[asset] = ltv;
_isPendingLtvSet[asset] = true;

emit PendingLtvChanged(asset, ltv);
} else {
currentConfig.setLtv(ltv);
}

currentConfig.setLtv(ltv);

currentConfig.setLiquidationThreshold(liquidationThreshold);
currentConfig.setLiquidationBonus(liquidationBonus);

Expand Down Expand Up @@ -221,22 +218,31 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator
bool freeze
) external override onlyRiskOrPoolOrEmergencyAdmins {
DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);

require(freeze != currentConfig.getFrozen(), Errors.INVALID_FREEZE_STATE);

currentConfig.setFrozen(freeze);

if (freeze) {
_pendingLtv[asset] = currentConfig.getLtv();
_isPendingLtvSet[asset] = true;
currentConfig.setLtv(0);
uint256 currentLtv;
uint256 pendingLtv;

emit PendingLtvChanged(asset, currentConfig.getLtv());
} else if (_isPendingLtvSet[asset]) {
uint256 ltv = _pendingLtv[asset];
currentConfig.setLtv(ltv);
if (freeze) {
currentLtv = currentConfig.getLtv();
} else {
pendingLtv = _pendingLtv[asset];
}

delete _pendingLtv[asset];
delete _isPendingLtvSet[asset];
if (currentLtv != pendingLtv) {
_pendingLtv[asset] = currentLtv;
currentConfig.setLtv(pendingLtv);

emit PendingLtvRemoved(asset);
emit PendingLtvChanged(asset, currentLtv);
emit CollateralConfigurationChanged(
asset,
pendingLtv,
currentConfig.getLiquidationThreshold(),
currentConfig.getLiquidationBonus()
);
}

_pool.setConfiguration(asset, currentConfig);
Expand Down Expand Up @@ -415,7 +421,11 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator
for (uint256 i = 0; i < reserves.length; i++) {
DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(reserves[i]);
if (categoryId == currentConfig.getEModeCategory()) {
require(ltv > currentConfig.getLtv(), Errors.INVALID_EMODE_CATEGORY_PARAMS);
uint256 currentLtv = currentConfig.getFrozen()
? _pendingLtv[reserves[i]]
: currentConfig.getLtv();
require(ltv > currentLtv, Errors.INVALID_EMODE_CATEGORY_PARAMS);

require(
liquidationThreshold > currentConfig.getLiquidationThreshold(),
Errors.INVALID_EMODE_CATEGORY_PARAMS
Expand Down Expand Up @@ -544,8 +554,8 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator
}

/// @inheritdoc IPoolConfigurator
function getPendingLtv(address asset) external view override returns (uint256, bool) {
return (_pendingLtv[asset], _isPendingLtvSet[asset]);
function getPendingLtv(address asset) external view override returns (uint256) {
return _pendingLtv[asset];
}

/// @inheritdoc IPoolConfigurator
Expand Down
33 changes: 33 additions & 0 deletions tests/core/PoolConfigurator.eMode.sol
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,39 @@ contract PoolConfiguratorEModeConfigTests is TestnetProcedures {
vm.stopPrank();
}

function test_reverts_configureEmodeCategory_input_ltv_lt_reserve_emode_pendingLtv() public {
EModeCategoryInput memory ct = _genCategoryOne();
vm.startPrank(poolAdmin);

contracts.poolConfiguratorProxy.setEModeCategory(
ct.id,
ct.ltv,
ct.lt,
ct.lb,
ct.oracle,
ct.label
);
contracts.poolConfiguratorProxy.setAssetEModeCategory(tokenList.usdx, ct.id);

(, uint256 ltv, , , , , , , , ) = contracts.protocolDataProvider.getReserveConfigurationData(
tokenList.usdx
);

// freeze asset
contracts.poolConfiguratorProxy.setReserveFreeze(tokenList.usdx, true);

vm.expectRevert(bytes(Errors.INVALID_EMODE_CATEGORY_PARAMS));
contracts.poolConfiguratorProxy.setEModeCategory(
ct.id,
uint16(ltv) - 1,
ct.lt,
ct.lb,
ct.oracle,
ct.label
);
vm.stopPrank();
}

function test_reverts_configureEmodeCategory_input_lt_lt_reserve_emode_lt() public {
EModeCategoryInput memory ct = _genCategoryOne();
vm.startPrank(poolAdmin);
Expand Down
115 changes: 65 additions & 50 deletions tests/core/PoolConfigurator.pendingLTV.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,44 @@ import {DataTypes} from 'aave-v3-core/contracts/protocol/libraries/types/DataTyp
import {TestnetProcedures} from '../utils/TestnetProcedures.sol';

contract PoolConfiguratorPendingLtvTests is TestnetProcedures {
event PendingLtvChanged(address indexed asset, uint256 ltv);

event CollateralConfigurationChanged(
address indexed asset,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus
);

function setUp() public {
initTestEnvironment();
}

function test_freezeReserve_ltvSetTo0() public {
// check current ltv
(, uint256 ltv, , , , , , , , bool isFrozen) = contracts
.protocolDataProvider
.getReserveConfigurationData(tokenList.usdx);
(
,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus,
,
,
,
,
,
bool isFrozen
) = contracts.protocolDataProvider.getReserveConfigurationData(tokenList.usdx);

assertTrue(ltv > 0);
assertEq(isFrozen, false);

// expect events to be emitted
vm.expectEmit(address(contracts.poolConfiguratorProxy));
emit PendingLtvChanged(tokenList.usdx, ltv);

vm.expectEmit(address(contracts.poolConfiguratorProxy));
emit CollateralConfigurationChanged(tokenList.usdx, 0, liquidationThreshold, liquidationBonus);

// freeze reserve
vm.prank(poolAdmin);
contracts.poolConfiguratorProxy.setReserveFreeze(tokenList.usdx, true);
Expand All @@ -34,19 +59,25 @@ contract PoolConfiguratorPendingLtvTests is TestnetProcedures {
assertEq(updatedIsFrozen, true);

// check pending ltv is set
(uint256 pendingLtv, bool isPendingLtvSet) = contracts.poolConfiguratorProxy.getPendingLtv(
tokenList.usdx
);
uint256 pendingLtv = contracts.poolConfiguratorProxy.getPendingLtv(tokenList.usdx);

assertEq(pendingLtv, ltv);
assertEq(isPendingLtvSet, true);
}

function test_unfreezeReserve_pendingSetToLtv() public {
// check ltv
(, uint256 originalLtv, , , , , , , , ) = contracts
.protocolDataProvider
.getReserveConfigurationData(tokenList.usdx);
(
,
uint256 originalLtv,
uint256 liquidationThreshold,
uint256 liquidationBonus,
,
,
,
,
,

) = contracts.protocolDataProvider.getReserveConfigurationData(tokenList.usdx);

// freeze reserve
vm.startPrank(poolAdmin);
Expand All @@ -61,7 +92,15 @@ contract PoolConfiguratorPendingLtvTests is TestnetProcedures {
assertEq(isFrozen, true);

// check pending ltv
(uint256 pendingLtv, ) = contracts.poolConfiguratorProxy.getPendingLtv(tokenList.usdx);
uint256 pendingLtv = contracts.poolConfiguratorProxy.getPendingLtv(tokenList.usdx);

vm.expectEmit(address(contracts.poolConfiguratorProxy));
emit CollateralConfigurationChanged(
tokenList.usdx,
originalLtv,
liquidationThreshold,
liquidationBonus
);

// unfreeze reserve
contracts.poolConfiguratorProxy.setReserveFreeze(tokenList.usdx, false);
Expand All @@ -76,17 +115,14 @@ contract PoolConfiguratorPendingLtvTests is TestnetProcedures {
assertEq(updatedIsFrozen, false);

// check pending ltv is set to zero
(uint256 updatedPendingLtv, bool updatedIsPendingLtvSet) = contracts
.poolConfiguratorProxy
.getPendingLtv(tokenList.usdx);
uint256 updatedPendingLtv = contracts.poolConfiguratorProxy.getPendingLtv(tokenList.usdx);

assertEq(updatedPendingLtv, 0);
assertEq(updatedIsPendingLtvSet, false);

vm.stopPrank();
}

function test_setLtvToFrozen_ltvSetToPending(uint256 originalLtv, uint256 ltvToSet) public {
function test_setLtv_ltvSetPendingLtvSet(uint256 originalLtv, uint256 ltvToSet) public {
uint256 liquidationThreshold = 86_00;
uint256 liquidationBonus = 10_500;

Expand All @@ -97,8 +133,6 @@ contract PoolConfiguratorPendingLtvTests is TestnetProcedures {
vm.assume(ltvToSet < liquidationThreshold);
vm.assume(ltvToSet != originalLtv);

console.logUint(ltvToSet);

// set original ltv
vm.startPrank(poolAdmin);
contracts.poolConfiguratorProxy.configureReserveAsCollateral(
Expand All @@ -112,45 +146,21 @@ contract PoolConfiguratorPendingLtvTests is TestnetProcedures {
contracts.poolConfiguratorProxy.setReserveFreeze(tokenList.usdx, true);

// check pending ltv
(uint256 pendingLtv, ) = contracts.poolConfiguratorProxy.getPendingLtv(tokenList.usdx);
uint256 pendingLtv = contracts.poolConfiguratorProxy.getPendingLtv(tokenList.usdx);
assertEq(pendingLtv, originalLtv);

// setLtv
contracts.poolConfiguratorProxy.configureReserveAsCollateral(
// expect events to be emitted
vm.expectEmit(address(contracts.poolConfiguratorProxy));
emit PendingLtvChanged(tokenList.usdx, ltvToSet);

vm.expectEmit(address(contracts.poolConfiguratorProxy));
emit CollateralConfigurationChanged(
tokenList.usdx,
ltvToSet,
liquidationThreshold,
liquidationBonus
);

// check ltv is still 0
(, uint256 ltv, , , , , , , , ) = contracts.protocolDataProvider.getReserveConfigurationData(
tokenList.usdx
);

assertEq(ltv, 0);

// check pending ltv
(uint256 updatedPendingLtv, bool updatedIsPendingLtvSet) = contracts
.poolConfiguratorProxy
.getPendingLtv(tokenList.usdx);

assertEq(updatedPendingLtv, ltvToSet);
assertEq(updatedIsPendingLtvSet, true);

vm.stopPrank();
}

function test_setLtv_ltvSet(uint256 ltvToSet) public {
uint256 liquidationThreshold = 86_00;
uint256 liquidationBonus = 10_500;

vm.assume(ltvToSet > 0);
vm.assume(ltvToSet < liquidationThreshold);

// freeze reserve
vm.startPrank(poolAdmin);

// setLtv
contracts.poolConfiguratorProxy.configureReserveAsCollateral(
tokenList.usdx,
Expand All @@ -159,13 +169,18 @@ contract PoolConfiguratorPendingLtvTests is TestnetProcedures {
liquidationBonus
);

// check ltv is updated
// check ltv is still 0
(, uint256 ltv, , , , , , , , ) = contracts.protocolDataProvider.getReserveConfigurationData(
tokenList.usdx
);

assertEq(ltv, ltvToSet);

// check pending ltv
uint256 updatedPendingLtv = contracts.poolConfiguratorProxy.getPendingLtv(tokenList.usdx);

assertEq(updatedPendingLtv, ltvToSet);

vm.stopPrank();
}
}
Loading

0 comments on commit 17915df

Please sign in to comment.