Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3.0.2 Upgrade #832

Merged
merged 9 commits into from
Jun 26, 2023
Merged
2 changes: 1 addition & 1 deletion .github/workflows/certora.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
with: { java-version: '11', java-package: jre }

- name: Install certora cli
run: pip install certora-cli
run: pip install certora-cli==3.6.8.post3

- name: Install solc
run: |
Expand Down
Binary file added audits/19-04-2023_SigmaPrime_AaveV3-0-2.pdf
Binary file not shown.
Binary file modified audits/27-01-2022_SigmaPrime_AaveV3.pdf
Binary file not shown.
Binary file added certora/Aave_V3.0.2_PR_820_Report_Mar2023.pdf
Binary file not shown.
2 changes: 1 addition & 1 deletion certora/scripts/verifyAToken.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ certoraRun certora/harness/SimpleERC20.sol \
--link ATokenHarness:_underlyingAsset=SimpleERC20 \
--optimistic_loop \
--solc solc8.10 \
--cloud master \
--cloud \
--msg "aToken spec - all rules"
2 changes: 1 addition & 1 deletion certora/scripts/verifyPool.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ certoraRun certora/harness/PoolHarness.sol \
--settings -mediumTimeout=700,-depth=40 \
--optimistic_loop \
--solc solc8.10 \
--cloud master \
--cloud \
--rules $1 \
--msg "Pool"
2 changes: 1 addition & 1 deletion certora/scripts/verifyReserveConfiguration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ certoraRun certora/harness/ReserveConfigurationHarness.sol \
--settings -useBitVectorTheory \
--optimistic_loop \
--solc solc8.10 \
--cloud master \
--cloud \
--msg "ReserveConfiguration"
2 changes: 1 addition & 1 deletion certora/scripts/verifyStableTokenCLI.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ certoraRun certora/harness/StableDebtTokenHarness.sol:StableDebtTokenHarness \
--settings -assumeUnwindCond,-b=4 \
--cache StableToken \
--solc solc8.10 \
--cloud master \
--cloud \
--msg "stableTokenCLI"
2 changes: 1 addition & 1 deletion certora/scripts/verifyUserConfigCLI.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ certoraRun certora/harness/UserConfigurationHarness.sol \
--settings -useBitVectorTheory \
--optimistic_loop \
--solc solc8.10 \
--cloud master \
--cloud \
--msg "UserConfiguration All spec"
2 changes: 1 addition & 1 deletion certora/scripts/verifyVariableTokenCLI.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ certoraRun certora/harness/VariableDebtTokenHarness.sol \
--verify VariableDebtTokenHarness:certora/specs/VariableDebtToken.spec \
--optimistic_loop \
--solc solc8.10 \
--cloud master \
--cloud \
--msg "variable debt token"
3 changes: 2 additions & 1 deletion contracts/interfaces/IL2Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ interface IL2Pool {
* @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value will be expanded to
* type(uint256).max
* @dev assetId is the index of the asset in the reservesList.
* @return The final amount withdrawn
*/
function withdraw(bytes32 args) external;
function withdraw(bytes32 args) external returns (uint256);

/**
* @notice Calldata efficient wrapper of the borrow function, borrowing on behalf of the caller
Expand Down
105 changes: 105 additions & 0 deletions contracts/misc/ZeroReserveInterestRateStrategy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
import {IDefaultInterestRateStrategy} from '../interfaces/IDefaultInterestRateStrategy.sol';
import {IReserveInterestRateStrategy} from '../interfaces/IReserveInterestRateStrategy.sol';
import {IPoolAddressesProvider} from '../interfaces/IPoolAddressesProvider.sol';

/**
* @title ZeroReserveInterestRateStrategy contract
* @author Aave
* @notice Interest Rate Strategy contract, with all parameters zeroed.
* @dev It returns zero liquidity and borrow rate.
*/
contract ZeroReserveInterestRateStrategy is IDefaultInterestRateStrategy {
/// @inheritdoc IDefaultInterestRateStrategy
uint256 public constant OPTIMAL_USAGE_RATIO = 0;

/// @inheritdoc IDefaultInterestRateStrategy
uint256 public constant OPTIMAL_STABLE_TO_TOTAL_DEBT_RATIO = 0;

/// @inheritdoc IDefaultInterestRateStrategy
uint256 public constant MAX_EXCESS_USAGE_RATIO = 0;

/// @inheritdoc IDefaultInterestRateStrategy
uint256 public constant MAX_EXCESS_STABLE_TO_TOTAL_DEBT_RATIO = 0;

IPoolAddressesProvider public immutable ADDRESSES_PROVIDER;

// Base variable borrow rate when usage rate = 0. Expressed in ray
uint256 internal constant _baseVariableBorrowRate = 0;

// Slope of the variable interest curve when usage ratio > 0 and <= OPTIMAL_USAGE_RATIO. Expressed in ray
uint256 internal constant _variableRateSlope1 = 0;

// Slope of the variable interest curve when usage ratio > OPTIMAL_USAGE_RATIO. Expressed in ray
uint256 internal constant _variableRateSlope2 = 0;

// Slope of the stable interest curve when usage ratio > 0 and <= OPTIMAL_USAGE_RATIO. Expressed in ray
uint256 internal constant _stableRateSlope1 = 0;

// Slope of the stable interest curve when usage ratio > OPTIMAL_USAGE_RATIO. Expressed in ray
uint256 internal constant _stableRateSlope2 = 0;

// Premium on top of `_variableRateSlope1` for base stable borrowing rate
uint256 internal constant _baseStableRateOffset = 0;

// Additional premium applied to stable rate when stable debt surpass `OPTIMAL_STABLE_TO_TOTAL_DEBT_RATIO`
uint256 internal constant _stableRateExcessOffset = 0;

/**
* @dev Constructor.
* @param provider The address of the PoolAddressesProvider contract
*/
constructor(IPoolAddressesProvider provider) {
ADDRESSES_PROVIDER = provider;
}

/// @inheritdoc IDefaultInterestRateStrategy
function getVariableRateSlope1() external pure returns (uint256) {
return _variableRateSlope1;
}

/// @inheritdoc IDefaultInterestRateStrategy
function getVariableRateSlope2() external pure returns (uint256) {
return _variableRateSlope2;
}

/// @inheritdoc IDefaultInterestRateStrategy
function getStableRateSlope1() external pure returns (uint256) {
return _stableRateSlope1;
}

/// @inheritdoc IDefaultInterestRateStrategy
function getStableRateSlope2() external pure returns (uint256) {
return _stableRateSlope2;
}

/// @inheritdoc IDefaultInterestRateStrategy
function getStableRateExcessOffset() external pure returns (uint256) {
return _stableRateExcessOffset;
}

/// @inheritdoc IDefaultInterestRateStrategy
function getBaseStableBorrowRate() public pure returns (uint256) {
return _variableRateSlope1 + _baseStableRateOffset;
}

/// @inheritdoc IDefaultInterestRateStrategy
function getBaseVariableBorrowRate() external pure override returns (uint256) {
return _baseVariableBorrowRate;
}

/// @inheritdoc IDefaultInterestRateStrategy
function getMaxVariableBorrowRate() external pure override returns (uint256) {
return _baseVariableBorrowRate + _variableRateSlope1 + _variableRateSlope2;
}

/// @inheritdoc IReserveInterestRateStrategy
function calculateInterestRates(
DataTypes.CalculateInterestRatesParams memory
) public pure override returns (uint256, uint256, uint256) {
return (0, 0, 0);
}
}
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: 4 additions & 1 deletion contracts/protocol/libraries/logic/FlashLoanLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ library FlashLoanLogic {

for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
vars.currentAmount = params.amounts[vars.i];
vars.totalPremiums[vars.i] = vars.currentAmount.percentMul(vars.flashloanPremiumTotal);
vars.totalPremiums[vars.i] = DataTypes.InterestRateMode(params.interestRateModes[vars.i]) ==
DataTypes.InterestRateMode.NONE
? vars.currentAmount.percentMul(vars.flashloanPremiumTotal)
: 0;
IAToken(reservesData[params.assets[vars.i]].aTokenAddress).transferUnderlyingTo(
params.receiverAddress,
vars.currentAmount
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
4 changes: 2 additions & 2 deletions contracts/protocol/pool/L2Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ contract L2Pool is Pool, IL2Pool {
}

/// @inheritdoc IL2Pool
function withdraw(bytes32 args) external override {
function withdraw(bytes32 args) external override returns (uint256) {
(address asset, uint256 amount) = CalldataLogic.decodeWithdrawParams(_reservesList, args);

withdraw(asset, amount, msg.sender);
return withdraw(asset, amount, msg.sender);
}

/// @inheritdoc IL2Pool
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