Skip to content

Commit

Permalink
feat: Initial OperationalValidator integration
Browse files Browse the repository at this point in the history
  • Loading branch information
LHerskind committed Sep 28, 2021
1 parent d6af2e5 commit 5088148
Show file tree
Hide file tree
Showing 16 changed files with 663 additions and 20 deletions.
4 changes: 2 additions & 2 deletions contracts/interfaces/IOperationalValidator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity 0.8.7;

interface IOperationalValidator {
function isBorrowAllowed() external returns (bool);
function isBorrowAllowed() external view returns (bool);

function isLiquidationAllowed() external returns (bool);
function isLiquidationAllowed(uint256 healthFactor) external view returns (bool);
}
13 changes: 13 additions & 0 deletions contracts/interfaces/IPoolAddressesProvider.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ interface IPoolAddressesProvider {
event RateOracleUpdated(address indexed newAddress);
event ACLManagerUpdated(address indexed newAddress);
event ACLAdminUpdated(address indexed newAddress);
event OperationalValidatorUpdated(address indexed newAddress);
event ProxyCreated(bytes32 id, address indexed newAddress);
event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy);

Expand Down Expand Up @@ -111,4 +112,16 @@ interface IPoolAddressesProvider {
* @param aclAdmin The address of the new ACL admin
*/
function setACLAdmin(address aclAdmin) external;

/**
* @notice Returns the address of the OperationalValidator
* @return The OperationalValidator address
*/
function getOperationalValidator() external view returns (address);

/**
* @notice Updates the address of the OperationalValidator
* @param operationalValidator The address of the new OperationalValidator
**/
function setOperationalValidator(address operationalValidator) external;
}
8 changes: 8 additions & 0 deletions contracts/interfaces/ISequencerOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.7;

interface ISequencerOracle {
function setAnswer(bool isDown, uint256 timestamp) external;

function latestAnswer() external view returns (bool, uint256);
}
18 changes: 18 additions & 0 deletions contracts/mocks/oracle/SequencersOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.7;

import {Ownable} from '../../dependencies/openzeppelin/contracts/Ownable.sol';

contract SequencerOracle is Ownable {
bool internal _isDown;
uint256 internal _timestampGotUp;

function setAnswer(bool isDown, uint256 timestamp) external onlyOwner {
_isDown = isDown;
_timestampGotUp = timestamp;
}

function latestAnswer() external view returns (bool, uint256) {
return (_isDown, _timestampGotUp);
}
}
23 changes: 20 additions & 3 deletions contracts/protocol/configuration/OperationalValidator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity 0.8.7;

import {IPoolAddressesProvider} from '../../interfaces/IPoolAddressesProvider.sol';
import {IOperationalValidator} from '../../interfaces/IOperationalValidator.sol';
import {ISequencerOracle} from '../../interfaces/ISequencerOracle.sol';

