Skip to content

Commit

Permalink
Merge pull request #17 from bgd-labs/fix/cantina
Browse files Browse the repository at this point in the history
fix: misc v3.1 fixes
  • Loading branch information
eboadom authored May 23, 2024
2 parents bdd0f9b + 1ff0262 commit eaf0b1e
Show file tree
Hide file tree
Showing 20 changed files with 143 additions and 33 deletions.
2 changes: 1 addition & 1 deletion docs/Aave-v3.1-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Given its implications and criticality, virtual accounting can be considered the
- [ConfigurationInputTypes](../src/core/contracts/protocol/libraries/types/ConfiguratorInputTypes.sol)
- Added flag `useVirtualBalance` for a new listing to use or not virtual balance.
- [ReserveConfiguration](../src/core/contracts/protocol/libraries/configuration/ReserveConfiguration.sol)
- Added logic to store and set/get the new `VIRTUAL_ACC_ACTIVE` flag.
- Added logic to set/get the new configuration flag for if a reserve has virtual account active.
- [Errors](../src/core/contracts/protocol/libraries/helpers/Errors.sol)
- In relation with this feature, added the `WITHDRAW_TO_ATOKEN` and `SUPPLY_TO_ATOKEN` errors.
- [Pool](../src/core/contracts/protocol/pool/Pool.sol)
Expand Down
6 changes: 3 additions & 3 deletions src/core/contracts/interfaces/IPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -381,10 +381,10 @@ interface IPool {
function swapBorrowRateMode(address asset, uint256 interestRateMode) external;

/**
* @notice Allows a borrower to swap his debt between stable and variable mode,
* @dev introduce in a flavor stable rate deprecation
* @notice Permissionless method which allows anyone to swap a users stable debt to variable debt
* @dev Introduced in favor of stable rate deprecation
* @param asset The address of the underlying asset borrowed
* @param user The address of the user to be swapped
* @param user The address of the user whose debt will be swapped from stable to variable
*/
function swapToVariable(address asset, address user) external;

Expand Down
15 changes: 15 additions & 0 deletions src/core/contracts/interfaces/IPoolConfigurator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ interface IPoolConfigurator {
*/
event LiquidationGracePeriodChanged(address indexed asset, uint40 gracePeriodUntil);

/**
* @dev Emitted when the liquidation grace period is disabled.
* @param asset The address of the underlying asset of the reserve
*/
event LiquidationGracePeriodDisabled(address indexed asset);

/**
* @dev Emitted when the unbacked mint cap of a reserve is updated.
* @param asset The address of the underlying asset of the reserve
Expand Down Expand Up @@ -289,6 +295,8 @@ interface IPoolConfigurator {

/**
* @notice Initializes multiple reserves.
* @dev param useVirtualBalance of the input struct should be true for all normal assets and should be false
* only in special cases (ex. GHO) where an asset is minted instead of supplied.
* @param input The array of initialization parameters
*/
function initReserves(ConfiguratorInputTypes.InitReserveInput[] calldata input) external;
Expand Down Expand Up @@ -401,6 +409,13 @@ interface IPoolConfigurator {
*/
function setReservePause(address asset, bool paused) external;

/**
* @notice Disables liquidation grace period for the asset. The liquidation grace period is set in the past
* so that liquidations are allowed for the asset.
* @param asset The address of the underlying asset of the reserve
*/
function disableLiquidationGracePeriod(address asset) external;

/**
* @notice Updates the reserve factor of a reserve.
* @param asset The address of the underlying asset of the reserve
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ library ReserveConfiguration {
uint256 internal constant EMODE_CATEGORY_MASK = 0xFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore
uint256 internal constant UNBACKED_MINT_CAP_MASK = 0xFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore
uint256 internal constant DEBT_CEILING_MASK = 0xF0000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore
uint256 internal constant VIRTUAL_ACC_ACTIVE = 0xEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore
uint256 internal constant VIRTUAL_ACC_ACTIVE_MASK = 0xEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore

/// @dev For the LTV, the start bit is 0 (up to 15), hence no bitshifting is needed
uint256 internal constant LIQUIDATION_THRESHOLD_START_BIT_POSITION = 16;
Expand Down Expand Up @@ -556,19 +556,21 @@ library ReserveConfiguration {
bool active
) internal pure {
self.data =
(self.data & VIRTUAL_ACC_ACTIVE) |
(self.data & VIRTUAL_ACC_ACTIVE_MASK) |
(uint256(active ? 1 : 0) << VIRTUAL_ACC_START_BIT_POSITION);
}

/**
* @notice Gets the virtual account active/not state of the reserve
* @dev The state should be true for all normal assets and should be false
* only in special cases (ex. GHO) where an asset is minted instead of supplied.
* @param self The reserve configuration
* @return The active state
*/
function getIsVirtualAccActive(
DataTypes.ReserveConfigurationMap memory self
) internal pure returns (bool) {
return (self.data & ~VIRTUAL_ACC_ACTIVE) != 0;
return (self.data & ~VIRTUAL_ACC_ACTIVE_MASK) != 0;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ library BorrowLogic {
* @param reserve The of the reserve of the asset being repaid
* @param userConfig The user configuration mapping that tracks the supplied/borrowed assets
* @param asset The asset of the position being swapped
* @param user The user whose debt position is being swapped
* @param interestRateMode The current interest rate mode of the position being swapped
*/
function executeSwapBorrowRateMode(
Expand Down
14 changes: 10 additions & 4 deletions src/core/contracts/protocol/libraries/logic/ConfiguratorLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import {InitializableImmutableAdminUpgradeabilityProxy} from '../aave-upgradeabi
import {IReserveInterestRateStrategy} from '../../../interfaces/IReserveInterestRateStrategy.sol';
import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
import {DataTypes} from '../types/DataTypes.sol';
import {Errors} from '../helpers/Errors.sol';
import {ConfiguratorInputTypes} from '../types/ConfiguratorInputTypes.sol';
import {IERC20Detailed} from '../../../dependencies/openzeppelin/contracts/IERC20Detailed.sol';

/**
* @title ConfiguratorLogic library
Expand Down Expand Up @@ -52,6 +54,10 @@ library ConfiguratorLogic {
IPool pool,
ConfiguratorInputTypes.InitReserveInput calldata input
) external {
// It is an assumption that the asset listed is non-malicious, and the external call doesn't create re-entrancies
uint8 underlyingAssetDecimals = IERC20Detailed(input.underlyingAsset).decimals();
require(underlyingAssetDecimals > 5, Errors.INVALID_DECIMALS);

address aTokenProxyAddress = _initTokenWithProxy(
input.aTokenImpl,
abi.encodeWithSelector(
Expand All @@ -60,7 +66,7 @@ library ConfiguratorLogic {
input.treasury,
input.underlyingAsset,
input.incentivesController,
input.underlyingAssetDecimals,
underlyingAssetDecimals,
input.aTokenName,
input.aTokenSymbol,
input.params
Expand All @@ -74,7 +80,7 @@ library ConfiguratorLogic {
pool,
input.underlyingAsset,
input.incentivesController,
input.underlyingAssetDecimals,
underlyingAssetDecimals,
input.stableDebtTokenName,
input.stableDebtTokenSymbol,
input.params
Expand All @@ -88,7 +94,7 @@ library ConfiguratorLogic {
pool,
input.underlyingAsset,
input.incentivesController,
input.underlyingAssetDecimals,
underlyingAssetDecimals,
input.variableDebtTokenName,
input.variableDebtTokenSymbol,
input.params
Expand All @@ -105,7 +111,7 @@ library ConfiguratorLogic {

DataTypes.ReserveConfigurationMap memory currentConfig = DataTypes.ReserveConfigurationMap(0);

currentConfig.setDecimals(input.underlyingAssetDecimals);
currentConfig.setDecimals(underlyingAssetDecimals);

currentConfig.setActive(true);
currentConfig.setPaused(false);
Expand Down
1 change: 0 additions & 1 deletion src/core/contracts/protocol/libraries/logic/EModeLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {GPv2SafeERC20} from '../../../dependencies/gnosis/contracts/GPv2SafeERC2
import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
import {IPriceOracleGetter} from '../../../interfaces/IPriceOracleGetter.sol';
import {UserConfiguration} from '../configuration/UserConfiguration.sol';
import {Errors} from '../helpers/Errors.sol';
import {WadRayMath} from '../math/WadRayMath.sol';
import {PercentageMath} from '../math/PercentageMath.sol';
import {DataTypes} from '../types/DataTypes.sol';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {IPool} from '../../../interfaces/IPool.sol';
import {IFlashLoanReceiver} from '../../../flashloan/interfaces/IFlashLoanReceiver.sol';
import {IFlashLoanSimpleReceiver} from '../../../flashloan/interfaces/IFlashLoanSimpleReceiver.sol';
import {IPoolAddressesProvider} from '../../../interfaces/IPoolAddressesProvider.sol';
import {UserConfiguration} from '../configuration/UserConfiguration.sol';
import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
import {Errors} from '../helpers/Errors.sol';
import {WadRayMath} from '../math/WadRayMath.sol';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
import {Address} from '../../../dependencies/openzeppelin/contracts/Address.sol';
import {GPv2SafeERC20} from '../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
import {IReserveInterestRateStrategy} from '../../../interfaces/IReserveInterestRateStrategy.sol';
import {IStableDebtToken} from '../../../interfaces/IStableDebtToken.sol';
import {IScaledBalanceToken} from '../../../interfaces/IScaledBalanceToken.sol';
import {IPriceOracleGetter} from '../../../interfaces/IPriceOracleGetter.sol';
import {IAToken} from '../../../interfaces/IAToken.sol';
import {IPriceOracleSentinel} from '../../../interfaces/IPriceOracleSentinel.sol';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ library ConfiguratorInputTypes {
address aTokenImpl;
address stableDebtTokenImpl;
address variableDebtTokenImpl;
uint8 underlyingAssetDecimals;
bool useVirtualBalance;
address interestRateStrategyAddress;
address underlyingAsset;
Expand Down
2 changes: 1 addition & 1 deletion src/core/contracts/protocol/libraries/types/DataTypes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ library DataTypes {
uint40 lastUpdateTimestamp;
//the id of the reserve. Represents the position in the list of the active reserves
uint16 id;
//timestamp in the future, until when liquidations are not allowed on the reserve
//timestamp until when liquidations are not allowed on the reserve, if set to past liquidations will be allowed
uint40 liquidationGracePeriodUntil;
//aToken address
address aTokenAddress;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ contract DefaultReserveInterestRateStrategyV2 is IDefaultInterestRateStrategyV2
) external view virtual override returns (uint256, uint256, uint256) {
InterestRateDataRay memory rateData = _rayifyRateData(_interestRateData[params.reserve]);

// @note This is a short circuit to allow mintable assets, which by definition cannot be supplied
// @note This is a short circuit to allow mintable assets (ex. GHO), which by definition cannot be supplied
// and thus do not use virtual underlying balances.
if (!params.usingVirtualBalance) {
return (0, 0, rateData.baseVariableBorrowRate);
Expand Down
11 changes: 9 additions & 2 deletions src/core/contracts/protocol/pool/PoolConfigurator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,8 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator
ConfiguratorInputTypes.InitReserveInput[] calldata input
) external override onlyAssetListingOrPoolAdmins {
IPool cachedPool = _pool;
for (uint256 i = 0; i < input.length; i++) {
require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS);

for (uint256 i = 0; i < input.length; i++) {
ConfiguratorLogic.executeInitReserve(cachedPool, input[i]);
emit ReserveInterestRateDataChanged(
input[i].underlyingAsset,
Expand Down Expand Up @@ -280,6 +279,14 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator
setReservePause(asset, paused, 0);
}

/// @inheritdoc IPoolConfigurator
function disableLiquidationGracePeriod(address asset) external override onlyEmergencyOrPoolAdmin {
// set the liquidation grace period in the past to disable liquidation grace period
_pool.setLiquidationGracePeriod(asset, 0);

emit LiquidationGracePeriodDisabled(asset);
}

/// @inheritdoc IPoolConfigurator
function setReserveFactor(
address asset,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import {IERC20Metadata} from 'solidity-utils/contracts/oz-common/interfaces/IERC20Metadata.sol';
import {IAaveV3ConfigEngine as IEngine, IPoolConfigurator, IPool, IDefaultInterestRateStrategyV2} from '../IAaveV3ConfigEngine.sol';
import {PriceFeedEngine} from './PriceFeedEngine.sol';
import {CapsEngine} from './CapsEngine.sol';
Expand Down Expand Up @@ -177,14 +176,10 @@ library ListingEngine {
memory initReserveInputs = new ConfiguratorInputTypes.InitReserveInput[](ids.length);

for (uint256 i = 0; i < ids.length; i++) {
uint8 decimals = IERC20Metadata(ids[i]).decimals();
require(decimals > 0, 'INVALID_ASSET_DECIMALS');

initReserveInputs[i] = ConfiguratorInputTypes.InitReserveInput({
aTokenImpl: basics[i].implementations.aToken,
stableDebtTokenImpl: basics[i].implementations.sToken,
variableDebtTokenImpl: basics[i].implementations.vToken,
underlyingAssetDecimals: decimals,
interestRateStrategyAddress: rateStrategy,
interestRateData: abi.encode(rates[i]),
underlyingAsset: ids[i],
Expand Down
52 changes: 52 additions & 0 deletions tests/core/Pool.Liquidations.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,58 @@ contract PoolLiquidationTests is TestnetProcedures {
contracts.poolProxy.liquidationCall(tokenList.usdx, tokenList.wbtc, bob, 100e6, false);
}

function test_liquidation_when_grace_period_disabled(uint40 liquidationGracePeriod) public {
vm.assume(
liquidationGracePeriod <= contracts.poolConfiguratorProxy.MAX_GRACE_PERIOD() &&
liquidationGracePeriod != 0
);
address[] memory assetsInGrace = new address[](1);
assetsInGrace[0] = tokenList.usdx;

_setLiquidationGracePeriod(assetsInGrace, liquidationGracePeriod);

vm.startPrank(alice);
contracts.poolProxy.supply(tokenList.wbtc, 1.25e8, alice, 0);
contracts.poolProxy.borrow(tokenList.usdx, 22_500e6, 2, 0, alice);
vm.stopPrank();

LiquidationInput memory params = _loadLiquidationInput(
alice,
tokenList.wbtc, // collateral
tokenList.usdx, // debt
5_000e6,
tokenList.wbtc,
25_00
);

vm.startPrank(bob);
// check that liquidations are not allowed after grace period activation
vm.expectRevert(bytes(Errors.LIQUIDATION_GRACE_SENTINEL_CHECK_FAILED));
contracts.poolProxy.liquidationCall(
params.collateralAsset,
params.debtAsset,
params.user,
params.liquidationAmountInput,
params.receiveAToken
);
vm.stopPrank();

vm.startPrank(poolAdmin);
contracts.poolConfiguratorProxy.disableLiquidationGracePeriod(assetsInGrace[0]);
vm.stopPrank();

vm.startPrank(bob);
// check that liquidations are allowed after grace period disabled
contracts.poolProxy.liquidationCall(
params.collateralAsset,
params.debtAsset,
params.user,
params.liquidationAmountInput,
params.receiveAToken
);
vm.stopPrank();
}

function test_liquidation_with_liquidation_grace_period_collateral_active(
uint40 liquidationGracePeriod
) public {
Expand Down
16 changes: 16 additions & 0 deletions tests/core/PoolConfigurator.ACLModifiers.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,22 @@ contract PoolConfiguratorACLModifiersTest is TestnetProcedures {
contracts.poolConfiguratorProxy.setReservePause(asset, paused);
}

function test_reverts_disableLiquidationGracePeriod_on_unauth(
address caller,
address asset
) public {
vm.assume(
!contracts.aclManager.isPoolAdmin(caller) &&
!contracts.aclManager.isEmergencyAdmin(caller) &&
caller != address(contracts.poolAddressesProvider)
);

vm.prank(caller);

vm.expectRevert(bytes(Errors.CALLER_NOT_POOL_OR_EMERGENCY_ADMIN));
contracts.poolConfiguratorProxy.disableLiquidationGracePeriod(asset);
}

function test_reverts_setPoolPause_unauth(
address caller,
bool paused,
Expand Down
19 changes: 13 additions & 6 deletions tests/core/PoolConfigurator.initReserves.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ contract PoolConfiguratorInitReservesTest is TestnetProcedures {
report.aToken,
report.stableDebtToken,
report.variableDebtToken,
newToken.decimals(),
isVirtualAccActive,
t.rateStrategy,
address(newToken),
Expand Down Expand Up @@ -167,7 +166,10 @@ contract PoolConfiguratorInitReservesTest is TestnetProcedures {

assertEq(AToken(aTokenProxy).name(), reserveInput.aTokenName);
assertEq(AToken(aTokenProxy).symbol(), reserveInput.aTokenSymbol);
assertEq(AToken(aTokenProxy).decimals(), reserveInput.underlyingAssetDecimals);
assertEq(
AToken(aTokenProxy).decimals(),
TestnetERC20(reserveInput.underlyingAsset).decimals()
);
assertEq(AToken(aTokenProxy).RESERVE_TREASURY_ADDRESS(), reserveInput.treasury);
assertEq(AToken(aTokenProxy).UNDERLYING_ASSET_ADDRESS(), reserveInput.underlyingAsset);
assertEq(
Expand All @@ -177,7 +179,10 @@ contract PoolConfiguratorInitReservesTest is TestnetProcedures {

assertEq(AToken(stableDebtProxy).name(), reserveInput.stableDebtTokenName);
assertEq(AToken(stableDebtProxy).symbol(), reserveInput.stableDebtTokenSymbol);
assertEq(AToken(stableDebtProxy).decimals(), reserveInput.underlyingAssetDecimals);
assertEq(
AToken(stableDebtProxy).decimals(),
TestnetERC20(reserveInput.underlyingAsset).decimals()
);
assertEq(AToken(stableDebtProxy).UNDERLYING_ASSET_ADDRESS(), reserveInput.underlyingAsset);
assertEq(
address(AToken(stableDebtProxy).getIncentivesController()),
Expand All @@ -186,7 +191,10 @@ contract PoolConfiguratorInitReservesTest is TestnetProcedures {

assertEq(AToken(variableDebtProxy).name(), reserveInput.variableDebtTokenName);
assertEq(AToken(variableDebtProxy).symbol(), reserveInput.variableDebtTokenSymbol);
assertEq(AToken(variableDebtProxy).decimals(), reserveInput.underlyingAssetDecimals);
assertEq(
AToken(variableDebtProxy).decimals(),
TestnetERC20(reserveInput.underlyingAsset).decimals()
);
assertEq(
AToken(variableDebtProxy).UNDERLYING_ASSET_ADDRESS(),
reserveInput.underlyingAsset
Expand All @@ -205,7 +213,7 @@ contract PoolConfiguratorInitReservesTest is TestnetProcedures {
assertEq(c.isActive, true);
assertEq(c.isFrozen, false);
assertEq(c.isPaused, false);
assertEq(c.decimals, reserveInput.underlyingAssetDecimals);
assertEq(c.decimals, TestnetERC20(reserveInput.underlyingAsset).decimals());

assertEq(c.ltv, 0);
assertEq(c.liquidationThreshold, 0);
Expand Down Expand Up @@ -274,7 +282,6 @@ contract PoolConfiguratorInitReservesTest is TestnetProcedures {
report.aToken,
report.stableDebtToken,
report.variableDebtToken,
newToken.decimals(),
true,
t.rateStrategy,
address(newToken),
Expand Down
Loading

0 comments on commit eaf0b1e

Please sign in to comment.