/**
* @title OperationalValidator
Expand All @@ -11,26 +12,42 @@ import {IOperationalValidator} from '../../interfaces/IOperationalValidator.sol'
*/
contract OperationalValidator is IOperationalValidator {
IPoolAddressesProvider public _addressesProvider;
ISequencerOracle public _sequencerOracle;
uint256 public _gracePeriod;

/**
* @notice Constructor
* @dev
* @param provider The address of the PoolAddressesProvider
*/
constructor(IPoolAddressesProvider provider, uint256 gracePeriod) {
constructor(
IPoolAddressesProvider provider,
ISequencerOracle sequencerOracle,
uint256 gracePeriod
) {
_addressesProvider = provider;
_sequencerOracle = sequencerOracle;
_gracePeriod = gracePeriod;
}

/// @inheritdoc IOperationalValidator
function isBorrowAllowed() public override returns (bool) {
function isBorrowAllowed() public view override returns (bool) {
// If the sequencer goes down, borrowing is not allowed
return _isUpAndGracePeriodPassed();
}

/// @inheritdoc IOperationalValidator
function isLiquidationAllowed() public override returns (bool) {
function isLiquidationAllowed(uint256 healthFactor) public view override returns (bool) {
if (healthFactor < 0.95 ether) {
return true;
}
return _isUpAndGracePeriodPassed();
// If the sequencer goes down AND HF > 0.9, liquidation is not allowed
// If timestampSequencerGotUp - block.timestamp > gracePeriod, liquidation allowed
}

function _isUpAndGracePeriodPassed() internal view returns (bool) {
(bool isDown, uint256 timestampGotUp) = _sequencerOracle.latestAnswer();
return !isDown && block.timestamp - timestampGotUp > _gracePeriod;
}
}
12 changes: 12 additions & 0 deletions contracts/protocol/configuration/PoolAddressesProvider.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ contract PoolAddressesProvider is Ownable, IPoolAddressesProvider {
bytes32 private constant RATE_ORACLE = 'RATE_ORACLE';
bytes32 private constant ACL_MANAGER = 'ACL_MANAGER';
bytes32 private constant ACL_ADMIN = 'ACL_ADMIN';
bytes32 private constant OPERATIONAL_VALIDATOR = 'OPERATIONAL_VALIDATOR';

constructor(string memory marketId) {
_setMarketId(marketId);
Expand Down Expand Up @@ -120,6 +121,17 @@ contract PoolAddressesProvider is Ownable, IPoolAddressesProvider {
emit ACLAdminUpdated(aclAdmin);
}

/// @inheritdoc IPoolAddressesProvider
function setOperationalValidator(address operationalValidator) external override onlyOwner {
_addresses[OPERATIONAL_VALIDATOR] = operationalValidator;
emit OperationalValidatorUpdated(operationalValidator);
}

/// @inheritdoc IPoolAddressesProvider
function getOperationalValidator() external view override returns (address) {
return getAddress(OPERATIONAL_VALIDATOR);
}

/**
* @notice Internal function to update the implementation of a specific proxied component of the protocol
* @dev If there is no proxy registered in the given `id`, it creates the proxy setting `newAdress`
Expand Down
1 change: 1 addition & 0 deletions contracts/protocol/libraries/helpers/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,5 @@ library Errors {
string public constant VL_INCONSISTENT_EMODE_CATEGORY = '99';
string public constant HLP_UINT128_OVERFLOW = '100';
string public constant PC_CALLER_NOT_ASSET_LISTING_OR_POOL_ADMIN = '101';
string public constant VL_SEQUENCER_IS_DOWN = '102';
}
14 changes: 6 additions & 8 deletions contracts/protocol/libraries/logic/BorrowLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ library BorrowLogic {
params.maxStableRateBorrowSizePercent,
params.reservesCount,
params.oracle,
params.userEModeCategory
params.userEModeCategory,
params.operationalValidator
)
);

Expand Down Expand Up @@ -239,9 +240,7 @@ library BorrowLogic {

for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
vars.aTokenAddresses[vars.i] = reserves[params.assets[vars.i]].aTokenAddress;
vars.totalPremiums[vars.i] = params.amounts[vars.i].percentMul(
vars.flashloanPremiumTotal
);
vars.totalPremiums[vars.i] = params.amounts[vars.i].percentMul(vars.flashloanPremiumTotal);
IAToken(vars.aTokenAddresses[vars.i]).transferUnderlyingTo(
params.receiverAddress,
params.amounts[vars.i]
Expand Down Expand Up @@ -269,9 +268,7 @@ library BorrowLogic {
);
vars.currentPremiumToLP = vars.totalPremiums[vars.i] - vars.currentPremiumToProtocol;

if (
DataTypes.InterestRateMode(params.modes[vars.i]) == DataTypes.InterestRateMode.NONE
) {
if (DataTypes.InterestRateMode(params.modes[vars.i]) == DataTypes.InterestRateMode.NONE) {
DataTypes.ReserveData storage reserve = reserves[vars.currentAsset];
DataTypes.ReserveCache memory reserveCache = reserve.cache();

Expand Down Expand Up @@ -316,7 +313,8 @@ library BorrowLogic {
params.maxStableRateBorrowSizePercent,
params.reservesCount,
params.oracle,
params.userEModeCategory
params.userEModeCategory,
params.operationalValidator
)
);
}
Expand Down
3 changes: 2 additions & 1 deletion contracts/protocol/libraries/logic/LiquidationLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ library LiquidationLogic {
params.user,
params.reservesCount,
params.priceOracle,
params.userEModeCategory
params.userEModeCategory,
params.operationalValidator
)
);

Expand Down
15 changes: 15 additions & 0 deletions contracts/protocol/libraries/logic/ValidationLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ 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 {IOperationalValidator} from '../../../interfaces/IOperationalValidator.sol';
import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../configuration/UserConfiguration.sol';
import {Errors} from '../helpers/Errors.sol';
Expand Down Expand Up @@ -197,6 +198,13 @@ library ValidationLogic {

require(vars.userCollateralInBaseCurrency > 0, Errors.VL_COLLATERAL_BALANCE_IS_0);

if (params.operationalValidator != address(0)) {
require(
IOperationalValidator(params.operationalValidator).isBorrowAllowed(),
Errors.VL_SEQUENCER_IS_DOWN
);
}

require(
vars.healthFactor > GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
Errors.VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
Expand Down Expand Up @@ -489,6 +497,13 @@ library ValidationLogic {
)
);

if (params.operationalValidator != address(0)) {
require(
IOperationalValidator(params.operationalValidator).isLiquidationAllowed(vars.healthFactor),
Errors.VL_SEQUENCER_IS_DOWN
);
}

require(
vars.healthFactor < GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
Errors.VL_HEALTH_FACTOR_NOT_BELOW_THRESHOLD
Expand Down
7 changes: 6 additions & 1 deletion contracts/protocol/libraries/types/DataTypes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ library DataTypes {
bool receiveAToken;
address priceOracle;
uint8 userEModeCategory;
address operationalValidator;
}

struct ExecuteSupplyParams {
Expand All @@ -120,6 +121,7 @@ library DataTypes {
uint256 reservesCount;
address oracle;
uint8 userEModeCategory;
address operationalValidator;
}

struct ExecuteRepayParams {
Expand All @@ -139,7 +141,7 @@ library DataTypes {
uint8 userEModeCategory;
}

struct ExecuteSetUserEModeParams {
struct ExecuteSetUserEModeParams {
uint256 reservesCount;
address oracle;
uint8 categoryId;
Expand Down Expand Up @@ -173,6 +175,7 @@ library DataTypes {
address oracle;
uint8 userEModeCategory;
bool isAuthorizedFlashBorrower;
address operationalValidator;
}

struct CalculateUserAccountDataParams {
Expand All @@ -194,6 +197,7 @@ library DataTypes {
uint256 reservesCount;
address oracle;
uint8 userEModeCategory;
address operationalValidator;
}

struct ValidateLiquidationCallParams {
Expand All @@ -203,5 +207,6 @@ library DataTypes {
uint256 reservesCount;
address oracle;
uint8 userEModeCategory;
address operationalValidator;
}
}
9 changes: 6 additions & 3 deletions contracts/protocol/pool/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
_maxStableRateBorrowSizePercent,
_reservesCount,
_addressesProvider.getPriceOracle(),
_usersEModeCategory[msg.sender]
_usersEModeCategory[msg.sender],
_addressesProvider.getOperationalValidator()
)
);
}
Expand Down Expand Up @@ -278,7 +279,8 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
user,
receiveAToken,
_addressesProvider.getPriceOracle(),
_usersEModeCategory[user]
_usersEModeCategory[user],
_addressesProvider.getOperationalValidator()
)
);
}
Expand Down Expand Up @@ -307,7 +309,8 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
_reservesCount,
_addressesProvider.getPriceOracle(),
_usersEModeCategory[onBehalfOf],
IACLManager(_addressesProvider.getACLManager()).isFlashBorrower(msg.sender)
IACLManager(_addressesProvider.getACLManager()).isFlashBorrower(msg.sender),
_addressesProvider.getOperationalValidator()
);

BorrowLogic.executeFlashLoan(
Expand Down
3 changes: 2 additions & 1 deletion helpers/contracts-deployments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
WETH9Mocked,
ACLManagerFactory,
EModeLogicFactory,
OperationalValidatorFactory,
} from '../types';
import {
withSave,
Expand All @@ -50,6 +51,7 @@ import { MintableDelegationERC20 } from '../types/MintableDelegationERC20';
import { HardhatRuntimeEnvironment } from 'hardhat/types';
import { PoolLibraryAddresses } from '../types/PoolFactory';
import AaveConfig from '../market-config';
import { BigNumber } from 'ethers';

const readArtifact = async (id: string) => {
return (DRE as HardhatRuntimeEnvironment).artifacts.readArtifact(id);
Expand Down Expand Up @@ -146,7 +148,6 @@ export const deployEModeLogic = async () => {
return withSave(eModeLogic, eContractid.EModeLogic);
};


export const deployAaveLibraries = async (): Promise<PoolLibraryAddresses> => {
const supplyLogic = await deploySupplyLogic();
const borrowLogic = await deployBorrowLogic();
Expand Down
2 changes: 2 additions & 0 deletions helpers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export enum eContractid {
MintableDelegationERC20 = 'MintableDelegationERC20',
PoolAddressesProviderRegistry = 'PoolAddressesProviderRegistry',
ACLManager = 'ACLManager',
OperationalValidator = 'OperationalValidator',
PoolParametersProvider = 'PoolParametersProvider',
PoolConfigurator = 'PoolConfigurator',
ValidationLogic = 'ValidationLogic',
Expand Down Expand Up @@ -167,6 +168,7 @@ export enum ProtocolErrors {
VL_INCONSISTENT_EMODE_CATEGORY = '99',
HLP_UINT128_OVERFLOW = '100',
PC_CALLER_NOT_ASSET_LISTING_OR_POOL_ADMIN = '101',
VL_SEQUENCER_IS_DOWN = '102',

// old

Expand Down
4 changes: 3 additions & 1 deletion test-suites/__setup.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import rawBRE from 'hardhat';
import { ethers, Signer } from 'ethers';
import { BigNumber, ethers, Signer } from 'ethers';
import {
insertContractAddressInDb,
getEthersSigners,
Expand All @@ -20,6 +20,7 @@ import {
deployAllMockTokens,
deployACLManager,
deployMockIncentivesController,
deployOperationalValidator,
} from '../helpers/contracts-deployments';
import { eContractid, tEthereumAddress } from '../helpers/types';
import {
Expand All @@ -37,6 +38,7 @@ import {
getACLManager,
} from '../helpers/contracts-getters';
import { initializeMakeSuite } from './helpers/make-suite';
import { ZERO_ADDRESS } from '../helpers/constants';

const MOCK_USD_PRICE_IN_WEI = AaveConfig.ProtocolGlobalParams.MockUsdPriceInWei;
const ALL_ASSETS_INITIAL_PRICES = AaveConfig.Mocks.AllAssetsInitialPrices;
Expand Down
Loading

0 comments on commit 5088148

Please sign in to comment.