From b190556963dbc62392921c24e223a8fa3416ee1f Mon Sep 17 00:00:00 2001 From: x-moola Date: Fri, 11 Mar 2022 12:08:17 -0800 Subject: [PATCH 01/11] Add configurator files for MOBI and UBE --- .../MOBI/MOBIConfiguratorAlfajores.sol | 93 +++++++++++++++++++ .../lendingpool/MOBI/MOBIConfiguratorCelo.sol | 93 +++++++++++++++++++ .../UBE/UBEConfiguratorAlfajores.sol | 93 +++++++++++++++++++ .../lendingpool/UBE/UBEConfiguratorCelo.sol | 0 4 files changed, 279 insertions(+) create mode 100644 contracts/protocol/lendingpool/MOBI/MOBIConfiguratorAlfajores.sol create mode 100644 contracts/protocol/lendingpool/MOBI/MOBIConfiguratorCelo.sol create mode 100644 contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol create mode 100644 contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol diff --git a/contracts/protocol/lendingpool/MOBI/MOBIConfiguratorAlfajores.sol b/contracts/protocol/lendingpool/MOBI/MOBIConfiguratorAlfajores.sol new file mode 100644 index 00000000..aed820c8 --- /dev/null +++ b/contracts/protocol/lendingpool/MOBI/MOBIConfiguratorAlfajores.sol @@ -0,0 +1,93 @@ +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {ERC20} from '../../../dependencies/openzeppelin/contracts/ERC20.sol'; +import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol'; +import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; +import '../../../interfaces/ILendingPoolConfigurator.sol'; + +contract MOBIConfiguratorAlfajores is Ownable { + address constant lendingPoolConfiguratorAddress = 0x39fe2A4a4174bB5cAC5568ce0715a0b320bcB231; + + LendingPoolConfigurator public lendingPoolConfigurator = + LendingPoolConfigurator(lendingPoolConfiguratorAddress); + address constant assetAddress = 0x17700282592D6917F6A73D0bF8AcCf4D578c131e; + + bytes constant params = '0x10'; + bool constant stableBorrowRateEnabled = true; + uint8 constant underlyingAssetDecimals = 18; + address constant aTokenImpl = 0xe8B286649713447D8d5fBeBC28c731830d19B6C9; + address constant stableDebtTokenImpl = 0xB6a5059A228a16Fa2827E28E52ceC96BBC63D639; + address constant variableDebtTokenImpl = 0xB65b6a6a6F78E4daABF259c756567ae346699687; + address constant interestRateStrategyAddress = 0x3C06Fb2f5Ab65b0e35F91073d88afE2b017D04b8; + address constant treasury = 0x643C574128c7C56A1835e021Ad0EcC2592E72624; + address constant incentivesController = 0x0000000000000000000000000000000000000000; + string constant underlyingAssetName = 'Mobius DAO'; + string constant aTokenName = 'Mobius DAO interest bearing MOO'; + string constant aTokenSymbol = 'mMOBI'; + string constant variableDebtTokenName = 'Mobius DAO variable debt bearing mMOBI'; + string constant variableDebtTokenSymbol = 'variableDebtmMOBI'; + string constant stableDebtTokenName = 'Mobius DAO stable debt bearing mMOBI'; + string constant stableDebtTokenSymbol = 'stableDebtmMOBI'; + uint256 constant baseLTV = 5000; + uint256 constant liquidationThreshold = 6500; + uint256 constant liquidationBonus = 11000; + uint256 constant reserveFactor = 1000; + + function execute() external onlyOwner { + createReserve(); + enableCollateral(); + enableBorrowing(); + setReserveFactor(); + + selfdestruct(payable(treasury)); + } + + function destruct() external onlyOwner { + selfdestruct(payable(treasury)); + } + + function createReserve() internal { + ILendingPoolConfigurator.InitReserveInput[] + memory inputs = new ILendingPoolConfigurator.InitReserveInput[](1); + ILendingPoolConfigurator.InitReserveInput memory input = ILendingPoolConfigurator + .InitReserveInput({ + aTokenImpl: aTokenImpl, + stableDebtTokenImpl: stableDebtTokenImpl, + variableDebtTokenImpl: variableDebtTokenImpl, + underlyingAssetDecimals: underlyingAssetDecimals, + interestRateStrategyAddress: interestRateStrategyAddress, + underlyingAsset: assetAddress, + treasury: treasury, + incentivesController: incentivesController, + underlyingAssetName: underlyingAssetName, + aTokenName: aTokenName, + aTokenSymbol: aTokenSymbol, + variableDebtTokenName: variableDebtTokenName, + variableDebtTokenSymbol: variableDebtTokenSymbol, + stableDebtTokenName: stableDebtTokenName, + stableDebtTokenSymbol: stableDebtTokenSymbol, + params: params + }); + inputs[0] = input; + + lendingPoolConfigurator.batchInitReserve(inputs); + } + + function enableCollateral() internal { + lendingPoolConfigurator.configureReserveAsCollateral( + assetAddress, + baseLTV, + liquidationThreshold, + liquidationBonus + ); + } + + function enableBorrowing() internal { + lendingPoolConfigurator.enableBorrowingOnReserve(assetAddress, stableBorrowRateEnabled); + } + + function setReserveFactor() internal { + lendingPoolConfigurator.setReserveFactor(assetAddress, reserveFactor); + } +} diff --git a/contracts/protocol/lendingpool/MOBI/MOBIConfiguratorCelo.sol b/contracts/protocol/lendingpool/MOBI/MOBIConfiguratorCelo.sol new file mode 100644 index 00000000..44f39e7f --- /dev/null +++ b/contracts/protocol/lendingpool/MOBI/MOBIConfiguratorCelo.sol @@ -0,0 +1,93 @@ +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {ERC20} from '../../../dependencies/openzeppelin/contracts/ERC20.sol'; +import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol'; +import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; +import '../../../interfaces/ILendingPoolConfigurator.sol'; + +contract MOOConfiguratorCelo is Ownable { + address constant lendingPoolConfiguratorAddress = 0x928F63a83217e427A84504950206834CBDa4Aa65; + + LendingPoolConfigurator public lendingPoolConfigurator = + LendingPoolConfigurator(lendingPoolConfiguratorAddress); + address constant assetAddress = 0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC; + + bytes constant params = '0x10'; + bool constant stableBorrowRateEnabled = true; + uint8 constant underlyingAssetDecimals = 18; + address constant aTokenImpl = 0x55bFCED2451b2154e06604D4269c9349F31141e6; + address constant stableDebtTokenImpl = 0xaCdb7B3e2b0a038F1f4eF04736728E0065b689DA; + address constant variableDebtTokenImpl = 0x0301Cf8F1FCD9255BD32FB7e0fE5B3494f445C2C; + address constant interestRateStrategyAddress = 0x801443470c119F2eac65F13886D9e293CdecE2DF; + address constant treasury = 0x313bc86D3D6e86ba164B2B451cB0D9CfA7943e5c; + address constant incentivesController = 0x0000000000000000000000000000000000000000; + string constant underlyingAssetName = 'Ubeswap'; + string constant aTokenName = 'Ubeswap interest bearing MOO'; + string constant aTokenSymbol = 'mUBE'; + string constant variableDebtTokenName = 'Ubeswap variable debt bearing mUBE'; + string constant variableDebtTokenSymbol = 'variableDebtmUBE'; + string constant stableDebtTokenName = 'Ubeswap stable debt bearing mUBE'; + string constant stableDebtTokenSymbol = 'stableDebtmUBE'; + uint256 constant baseLTV = 5000; + uint256 constant liquidationThreshold = 6500; + uint256 constant liquidationBonus = 11000; + uint256 constant reserveFactor = 1000; + + function execute() external onlyOwner { + createReserve(); + enableCollateral(); + enableBorrowing(); + setReserveFactor(); + + selfdestruct(payable(treasury)); + } + + function destruct() external onlyOwner { + selfdestruct(payable(treasury)); + } + + function createReserve() internal { + ILendingPoolConfigurator.InitReserveInput[] + memory inputs = new ILendingPoolConfigurator.InitReserveInput[](1); + ILendingPoolConfigurator.InitReserveInput memory input = ILendingPoolConfigurator + .InitReserveInput({ + aTokenImpl: aTokenImpl, + stableDebtTokenImpl: stableDebtTokenImpl, + variableDebtTokenImpl: variableDebtTokenImpl, + underlyingAssetDecimals: underlyingAssetDecimals, + interestRateStrategyAddress: interestRateStrategyAddress, + underlyingAsset: assetAddress, + treasury: treasury, + incentivesController: incentivesController, + underlyingAssetName: underlyingAssetName, + aTokenName: aTokenName, + aTokenSymbol: aTokenSymbol, + variableDebtTokenName: variableDebtTokenName, + variableDebtTokenSymbol: variableDebtTokenSymbol, + stableDebtTokenName: stableDebtTokenName, + stableDebtTokenSymbol: stableDebtTokenSymbol, + params: params + }); + inputs[0] = input; + + lendingPoolConfigurator.batchInitReserve(inputs); + } + + function enableCollateral() internal { + lendingPoolConfigurator.configureReserveAsCollateral( + assetAddress, + baseLTV, + liquidationThreshold, + liquidationBonus + ); + } + + function enableBorrowing() internal { + lendingPoolConfigurator.enableBorrowingOnReserve(assetAddress, stableBorrowRateEnabled); + } + + function setReserveFactor() internal { + lendingPoolConfigurator.setReserveFactor(assetAddress, reserveFactor); + } +} diff --git a/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol b/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol new file mode 100644 index 00000000..c4ac98b2 --- /dev/null +++ b/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol @@ -0,0 +1,93 @@ +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {ERC20} from '../../../dependencies/openzeppelin/contracts/ERC20.sol'; +import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol'; +import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; +import '../../../interfaces/ILendingPoolConfigurator.sol'; + +contract UBEConfiguratorAlfajores is Ownable { + address constant lendingPoolConfiguratorAddress = 0x39fe2A4a4174bB5cAC5568ce0715a0b320bcB231; + + LendingPoolConfigurator public lendingPoolConfigurator = + LendingPoolConfigurator(lendingPoolConfiguratorAddress); + address constant assetAddress = 0x692A3Fe6cbe2588D64d7081bAF2F479424cCb2C3; // FIXME-- check the address + + bytes constant params = '0x10'; + bool constant stableBorrowRateEnabled = true; + uint8 constant underlyingAssetDecimals = 18; + address constant aTokenImpl = 0xe8B286649713447D8d5fBeBC28c731830d19B6C9; + address constant stableDebtTokenImpl = 0xB6a5059A228a16Fa2827E28E52ceC96BBC63D639; + address constant variableDebtTokenImpl = 0xB65b6a6a6F78E4daABF259c756567ae346699687; + address constant interestRateStrategyAddress = 0x3C06Fb2f5Ab65b0e35F91073d88afE2b017D04b8; + address constant treasury = 0x643C574128c7C56A1835e021Ad0EcC2592E72624; + address constant incentivesController = 0x0000000000000000000000000000000000000000; + string constant underlyingAssetName = 'Ubeswap'; + string constant aTokenName = 'Ubeswap interest bearing MOO'; + string constant aTokenSymbol = 'mUBE'; + string constant variableDebtTokenName = 'Ubeswap variable debt bearing mUBE'; + string constant variableDebtTokenSymbol = 'variableDebtmUBE'; + string constant stableDebtTokenName = 'Ubeswap stable debt bearing mUBE'; + string constant stableDebtTokenSymbol = 'stableDebtmUBE'; + uint256 constant baseLTV = 5000; + uint256 constant liquidationThreshold = 6500; + uint256 constant liquidationBonus = 11000; + uint256 constant reserveFactor = 1000; + + function execute() external onlyOwner { + createReserve(); + enableCollateral(); + enableBorrowing(); + setReserveFactor(); + + selfdestruct(payable(treasury)); + } + + function destruct() external onlyOwner { + selfdestruct(payable(treasury)); + } + + function createReserve() internal { + ILendingPoolConfigurator.InitReserveInput[] + memory inputs = new ILendingPoolConfigurator.InitReserveInput[](1); + ILendingPoolConfigurator.InitReserveInput memory input = ILendingPoolConfigurator + .InitReserveInput({ + aTokenImpl: aTokenImpl, + stableDebtTokenImpl: stableDebtTokenImpl, + variableDebtTokenImpl: variableDebtTokenImpl, + underlyingAssetDecimals: underlyingAssetDecimals, + interestRateStrategyAddress: interestRateStrategyAddress, + underlyingAsset: assetAddress, + treasury: treasury, + incentivesController: incentivesController, + underlyingAssetName: underlyingAssetName, + aTokenName: aTokenName, + aTokenSymbol: aTokenSymbol, + variableDebtTokenName: variableDebtTokenName, + variableDebtTokenSymbol: variableDebtTokenSymbol, + stableDebtTokenName: stableDebtTokenName, + stableDebtTokenSymbol: stableDebtTokenSymbol, + params: params + }); + inputs[0] = input; + + lendingPoolConfigurator.batchInitReserve(inputs); + } + + function enableCollateral() internal { + lendingPoolConfigurator.configureReserveAsCollateral( + assetAddress, + baseLTV, + liquidationThreshold, + liquidationBonus + ); + } + + function enableBorrowing() internal { + lendingPoolConfigurator.enableBorrowingOnReserve(assetAddress, stableBorrowRateEnabled); + } + + function setReserveFactor() internal { + lendingPoolConfigurator.setReserveFactor(assetAddress, reserveFactor); + } +} diff --git a/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol b/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol new file mode 100644 index 00000000..e69de29b From dc18a5c761b6c37b2e4fd6af2cf4decb5fb38f2b Mon Sep 17 00:00:00 2001 From: x-moola Date: Wed, 16 Mar 2022 07:50:05 -0700 Subject: [PATCH 02/11] Update contracts --- cli.js | 8 ++ .../UBE/UBEConfiguratorAlfajores.sol | 12 ++- .../lendingpool/UBE/UBEConfiguratorCelo.sol | 95 +++++++++++++++++++ .../WETHConfiguratorAlfajores.sol} | 24 ++--- .../WETHConfiguratorCelo.sol} | 23 ++--- 5 files changed, 135 insertions(+), 27 deletions(-) rename contracts/protocol/lendingpool/{MOBI/MOBIConfiguratorAlfajores.sol => WETH/WETHConfiguratorAlfajores.sol} (79%) rename contracts/protocol/lendingpool/{MOBI/MOBIConfiguratorCelo.sol => WETH/WETHConfiguratorCelo.sol} (80%) diff --git a/cli.js b/cli.js index edd34261..ba287c54 100644 --- a/cli.js +++ b/cli.js @@ -218,6 +218,8 @@ async function execute(network, action, ...params) { let cEUR; let cREAL; let MOO; + let UBE; + let WETH; let migrator; let privateKeyRequired = true; let liquiditySwapAdapter; @@ -235,6 +237,8 @@ async function execute(network, action, ...params) { cUSD = new kit.web3.eth.Contract(MToken, '0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1'); cREAL = new kit.web3.eth.Contract(MToken, '0xE4D517785D091D3c54818832dB6094bcc2744545'); MOO = new kit.web3.eth.Contract(MToken, '0x17700282592D6917F6A73D0bF8AcCf4D578c131e'); + UBE = new kit.web3.eth.Contract(MToken, '0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC'); + WETH = new kit.web3.eth.Contract(MToken, '0xDe37f36C9c045164CE89D3cEaeC67949EfACC398'); CELO = new kit.web3.eth.Contract(MToken, '0xF194afDf50B03e69Bd7D057c1Aa9e10c9954E4C9'); dataProvider = new kit.web3.eth.Contract( DataProvider, @@ -265,6 +269,8 @@ async function execute(network, action, ...params) { cUSD = new kit.web3.eth.Contract(MToken, '0x765DE816845861e75A25fCA122bb6898B8B1282a'); cREAL = new kit.web3.eth.Contract(MToken, '0xe8537a3d056DA446677B9E9d6c5dB704EaAb4787'); MOO = new kit.web3.eth.Contract(MToken, '0x17700282592D6917F6A73D0bF8AcCf4D578c131e'); + UBE = new kit.web3.eth.Contract(MToken, '0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC'); + WETH = new kit.web3.eth.Contract(MToken, '0x122013fd7dF1C6F636a5bb8f03108E876548b455'); CELO = new kit.web3.eth.Contract(MToken, '0x471EcE3750Da237f93B8E339c536989b8978a438'); dataProvider = new kit.web3.eth.Contract( DataProvider, @@ -339,6 +345,8 @@ async function execute(network, action, ...params) { ceur: cEUR, creal: cREAL, moo: MOO, + ube: UBE, + weth: WETH, }; const isValidAsset = (asset) => { diff --git a/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol b/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol index c4ac98b2..bd764fa4 100644 --- a/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol +++ b/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; @@ -11,7 +12,7 @@ contract UBEConfiguratorAlfajores is Ownable { LendingPoolConfigurator public lendingPoolConfigurator = LendingPoolConfigurator(lendingPoolConfiguratorAddress); - address constant assetAddress = 0x692A3Fe6cbe2588D64d7081bAF2F479424cCb2C3; // FIXME-- check the address + address constant assetAddress = 0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC; // FIXME-- check the address bytes constant params = '0x10'; bool constant stableBorrowRateEnabled = true; @@ -23,13 +24,14 @@ contract UBEConfiguratorAlfajores is Ownable { address constant treasury = 0x643C574128c7C56A1835e021Ad0EcC2592E72624; address constant incentivesController = 0x0000000000000000000000000000000000000000; string constant underlyingAssetName = 'Ubeswap'; - string constant aTokenName = 'Ubeswap interest bearing MOO'; + string constant aTokenName = 'Moola interest bearing UBE'; string constant aTokenSymbol = 'mUBE'; - string constant variableDebtTokenName = 'Ubeswap variable debt bearing mUBE'; + string constant variableDebtTokenName = 'Moola variable debt bearing mUBE'; string constant variableDebtTokenSymbol = 'variableDebtmUBE'; - string constant stableDebtTokenName = 'Ubeswap stable debt bearing mUBE'; + string constant stableDebtTokenName = 'Moola stable debt bearing mUBE'; string constant stableDebtTokenSymbol = 'stableDebtmUBE'; - uint256 constant baseLTV = 5000; + uint256 constant baseLTV = 5000; // TODO-- wait for params + uint256 constant liquidationThreshold = 6500; uint256 constant liquidationThreshold = 6500; uint256 constant liquidationBonus = 11000; uint256 constant reserveFactor = 1000; diff --git a/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol b/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol index e69de29b..5c0c9966 100644 --- a/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol +++ b/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {ERC20} from '../../../dependencies/openzeppelin/contracts/ERC20.sol'; +import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol'; +import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; +import '../../../interfaces/ILendingPoolConfigurator.sol'; + +contract UBEConfiguratorCelo is Ownable { + address constant lendingPoolConfiguratorAddress = 0x39fe2A4a4174bB5cAC5568ce0715a0b320bcB231; + + LendingPoolConfigurator public lendingPoolConfigurator = + LendingPoolConfigurator(lendingPoolConfiguratorAddress); + address constant assetAddress = 0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC; + + bytes constant params = '0x10'; + bool constant stableBorrowRateEnabled = true; + uint8 constant underlyingAssetDecimals = 18; + address constant aTokenImpl = 0xe8B286649713447D8d5fBeBC28c731830d19B6C9; + address constant stableDebtTokenImpl = 0xB6a5059A228a16Fa2827E28E52ceC96BBC63D639; + address constant variableDebtTokenImpl = 0xB65b6a6a6F78E4daABF259c756567ae346699687; + address constant interestRateStrategyAddress = 0x801443470c119F2eac65F13886D9e293CdecE2DF; + address constant treasury = 0x643C574128c7C56A1835e021Ad0EcC2592E72624; + address constant incentivesController = 0x0000000000000000000000000000000000000000; + string constant underlyingAssetName = 'Ubeswap'; + string constant aTokenName = 'Moola interest bearing UBE'; + string constant aTokenSymbol = 'mUBE'; + string constant variableDebtTokenName = 'Moola variable debt bearing mUBE'; + string constant variableDebtTokenSymbol = 'variableDebtmUBE'; + string constant stableDebtTokenName = 'Moola stable debt bearing mUBE'; + string constant stableDebtTokenSymbol = 'stableDebtmUBE'; + uint256 constant baseLTV = 5000; // TODO-- wait for params + uint256 constant liquidationThreshold = 6500; + uint256 constant liquidationThreshold = 6500; + uint256 constant liquidationBonus = 11000; + uint256 constant reserveFactor = 1000; + + function execute() external onlyOwner { + createReserve(); + enableCollateral(); + enableBorrowing(); + setReserveFactor(); + + selfdestruct(payable(treasury)); + } + + function destruct() external onlyOwner { + selfdestruct(payable(treasury)); + } + + function createReserve() internal { + ILendingPoolConfigurator.InitReserveInput[] + memory inputs = new ILendingPoolConfigurator.InitReserveInput[](1); + ILendingPoolConfigurator.InitReserveInput memory input = ILendingPoolConfigurator + .InitReserveInput({ + aTokenImpl: aTokenImpl, + stableDebtTokenImpl: stableDebtTokenImpl, + variableDebtTokenImpl: variableDebtTokenImpl, + underlyingAssetDecimals: underlyingAssetDecimals, + interestRateStrategyAddress: interestRateStrategyAddress, + underlyingAsset: assetAddress, + treasury: treasury, + incentivesController: incentivesController, + underlyingAssetName: underlyingAssetName, + aTokenName: aTokenName, + aTokenSymbol: aTokenSymbol, + variableDebtTokenName: variableDebtTokenName, + variableDebtTokenSymbol: variableDebtTokenSymbol, + stableDebtTokenName: stableDebtTokenName, + stableDebtTokenSymbol: stableDebtTokenSymbol, + params: params + }); + inputs[0] = input; + + lendingPoolConfigurator.batchInitReserve(inputs); + } + + function enableCollateral() internal { + lendingPoolConfigurator.configureReserveAsCollateral( + assetAddress, + baseLTV, + liquidationThreshold, + liquidationBonus + ); + } + + function enableBorrowing() internal { + lendingPoolConfigurator.enableBorrowingOnReserve(assetAddress, stableBorrowRateEnabled); + } + + function setReserveFactor() internal { + lendingPoolConfigurator.setReserveFactor(assetAddress, reserveFactor); + } +} diff --git a/contracts/protocol/lendingpool/MOBI/MOBIConfiguratorAlfajores.sol b/contracts/protocol/lendingpool/WETH/WETHConfiguratorAlfajores.sol similarity index 79% rename from contracts/protocol/lendingpool/MOBI/MOBIConfiguratorAlfajores.sol rename to contracts/protocol/lendingpool/WETH/WETHConfiguratorAlfajores.sol index aed820c8..6360f9a7 100644 --- a/contracts/protocol/lendingpool/MOBI/MOBIConfiguratorAlfajores.sol +++ b/contracts/protocol/lendingpool/WETH/WETHConfiguratorAlfajores.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; @@ -6,12 +7,12 @@ import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol' import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; import '../../../interfaces/ILendingPoolConfigurator.sol'; -contract MOBIConfiguratorAlfajores is Ownable { +contract WETHConfiguratorAlfajores is Ownable { address constant lendingPoolConfiguratorAddress = 0x39fe2A4a4174bB5cAC5568ce0715a0b320bcB231; LendingPoolConfigurator public lendingPoolConfigurator = LendingPoolConfigurator(lendingPoolConfiguratorAddress); - address constant assetAddress = 0x17700282592D6917F6A73D0bF8AcCf4D578c131e; + address constant assetAddress = 0xDe37f36C9c045164CE89D3cEaeC67949EfACC398; bytes constant params = '0x10'; bool constant stableBorrowRateEnabled = true; @@ -19,17 +20,18 @@ contract MOBIConfiguratorAlfajores is Ownable { address constant aTokenImpl = 0xe8B286649713447D8d5fBeBC28c731830d19B6C9; address constant stableDebtTokenImpl = 0xB6a5059A228a16Fa2827E28E52ceC96BBC63D639; address constant variableDebtTokenImpl = 0xB65b6a6a6F78E4daABF259c756567ae346699687; - address constant interestRateStrategyAddress = 0x3C06Fb2f5Ab65b0e35F91073d88afE2b017D04b8; + address constant interestRateStrategyAddress = 0x5B41b0c78659636c6664f08F7cCb620ceA3F1206; address constant treasury = 0x643C574128c7C56A1835e021Ad0EcC2592E72624; address constant incentivesController = 0x0000000000000000000000000000000000000000; - string constant underlyingAssetName = 'Mobius DAO'; - string constant aTokenName = 'Mobius DAO interest bearing MOO'; - string constant aTokenSymbol = 'mMOBI'; - string constant variableDebtTokenName = 'Mobius DAO variable debt bearing mMOBI'; - string constant variableDebtTokenSymbol = 'variableDebtmMOBI'; - string constant stableDebtTokenName = 'Mobius DAO stable debt bearing mMOBI'; - string constant stableDebtTokenSymbol = 'stableDebtmMOBI'; - uint256 constant baseLTV = 5000; + string constant underlyingAssetName = 'Wrapped Ether'; + string constant aTokenName = 'Moola interest bearing WETH'; + string constant aTokenSymbol = 'mWETH'; + string constant variableDebtTokenName = 'Moola variable debt bearing mWETH'; + string constant variableDebtTokenSymbol = 'variableDebtmWETH'; + string constant stableDebtTokenName = 'Moola stable debt bearing mWETH'; + string constant stableDebtTokenSymbol = 'stableDebtmWETH'; + uint256 constant baseLTV = 5000; // TODO-- wait for params + uint256 constant liquidationThreshold = 6500; uint256 constant liquidationThreshold = 6500; uint256 constant liquidationBonus = 11000; uint256 constant reserveFactor = 1000; diff --git a/contracts/protocol/lendingpool/MOBI/MOBIConfiguratorCelo.sol b/contracts/protocol/lendingpool/WETH/WETHConfiguratorCelo.sol similarity index 80% rename from contracts/protocol/lendingpool/MOBI/MOBIConfiguratorCelo.sol rename to contracts/protocol/lendingpool/WETH/WETHConfiguratorCelo.sol index 44f39e7f..dc755ed7 100644 --- a/contracts/protocol/lendingpool/MOBI/MOBIConfiguratorCelo.sol +++ b/contracts/protocol/lendingpool/WETH/WETHConfiguratorCelo.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; @@ -6,12 +7,12 @@ import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol' import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; import '../../../interfaces/ILendingPoolConfigurator.sol'; -contract MOOConfiguratorCelo is Ownable { +contract WETHConfiguratorCelo is Ownable { address constant lendingPoolConfiguratorAddress = 0x928F63a83217e427A84504950206834CBDa4Aa65; LendingPoolConfigurator public lendingPoolConfigurator = LendingPoolConfigurator(lendingPoolConfiguratorAddress); - address constant assetAddress = 0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC; + address constant assetAddress = 0x122013fd7dF1C6F636a5bb8f03108E876548b455; bytes constant params = '0x10'; bool constant stableBorrowRateEnabled = true; @@ -19,17 +20,17 @@ contract MOOConfiguratorCelo is Ownable { address constant aTokenImpl = 0x55bFCED2451b2154e06604D4269c9349F31141e6; address constant stableDebtTokenImpl = 0xaCdb7B3e2b0a038F1f4eF04736728E0065b689DA; address constant variableDebtTokenImpl = 0x0301Cf8F1FCD9255BD32FB7e0fE5B3494f445C2C; - address constant interestRateStrategyAddress = 0x801443470c119F2eac65F13886D9e293CdecE2DF; + address constant interestRateStrategyAddress = 0xb3072f5F0d5e8B9036aEC29F37baB70E86EA0018; address constant treasury = 0x313bc86D3D6e86ba164B2B451cB0D9CfA7943e5c; address constant incentivesController = 0x0000000000000000000000000000000000000000; - string constant underlyingAssetName = 'Ubeswap'; - string constant aTokenName = 'Ubeswap interest bearing MOO'; - string constant aTokenSymbol = 'mUBE'; - string constant variableDebtTokenName = 'Ubeswap variable debt bearing mUBE'; - string constant variableDebtTokenSymbol = 'variableDebtmUBE'; - string constant stableDebtTokenName = 'Ubeswap stable debt bearing mUBE'; - string constant stableDebtTokenSymbol = 'stableDebtmUBE'; - uint256 constant baseLTV = 5000; + string constant underlyingAssetName = 'Wrapped Ether'; + string constant aTokenName = 'Moola interest bearing WETH'; + string constant aTokenSymbol = 'mWETH'; + string constant variableDebtTokenName = 'Moola variable debt bearing mWETH'; + string constant variableDebtTokenSymbol = 'variableDebtmWETH'; + string constant stableDebtTokenName = 'Moola stable debt bearing mWETH'; + string constant stableDebtTokenSymbol = 'stableDebtmWETH'; + uint256 constant baseLTV = 5000; // TODO-- wait for params uint256 constant liquidationThreshold = 6500; uint256 constant liquidationBonus = 11000; uint256 constant reserveFactor = 1000; From 05ebf07935dff5ccaf54e269e159702bf9fff1bc Mon Sep 17 00:00:00 2001 From: x-moola Date: Tue, 26 Apr 2022 08:35:41 -0700 Subject: [PATCH 03/11] Update configurators --- cli.js | 3 ++- .../protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol | 5 ++--- .../protocol/lendingpool/WETH/WETHConfiguratorAlfajores.sol | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/cli.js b/cli.js index ba287c54..80c2d1b4 100644 --- a/cli.js +++ b/cli.js @@ -654,7 +654,8 @@ async function execute(network, action, ...params) { const from = params[1]; const user = params[2]; const amount = web3.utils.toWei(params[3]); - const rate = INTEREST_RATE[params[4].toUpperCase()]; + // const rate = INTEREST_RATE[params[4].toUpperCase()]; + const rate = parseInt(params[4]); if (privateKeyRequired) { pk = params[5]; if (!pk) { diff --git a/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol b/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol index bd764fa4..808ed16d 100644 --- a/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol +++ b/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol @@ -12,7 +12,7 @@ contract UBEConfiguratorAlfajores is Ownable { LendingPoolConfigurator public lendingPoolConfigurator = LendingPoolConfigurator(lendingPoolConfiguratorAddress); - address constant assetAddress = 0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC; // FIXME-- check the address + address constant assetAddress = 0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC; bytes constant params = '0x10'; bool constant stableBorrowRateEnabled = true; @@ -30,8 +30,7 @@ contract UBEConfiguratorAlfajores is Ownable { string constant variableDebtTokenSymbol = 'variableDebtmUBE'; string constant stableDebtTokenName = 'Moola stable debt bearing mUBE'; string constant stableDebtTokenSymbol = 'stableDebtmUBE'; - uint256 constant baseLTV = 5000; // TODO-- wait for params - uint256 constant liquidationThreshold = 6500; + uint256 constant baseLTV = 5000; uint256 constant liquidationThreshold = 6500; uint256 constant liquidationBonus = 11000; uint256 constant reserveFactor = 1000; diff --git a/contracts/protocol/lendingpool/WETH/WETHConfiguratorAlfajores.sol b/contracts/protocol/lendingpool/WETH/WETHConfiguratorAlfajores.sol index 6360f9a7..ba180ba5 100644 --- a/contracts/protocol/lendingpool/WETH/WETHConfiguratorAlfajores.sol +++ b/contracts/protocol/lendingpool/WETH/WETHConfiguratorAlfajores.sol @@ -30,8 +30,7 @@ contract WETHConfiguratorAlfajores is Ownable { string constant variableDebtTokenSymbol = 'variableDebtmWETH'; string constant stableDebtTokenName = 'Moola stable debt bearing mWETH'; string constant stableDebtTokenSymbol = 'stableDebtmWETH'; - uint256 constant baseLTV = 5000; // TODO-- wait for params - uint256 constant liquidationThreshold = 6500; + uint256 constant baseLTV = 5000; uint256 constant liquidationThreshold = 6500; uint256 constant liquidationBonus = 11000; uint256 constant reserveFactor = 1000; From bf45674351e388d0894ab25cb2417b48de5a95bd Mon Sep 17 00:00:00 2001 From: x-moola Date: Fri, 17 Jun 2022 12:34:13 -0700 Subject: [PATCH 04/11] Update configurators --- contracts/protocol/.DS_Store | Bin 0 -> 6148 bytes .../GNTConfiguratorAlfajores.sol} | 16 +- .../GNTConfiguratorCelo.sol} | 14 +- contracts/protocol/lendingpool/test.sol | 4308 +++++++++++++++++ 4 files changed, 4323 insertions(+), 15 deletions(-) create mode 100644 contracts/protocol/.DS_Store rename contracts/protocol/lendingpool/{WETH/WETHConfiguratorAlfajores.sol => GNT/GNTConfiguratorAlfajores.sol} (90%) rename contracts/protocol/lendingpool/{WETH/WETHConfiguratorCelo.sol => GNT/GNTConfiguratorCelo.sol} (92%) create mode 100644 contracts/protocol/lendingpool/test.sol diff --git a/contracts/protocol/.DS_Store b/contracts/protocol/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ddc54e7cb9a2f82365c60a3ef66f2944cda4fab2 GIT binary patch literal 6148 zcmeHKJ8HvF5S)!&7~HsY`L2)~JdAS!Um%5p2?#j^l3G>Hm7`_$LqLcSH)+DG*q!%Q zJ5Oi|trmbC-p=>H4#0-)hz}1-^ZV`#yQ_>5={(~ZBQAKsmDg?N+${z?k$Il+hxgO# zI9$g|o_^bLs*(ayKnh3!DIf)YQNVjIZL>{Olmb#f3VbWz--kwb?1fWed^#9n1R$=N z4&ypz31agEu@_E>%+M^U#H3n{7?yPATh;Z#DKY7=8a}L^Y&D@+Je}vaD2Me#MJXT! z<_fHGyYv44K>uO>pOdtc0#e{#DPZg4>3HBPRc~FqocG#Bf24cOC*6(fpfE%`CPq8v g#@q2ein6Zxn)iF*lo)j8gHF`Xfa@ZY0)MT*7fqNJ8UO$Q literal 0 HcmV?d00001 diff --git a/contracts/protocol/lendingpool/WETH/WETHConfiguratorAlfajores.sol b/contracts/protocol/lendingpool/GNT/GNTConfiguratorAlfajores.sol similarity index 90% rename from contracts/protocol/lendingpool/WETH/WETHConfiguratorAlfajores.sol rename to contracts/protocol/lendingpool/GNT/GNTConfiguratorAlfajores.sol index ba180ba5..67c03036 100644 --- a/contracts/protocol/lendingpool/WETH/WETHConfiguratorAlfajores.sol +++ b/contracts/protocol/lendingpool/GNT/GNTConfiguratorAlfajores.sol @@ -7,7 +7,7 @@ import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol' import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; import '../../../interfaces/ILendingPoolConfigurator.sol'; -contract WETHConfiguratorAlfajores is Ownable { +contract GNTConfiguratorAlfajores is Ownable { address constant lendingPoolConfiguratorAddress = 0x39fe2A4a4174bB5cAC5568ce0715a0b320bcB231; LendingPoolConfigurator public lendingPoolConfigurator = @@ -23,13 +23,13 @@ contract WETHConfiguratorAlfajores is Ownable { address constant interestRateStrategyAddress = 0x5B41b0c78659636c6664f08F7cCb620ceA3F1206; address constant treasury = 0x643C574128c7C56A1835e021Ad0EcC2592E72624; address constant incentivesController = 0x0000000000000000000000000000000000000000; - string constant underlyingAssetName = 'Wrapped Ether'; - string constant aTokenName = 'Moola interest bearing WETH'; - string constant aTokenSymbol = 'mWETH'; - string constant variableDebtTokenName = 'Moola variable debt bearing mWETH'; - string constant variableDebtTokenSymbol = 'variableDebtmWETH'; - string constant stableDebtTokenName = 'Moola stable debt bearing mWETH'; - string constant stableDebtTokenSymbol = 'stableDebtmWETH'; + string constant underlyingAssetName = 'CarbonCreditBundleToken'; + string constant aTokenName = 'Moola interest bearing GNT'; + string constant aTokenSymbol = 'mGNT'; + string constant variableDebtTokenName = 'Moola variable debt bearing mGNT'; + string constant variableDebtTokenSymbol = 'variableDebtmGNT'; + string constant stableDebtTokenName = 'Moola stable debt bearing mGNT'; + string constant stableDebtTokenSymbol = 'stableDebtmGNT'; uint256 constant baseLTV = 5000; uint256 constant liquidationThreshold = 6500; uint256 constant liquidationBonus = 11000; diff --git a/contracts/protocol/lendingpool/WETH/WETHConfiguratorCelo.sol b/contracts/protocol/lendingpool/GNT/GNTConfiguratorCelo.sol similarity index 92% rename from contracts/protocol/lendingpool/WETH/WETHConfiguratorCelo.sol rename to contracts/protocol/lendingpool/GNT/GNTConfiguratorCelo.sol index dc755ed7..f8958f94 100644 --- a/contracts/protocol/lendingpool/WETH/WETHConfiguratorCelo.sol +++ b/contracts/protocol/lendingpool/GNT/GNTConfiguratorCelo.sol @@ -7,7 +7,7 @@ import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol' import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; import '../../../interfaces/ILendingPoolConfigurator.sol'; -contract WETHConfiguratorCelo is Ownable { +contract GNTConfiguratorCelo is Ownable { address constant lendingPoolConfiguratorAddress = 0x928F63a83217e427A84504950206834CBDa4Aa65; LendingPoolConfigurator public lendingPoolConfigurator = @@ -24,12 +24,12 @@ contract WETHConfiguratorCelo is Ownable { address constant treasury = 0x313bc86D3D6e86ba164B2B451cB0D9CfA7943e5c; address constant incentivesController = 0x0000000000000000000000000000000000000000; string constant underlyingAssetName = 'Wrapped Ether'; - string constant aTokenName = 'Moola interest bearing WETH'; - string constant aTokenSymbol = 'mWETH'; - string constant variableDebtTokenName = 'Moola variable debt bearing mWETH'; - string constant variableDebtTokenSymbol = 'variableDebtmWETH'; - string constant stableDebtTokenName = 'Moola stable debt bearing mWETH'; - string constant stableDebtTokenSymbol = 'stableDebtmWETH'; + string constant aTokenName = 'Moola interest bearing GNT'; + string constant aTokenSymbol = 'mGNT'; + string constant variableDebtTokenName = 'Moola variable debt bearing mGNT'; + string constant variableDebtTokenSymbol = 'variableDebtmGNT'; + string constant stableDebtTokenName = 'Moola stable debt bearing mGNT'; + string constant stableDebtTokenSymbol = 'stableDebtmGNT'; uint256 constant baseLTV = 5000; // TODO-- wait for params uint256 constant liquidationThreshold = 6500; uint256 constant liquidationBonus = 11000; diff --git a/contracts/protocol/lendingpool/test.sol b/contracts/protocol/lendingpool/test.sol new file mode 100644 index 00000000..65816839 --- /dev/null +++ b/contracts/protocol/lendingpool/test.sol @@ -0,0 +1,4308 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, 'SafeMath: addition overflow'); + + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + return sub(a, b, 'SafeMath: subtraction overflow'); + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * - Subtraction cannot overflow. + */ + function sub( + uint256 a, + uint256 b, + string memory errorMessage + ) internal pure returns (uint256) { + require(b <= a, errorMessage); + uint256 c = a - b; + + return c; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) { + return 0; + } + + uint256 c = a * b; + require(c / a == b, 'SafeMath: multiplication overflow'); + + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return div(a, b, 'SafeMath: division by zero'); + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts with custom message on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * - The divisor cannot be zero. + */ + function div( + uint256 a, + uint256 b, + string memory errorMessage + ) internal pure returns (uint256) { + // Solidity only automatically asserts when dividing by 0 + require(b > 0, errorMessage); + uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + + return c; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + return mod(a, b, 'SafeMath: modulo by zero'); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts with custom message when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * - The divisor cannot be zero. + */ + function mod( + uint256 a, + uint256 b, + string memory errorMessage + ) internal pure returns (uint256) { + require(b != 0, errorMessage); + return a % b; + } +} + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address sender, + address recipient, + uint256 amount + ) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // According to EIP-1052, 0x0 is the value returned for not-yet created accounts + // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned + // for accounts without code, i.e. `keccak256('')` + bytes32 codehash; + bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; + // solhint-disable-next-line no-inline-assembly + assembly { + codehash := extcodehash(account) + } + return (codehash != accountHash && codehash != 0x0); + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, 'Address: insufficient balance'); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{value: amount}(''); + require(success, 'Address: unable to send value, recipient may have reverted'); + } +} + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using SafeMath for uint256; + using Address for address; + + function safeTransfer( + IERC20 token, + address to, + uint256 value + ) internal { + callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); + } + + function safeTransferFrom( + IERC20 token, + address from, + address to, + uint256 value + ) internal { + callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); + } + + function safeApprove( + IERC20 token, + address spender, + uint256 value + ) internal { + require( + (value == 0) || (token.allowance(address(this), spender) == 0), + 'SafeERC20: approve from non-zero to non-zero allowance' + ); + callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); + } + + function callOptionalReturn(IERC20 token, bytes memory data) private { + require(address(token).isContract(), 'SafeERC20: call to non-contract'); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = address(token).call(data); + require(success, 'SafeERC20: low-level call failed'); + + if (returndata.length > 0) { + // Return data is optional + // solhint-disable-next-line max-line-length + require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed'); + } + } +} + +/** + * @title LendingPoolAddressesProvider contract + * @dev Main registry of addresses part of or connected to the protocol, including permissioned roles + * - Acting also as factory of proxies and admin of those, so with right to change its implementations + * - Owned by the Aave Governance + * @author Aave + **/ +interface ILendingPoolAddressesProvider { + event MarketIdSet(string newMarketId); + event LendingPoolUpdated(address indexed newAddress); + event ConfigurationAdminUpdated(address indexed newAddress); + event EmergencyAdminUpdated(address indexed newAddress); + event LendingPoolConfiguratorUpdated(address indexed newAddress); + event LendingPoolCollateralManagerUpdated(address indexed newAddress); + event PriceOracleUpdated(address indexed newAddress); + event LendingRateOracleUpdated(address indexed newAddress); + event ProxyCreated(bytes32 id, address indexed newAddress); + event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy); + + function getMarketId() external view returns (string memory); + + function setMarketId(string calldata marketId) external; + + function setAddress(bytes32 id, address newAddress) external; + + function setAddressAsProxy(bytes32 id, address impl) external; + + function getAddress(bytes32 id) external view returns (address); + + function getLendingPool() external view returns (address); + + function setLendingPoolImpl(address pool) external; + + function getLendingPoolConfigurator() external view returns (address); + + function setLendingPoolConfiguratorImpl(address configurator) external; + + function getLendingPoolCollateralManager() external view returns (address); + + function setLendingPoolCollateralManager(address manager) external; + + function getPoolAdmin() external view returns (address); + + function setPoolAdmin(address admin) external; + + function getEmergencyAdmin() external view returns (address); + + function setEmergencyAdmin(address admin) external; + + function getPriceOracle() external view returns (address); + + function setPriceOracle(address priceOracle) external; + + function getLendingRateOracle() external view returns (address); + + function setLendingRateOracle(address lendingRateOracle) external; +} + +interface IScaledBalanceToken { + /** + * @dev Returns the scaled balance of the user. The scaled balance is the sum of all the + * updated stored balance divided by the reserve's liquidity index at the moment of the update + * @param user The user whose balance is calculated + * @return The scaled balance of the user + **/ + function scaledBalanceOf(address user) external view returns (uint256); + + /** + * @dev Returns the scaled balance of the user and the scaled total supply. + * @param user The address of the user + * @return The scaled balance of the user + * @return The scaled balance and the scaled total supply + **/ + function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256); + + /** + * @dev Returns the scaled total supply of the variable debt token. Represents sum(debt/index) + * @return The scaled total supply + **/ + function scaledTotalSupply() external view returns (uint256); +} + +library DataTypes { + // refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties. + struct ReserveData { + //stores the reserve configuration + ReserveConfigurationMap configuration; + //the liquidity index. Expressed in ray + uint128 liquidityIndex; + //variable borrow index. Expressed in ray + uint128 variableBorrowIndex; + //the current supply rate. Expressed in ray + uint128 currentLiquidityRate; + //the current variable borrow rate. Expressed in ray + uint128 currentVariableBorrowRate; + //the current stable borrow rate. Expressed in ray + uint128 currentStableBorrowRate; + uint40 lastUpdateTimestamp; + //tokens addresses + address aTokenAddress; + address stableDebtTokenAddress; + address variableDebtTokenAddress; + //address of the interest rate strategy + address interestRateStrategyAddress; + //the id of the reserve. Represents the position in the list of the active reserves + uint8 id; + } + + struct ReserveConfigurationMap { + //bit 0-15: LTV + //bit 16-31: Liq. threshold + //bit 32-47: Liq. bonus + //bit 48-55: Decimals + //bit 56: Reserve is active + //bit 57: reserve is frozen + //bit 58: borrowing is enabled + //bit 59: stable rate borrowing enabled + //bit 60-63: reserved + //bit 64-79: reserve factor + uint256 data; + } + + struct UserConfigurationMap { + uint256 data; + } + + enum InterestRateMode { + NONE, + STABLE, + VARIABLE + } +} + +/** + * @title UserConfiguration library + * @author Aave + * @notice Implements the bitmap logic to handle the user configuration + */ +library UserConfiguration { + uint256 internal constant BORROWING_MASK = + 0x5555555555555555555555555555555555555555555555555555555555555555; + + /** + * @dev Sets if the user is borrowing the reserve identified by reserveIndex + * @param self The configuration object + * @param reserveIndex The index of the reserve in the bitmap + * @param borrowing True if the user is borrowing the reserve, false otherwise + **/ + function setBorrowing( + DataTypes.UserConfigurationMap storage self, + uint256 reserveIndex, + bool borrowing + ) internal { + require(reserveIndex < 128, Errors.UL_INVALID_INDEX); + self.data = + (self.data & ~(1 << (reserveIndex * 2))) | + (uint256(borrowing ? 1 : 0) << (reserveIndex * 2)); + } + + /** + * @dev Sets if the user is using as collateral the reserve identified by reserveIndex + * @param self The configuration object + * @param reserveIndex The index of the reserve in the bitmap + * @param usingAsCollateral True if the user is usin the reserve as collateral, false otherwise + **/ + function setUsingAsCollateral( + DataTypes.UserConfigurationMap storage self, + uint256 reserveIndex, + bool usingAsCollateral + ) internal { + require(reserveIndex < 128, Errors.UL_INVALID_INDEX); + self.data = + (self.data & ~(1 << (reserveIndex * 2 + 1))) | + (uint256(usingAsCollateral ? 1 : 0) << (reserveIndex * 2 + 1)); + } + + /** + * @dev Used to validate if a user has been using the reserve for borrowing or as collateral + * @param self The configuration object + * @param reserveIndex The index of the reserve in the bitmap + * @return True if the user has been using a reserve for borrowing or as collateral, false otherwise + **/ + function isUsingAsCollateralOrBorrowing( + DataTypes.UserConfigurationMap memory self, + uint256 reserveIndex + ) internal pure returns (bool) { + require(reserveIndex < 128, Errors.UL_INVALID_INDEX); + return (self.data >> (reserveIndex * 2)) & 3 != 0; + } + + /** + * @dev Used to validate if a user has been using the reserve for borrowing + * @param self The configuration object + * @param reserveIndex The index of the reserve in the bitmap + * @return True if the user has been using a reserve for borrowing, false otherwise + **/ + function isBorrowing(DataTypes.UserConfigurationMap memory self, uint256 reserveIndex) + internal + pure + returns (bool) + { + require(reserveIndex < 128, Errors.UL_INVALID_INDEX); + return (self.data >> (reserveIndex * 2)) & 1 != 0; + } + + /** + * @dev Used to validate if a user has been using the reserve as collateral + * @param self The configuration object + * @param reserveIndex The index of the reserve in the bitmap + * @return True if the user has been using a reserve as collateral, false otherwise + **/ + function isUsingAsCollateral(DataTypes.UserConfigurationMap memory self, uint256 reserveIndex) + internal + pure + returns (bool) + { + require(reserveIndex < 128, Errors.UL_INVALID_INDEX); + return (self.data >> (reserveIndex * 2 + 1)) & 1 != 0; + } + + /** + * @dev Used to validate if a user has been borrowing from any reserve + * @param self The configuration object + * @return True if the user has been borrowing any reserve, false otherwise + **/ + function isBorrowingAny(DataTypes.UserConfigurationMap memory self) internal pure returns (bool) { + return self.data & BORROWING_MASK != 0; + } + + /** + * @dev Used to validate if a user has not been using any reserve + * @param self The configuration object + * @return True if the user has been borrowing any reserve, false otherwise + **/ + function isEmpty(DataTypes.UserConfigurationMap memory self) internal pure returns (bool) { + return self.data == 0; + } +} + +interface ILendingPool { + /** + * @dev Emitted on deposit() + * @param reserve The address of the underlying asset of the reserve + * @param user The address initiating the deposit + * @param onBehalfOf The beneficiary of the deposit, receiving the aTokens + * @param amount The amount deposited + * @param referral The referral code used + **/ + event Deposit( + address indexed reserve, + address user, + address indexed onBehalfOf, + uint256 amount, + uint16 indexed referral + ); + + /** + * @dev Emitted on withdraw() + * @param reserve The address of the underlyng asset being withdrawn + * @param user The address initiating the withdrawal, owner of aTokens + * @param to Address that will receive the underlying + * @param amount The amount to be withdrawn + **/ + event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount); + + /** + * @dev Emitted on borrow() and flashLoan() when debt needs to be opened + * @param reserve The address of the underlying asset being borrowed + * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just + * initiator of the transaction on flashLoan() + * @param onBehalfOf The address that will be getting the debt + * @param amount The amount borrowed out + * @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable + * @param borrowRate The numeric rate at which the user has borrowed + * @param referral The referral code used + **/ + event Borrow( + address indexed reserve, + address user, + address indexed onBehalfOf, + uint256 amount, + uint256 borrowRateMode, + uint256 borrowRate, + uint16 indexed referral + ); + + /** + * @dev Emitted on repay() + * @param reserve The address of the underlying asset of the reserve + * @param user The beneficiary of the repayment, getting his debt reduced + * @param repayer The address of the user initiating the repay(), providing the funds + * @param amount The amount repaid + **/ + event Repay( + address indexed reserve, + address indexed user, + address indexed repayer, + uint256 amount + ); + + /** + * @dev Emitted on swapBorrowRateMode() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user swapping his rate mode + * @param rateMode The rate mode that the user wants to swap to + **/ + event Swap(address indexed reserve, address indexed user, uint256 rateMode); + + /** + * @dev Emitted on setUserUseReserveAsCollateral() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user enabling the usage as collateral + **/ + event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); + + /** + * @dev Emitted on setUserUseReserveAsCollateral() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user enabling the usage as collateral + **/ + event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); + + /** + * @dev Emitted on rebalanceStableBorrowRate() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user for which the rebalance has been executed + **/ + event RebalanceStableBorrowRate(address indexed reserve, address indexed user); + + /** + * @dev Emitted on flashLoan() + * @param target The address of the flash loan receiver contract + * @param initiator The address initiating the flash loan + * @param asset The address of the asset being flash borrowed + * @param amount The amount flash borrowed + * @param premium The fee flash borrowed + * @param referralCode The referral code used + **/ + event FlashLoan( + address indexed target, + address indexed initiator, + address indexed asset, + uint256 amount, + uint256 premium, + uint16 referralCode + ); + + /** + * @dev Emitted when the pause is triggered. + */ + event Paused(); + + /** + * @dev Emitted when the pause is lifted. + */ + event Unpaused(); + + /** + * @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via + * LendingPoolCollateral manager using a DELEGATECALL + * This allows to have the events in the generated ABI for LendingPool. + * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation + * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation + * @param user The address of the borrower getting liquidated + * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover + * @param liquidatedCollateralAmount The amount of collateral received by the liiquidator + * @param liquidator The address of the liquidator + * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants + * to receive the underlying collateral asset directly + **/ + event LiquidationCall( + address indexed collateralAsset, + address indexed debtAsset, + address indexed user, + uint256 debtToCover, + uint256 liquidatedCollateralAmount, + address liquidator, + bool receiveAToken + ); + + /** + * @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared + * in the ReserveLogic library and emitted in the updateInterestRates() function. Since the function is internal, + * the event will actually be fired by the LendingPool contract. The event is therefore replicated here so it + * gets added to the LendingPool ABI + * @param reserve The address of the underlying asset of the reserve + * @param liquidityRate The new liquidity rate + * @param stableBorrowRate The new stable borrow rate + * @param variableBorrowRate The new variable borrow rate + * @param liquidityIndex The new liquidity index + * @param variableBorrowIndex The new variable borrow index + **/ + event ReserveDataUpdated( + address indexed reserve, + uint256 liquidityRate, + uint256 stableBorrowRate, + uint256 variableBorrowRate, + uint256 liquidityIndex, + uint256 variableBorrowIndex + ); + + /** + * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. + * - E.g. User deposits 100 USDC and gets in return 100 aUSDC + * @param asset The address of the underlying asset to deposit + * @param amount The amount to be deposited + * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user + * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens + * is a different wallet + * @param referralCode Code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + **/ + function deposit( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) external; + + /** + * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned + * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC + * @param asset The address of the underlying asset to withdraw + * @param amount The underlying amount to be withdrawn + * - Send the value type(uint256).max in order to withdraw the whole aToken balance + * @param to Address that will receive the underlying, same as msg.sender if the user + * wants to receive it on his own wallet, or a different address if the beneficiary is a + * different wallet + * @return The final amount withdrawn + **/ + function withdraw( + address asset, + uint256 amount, + address to + ) external returns (uint256); + + /** + * @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower + * already deposited enough collateral, or he was given enough allowance by a credit delegator on the + * corresponding debt token (StableDebtToken or VariableDebtToken) + * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet + * and 100 stable/variable debt tokens, depending on the `interestRateMode` + * @param asset The address of the underlying asset to borrow + * @param amount The amount to be borrowed + * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable + * @param referralCode Code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself + * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator + * if he has been given credit delegation allowance + **/ + function borrow( + address asset, + uint256 amount, + uint256 interestRateMode, + uint16 referralCode, + address onBehalfOf + ) external; + + /** + * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned + * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` + * @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable + * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the + * user calling the function if he wants to reduce/remove his own debt, or the address of any other + * other borrower whose debt should be removed + * @return The final amount repaid + **/ + function repay( + address asset, + uint256 amount, + uint256 rateMode, + address onBehalfOf + ) external returns (uint256); + + /** + * @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa + * @param asset The address of the underlying asset borrowed + * @param rateMode The rate mode that the user wants to swap to + **/ + function swapBorrowRateMode(address asset, uint256 rateMode) external; + + /** + * @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve. + * - Users can be rebalanced if the following conditions are satisfied: + * 1. Usage ratio is above 95% + * 2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been + * borrowed at a stable rate and depositors are not earning enough + * @param asset The address of the underlying asset borrowed + * @param user The address of the user to be rebalanced + **/ + function rebalanceStableBorrowRate(address asset, address user) external; + + /** + * @dev Allows depositors to enable/disable a specific deposited asset as collateral + * @param asset The address of the underlying asset deposited + * @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise + **/ + function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external; + + /** + * @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1 + * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives + * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk + * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation + * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation + * @param user The address of the borrower getting liquidated + * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover + * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants + * to receive the underlying collateral asset directly + **/ + function liquidationCall( + address collateralAsset, + address debtAsset, + address user, + uint256 debtToCover, + bool receiveAToken + ) external; + + /** + * @dev Allows smartcontracts to access the liquidity of the pool within one transaction, + * as long as the amount taken plus a fee is returned. + * IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration. + * For further details please visit https://developers.aave.com + * @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface + * @param assets The addresses of the assets being flash-borrowed + * @param amounts The amounts amounts being flash-borrowed + * @param modes Types of the debt to open if the flash loan is not returned: + * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver + * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address + * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address + * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2 + * @param params Variadic packed params to pass to the receiver as extra information + * @param referralCode Code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + **/ + function flashLoan( + address receiverAddress, + address[] calldata assets, + uint256[] calldata amounts, + uint256[] calldata modes, + address onBehalfOf, + bytes calldata params, + uint16 referralCode + ) external; + + /** + * @dev Returns the user account data across all the reserves + * @param user The address of the user + * @return totalCollateralETH the total collateral in ETH of the user + * @return totalDebtETH the total debt in ETH of the user + * @return availableBorrowsETH the borrowing power left of the user + * @return currentLiquidationThreshold the liquidation threshold of the user + * @return ltv the loan to value of the user + * @return healthFactor the current health factor of the user + **/ + function getUserAccountData(address user) + external + view + returns ( + uint256 totalCollateralETH, + uint256 totalDebtETH, + uint256 availableBorrowsETH, + uint256 currentLiquidationThreshold, + uint256 ltv, + uint256 healthFactor + ); + + function initReserve( + address reserve, + address aTokenAddress, + address stableDebtAddress, + address variableDebtAddress, + address interestRateStrategyAddress + ) external; + + function setReserveInterestRateStrategyAddress(address reserve, address rateStrategyAddress) + external; + + function setConfiguration(address reserve, uint256 configuration) external; + + /** + * @dev Returns the configuration of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The configuration of the reserve + **/ + function getConfiguration(address asset) + external + view + returns (DataTypes.ReserveConfigurationMap memory); + + /** + * @dev Returns the configuration of the user across all the reserves + * @param user The user address + * @return The configuration of the user + **/ + function getUserConfiguration(address user) + external + view + returns (DataTypes.UserConfigurationMap memory); + + /** + * @dev Returns the normalized income normalized income of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The reserve's normalized income + */ + function getReserveNormalizedIncome(address asset) external view returns (uint256); + + /** + * @dev Returns the normalized variable debt per unit of asset + * @param asset The address of the underlying asset of the reserve + * @return The reserve normalized variable debt + */ + function getReserveNormalizedVariableDebt(address asset) external view returns (uint256); + + /** + * @dev Returns the state and configuration of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The state of the reserve + **/ + function getReserveData(address asset) external view returns (DataTypes.ReserveData memory); + + function finalizeTransfer( + address asset, + address from, + address to, + uint256 amount, + uint256 balanceFromAfter, + uint256 balanceToBefore + ) external; + + function getReservesList() external view returns (address[] memory); + + function getAddressesProvider() external view returns (ILendingPoolAddressesProvider); + + function setPause(bool val) external; + + function paused() external view returns (bool); +} + +interface IAaveIncentivesController { + function handleAction( + address user, + uint256 userBalance, + uint256 totalSupply + ) external; +} + +/** + * @title IInitializableAToken + * @notice Interface for the initialize function on AToken + * @author Aave + **/ +interface IInitializableAToken { + /** + * @dev Emitted when an aToken is initialized + * @param underlyingAsset The address of the underlying asset + * @param pool The address of the associated lending pool + * @param treasury The address of the treasury + * @param incentivesController The address of the incentives controller for this aToken + * @param aTokenDecimals the decimals of the underlying + * @param aTokenName the name of the aToken + * @param aTokenSymbol the symbol of the aToken + * @param params A set of encoded parameters for additional initialization + **/ + event Initialized( + address indexed underlyingAsset, + address indexed pool, + address treasury, + address incentivesController, + uint8 aTokenDecimals, + string aTokenName, + string aTokenSymbol, + bytes params + ); + + /** + * @dev Initializes the aToken + * @param pool The address of the lending pool where this aToken will be used + * @param treasury The address of the Aave treasury, receiving the fees on this aToken + * @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH) + * @param incentivesController The smart contract managing potential incentives distribution + * @param aTokenDecimals The decimals of the aToken, same as the underlying asset's + * @param aTokenName The name of the aToken + * @param aTokenSymbol The symbol of the aToken + */ + function initialize( + ILendingPool pool, + address treasury, + address underlyingAsset, + IAaveIncentivesController incentivesController, + uint8 aTokenDecimals, + string calldata aTokenName, + string calldata aTokenSymbol, + bytes calldata params + ) external; +} + +interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken { + /** + * @dev Emitted after the mint action + * @param from The address performing the mint + * @param value The amount being + * @param index The new liquidity index of the reserve + **/ + event Mint(address indexed from, uint256 value, uint256 index); + + /** + * @dev Mints `amount` aTokens to `user` + * @param user The address receiving the minted tokens + * @param amount The amount of tokens getting minted + * @param index The new liquidity index of the reserve + * @return `true` if the the previous balance of the user was 0 + */ + function mint( + address user, + uint256 amount, + uint256 index + ) external returns (bool); + + /** + * @dev Emitted after aTokens are burned + * @param from The owner of the aTokens, getting them burned + * @param target The address that will receive the underlying + * @param value The amount being burned + * @param index The new liquidity index of the reserve + **/ + event Burn(address indexed from, address indexed target, uint256 value, uint256 index); + + /** + * @dev Emitted during the transfer action + * @param from The user whose tokens are being transferred + * @param to The recipient + * @param value The amount being transferred + * @param index The new liquidity index of the reserve + **/ + event BalanceTransfer(address indexed from, address indexed to, uint256 value, uint256 index); + + /** + * @dev Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying` + * @param user The owner of the aTokens, getting them burned + * @param receiverOfUnderlying The address that will receive the underlying + * @param amount The amount being burned + * @param index The new liquidity index of the reserve + **/ + function burn( + address user, + address receiverOfUnderlying, + uint256 amount, + uint256 index + ) external; + + /** + * @dev Mints aTokens to the reserve treasury + * @param amount The amount of tokens getting minted + * @param index The new liquidity index of the reserve + */ + function mintToTreasury(uint256 amount, uint256 index) external; + + /** + * @dev Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken + * @param from The address getting liquidated, current owner of the aTokens + * @param to The recipient + * @param value The amount of tokens getting transferred + **/ + function transferOnLiquidation( + address from, + address to, + uint256 value + ) external; + + /** + * @dev Transfers the underlying asset to `target`. Used by the LendingPool to transfer + * assets in borrow(), withdraw() and flashLoan() + * @param user The recipient of the underlying + * @param amount The amount getting transferred + * @return The amount transferred + **/ + function transferUnderlyingTo(address user, uint256 amount) external returns (uint256); + + /** + * @dev Invoked to execute actions on the aToken side after a repayment. + * @param user The user executing the repayment + * @param amount The amount getting repaid + **/ + function handleRepayment(address user, uint256 amount) external; + + /** + * @dev Returns the address of the incentives controller contract + **/ + function getIncentivesController() external view returns (IAaveIncentivesController); +} + +/** + * @title IInitializableDebtToken + * @notice Interface for the initialize function common between debt tokens + * @author Aave + **/ +interface IInitializableDebtToken { + /** + * @dev Emitted when a debt token is initialized + * @param underlyingAsset The address of the underlying asset + * @param pool The address of the associated lending pool + * @param incentivesController The address of the incentives controller for this aToken + * @param debtTokenDecimals the decimals of the debt token + * @param debtTokenName the name of the debt token + * @param debtTokenSymbol the symbol of the debt token + * @param params A set of encoded parameters for additional initialization + **/ + event Initialized( + address indexed underlyingAsset, + address indexed pool, + address incentivesController, + uint8 debtTokenDecimals, + string debtTokenName, + string debtTokenSymbol, + bytes params + ); + + /** + * @dev Initializes the debt token. + * @param pool The address of the lending pool where this aToken will be used + * @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH) + * @param incentivesController The smart contract managing potential incentives distribution + * @param debtTokenDecimals The decimals of the debtToken, same as the underlying asset's + * @param debtTokenName The name of the token + * @param debtTokenSymbol The symbol of the token + */ + function initialize( + ILendingPool pool, + address underlyingAsset, + IAaveIncentivesController incentivesController, + uint8 debtTokenDecimals, + string memory debtTokenName, + string memory debtTokenSymbol, + bytes calldata params + ) external; +} + +/** + * @title IVariableDebtToken + * @author Aave + * @notice Defines the basic interface for a variable debt token. + **/ +interface IVariableDebtToken is IScaledBalanceToken, IInitializableDebtToken { + /** + * @dev Emitted after the mint action + * @param from The address performing the mint + * @param onBehalfOf The address of the user on which behalf minting has been performed + * @param value The amount to be minted + * @param index The last index of the reserve + **/ + event Mint(address indexed from, address indexed onBehalfOf, uint256 value, uint256 index); + + /** + * @dev Mints debt token to the `onBehalfOf` address + * @param user The address receiving the borrowed underlying, being the delegatee in case + * of credit delegate, or same as `onBehalfOf` otherwise + * @param onBehalfOf The address receiving the debt tokens + * @param amount The amount of debt being minted + * @param index The variable debt index of the reserve + * @return `true` if the the previous balance of the user is 0 + **/ + function mint( + address user, + address onBehalfOf, + uint256 amount, + uint256 index + ) external returns (bool); + + /** + * @dev Emitted when variable debt is burnt + * @param user The user which debt has been burned + * @param amount The amount of debt being burned + * @param index The index of the user + **/ + event Burn(address indexed user, uint256 amount, uint256 index); + + /** + * @dev Burns user variable debt + * @param user The user which debt is burnt + * @param index The variable debt index of the reserve + **/ + function burn( + address user, + uint256 amount, + uint256 index + ) external; + + /** + * @dev Returns the address of the incentives controller contract + **/ + function getIncentivesController() external view returns (IAaveIncentivesController); +} + +/** + * @title IFlashLoanReceiver interface + * @notice Interface for the Aave fee IFlashLoanReceiver. + * @author Aave + * @dev implement this interface to develop a flashloan-compatible flashLoanReceiver contract + **/ +interface IFlashLoanReceiver { + function executeOperation( + address[] calldata assets, + uint256[] calldata amounts, + uint256[] calldata premiums, + address initiator, + bytes calldata params + ) external returns (bool); + + function ADDRESSES_PROVIDER() external view returns (ILendingPoolAddressesProvider); + + function LENDING_POOL() external view returns (ILendingPool); +} + +/** + * @title IPriceOracleGetter interface + * @notice Interface for the Aave price oracle. + **/ + +interface IPriceOracleGetter { + /** + * @dev returns the asset price in ETH + * @param asset the address of the asset + * @return the ETH price of the asset + **/ + function getAssetPrice(address asset) external view returns (uint256); +} + +/** + * @title IStableDebtToken + * @notice Defines the interface for the stable debt token + * @dev It does not inherit from IERC20 to save in code size + * @author Aave + **/ + +interface IStableDebtToken is IInitializableDebtToken { + /** + * @dev Emitted when new stable debt is minted + * @param user The address of the user who triggered the minting + * @param onBehalfOf The recipient of stable debt tokens + * @param amount The amount minted + * @param currentBalance The current balance of the user + * @param balanceIncrease The increase in balance since the last action of the user + * @param newRate The rate of the debt after the minting + * @param avgStableRate The new average stable rate after the minting + * @param newTotalSupply The new total supply of the stable debt token after the action + **/ + event Mint( + address indexed user, + address indexed onBehalfOf, + uint256 amount, + uint256 currentBalance, + uint256 balanceIncrease, + uint256 newRate, + uint256 avgStableRate, + uint256 newTotalSupply + ); + + /** + * @dev Emitted when new stable debt is burned + * @param user The address of the user + * @param amount The amount being burned + * @param currentBalance The current balance of the user + * @param balanceIncrease The the increase in balance since the last action of the user + * @param avgStableRate The new average stable rate after the burning + * @param newTotalSupply The new total supply of the stable debt token after the action + **/ + event Burn( + address indexed user, + uint256 amount, + uint256 currentBalance, + uint256 balanceIncrease, + uint256 avgStableRate, + uint256 newTotalSupply + ); + + /** + * @dev Mints debt token to the `onBehalfOf` address. + * - The resulting rate is the weighted average between the rate of the new debt + * and the rate of the previous debt + * @param user The address receiving the borrowed underlying, being the delegatee in case + * of credit delegate, or same as `onBehalfOf` otherwise + * @param onBehalfOf The address receiving the debt tokens + * @param amount The amount of debt tokens to mint + * @param rate The rate of the debt being minted + **/ + function mint( + address user, + address onBehalfOf, + uint256 amount, + uint256 rate + ) external returns (bool); + + /** + * @dev Burns debt of `user` + * - The resulting rate is the weighted average between the rate of the new debt + * and the rate of the previous debt + * @param user The address of the user getting his debt burned + * @param amount The amount of debt tokens getting burned + **/ + function burn(address user, uint256 amount) external; + + /** + * @dev Returns the average rate of all the stable rate loans. + * @return The average stable rate + **/ + function getAverageStableRate() external view returns (uint256); + + /** + * @dev Returns the stable rate of the user debt + * @return The stable rate of the user + **/ + function getUserStableRate(address user) external view returns (uint256); + + /** + * @dev Returns the timestamp of the last update of the user + * @return The timestamp + **/ + function getUserLastUpdated(address user) external view returns (uint40); + + /** + * @dev Returns the principal, the total supply and the average stable rate + **/ + function getSupplyData() + external + view + returns ( + uint256, + uint256, + uint256, + uint40 + ); + + /** + * @dev Returns the timestamp of the last update of the total supply + * @return The timestamp + **/ + function getTotalSupplyLastUpdated() external view returns (uint40); + + /** + * @dev Returns the total supply and the average stable rate + **/ + function getTotalSupplyAndAvgRate() external view returns (uint256, uint256); + + /** + * @dev Returns the principal debt balance of the user + * @return The debt balance of the user since the last burn/mint action + **/ + function principalBalanceOf(address user) external view returns (uint256); + + /** + * @dev Returns the address of the incentives controller contract + **/ + function getIncentivesController() external view returns (IAaveIncentivesController); +} + +/** + * @title VersionedInitializable + * + * @dev Helper contract to implement initializer functions. To use it, replace + * the constructor with a function that has the `initializer` modifier. + * WARNING: Unlike constructors, initializer functions must be manually + * invoked. This applies both to deploying an Initializable contract, as well + * as extending an Initializable contract via inheritance. + * WARNING: When used with inheritance, manual care must be taken to not invoke + * a parent initializer twice, or ensure that all initializers are idempotent, + * because this is not dealt with automatically as with constructors. + * + * @author Aave, inspired by the OpenZeppelin Initializable contract + */ +abstract contract VersionedInitializable { + /** + * @dev Indicates that the contract has been initialized. + */ + uint256 private lastInitializedRevision = 0; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private initializing; + + /** + * @dev Modifier to use in the initializer function of a contract. + */ + modifier initializer() { + uint256 revision = getRevision(); + require( + initializing || isConstructor() || revision > lastInitializedRevision, + 'Contract instance has already been initialized' + ); + + bool isTopLevelCall = !initializing; + if (isTopLevelCall) { + initializing = true; + lastInitializedRevision = revision; + } + + _; + + if (isTopLevelCall) { + initializing = false; + } + } + + /** + * @dev returns the revision number of the contract + * Needs to be defined in the inherited class as a constant. + **/ + function getRevision() internal pure virtual returns (uint256); + + /** + * @dev Returns true if and only if the function is running in the constructor + **/ + function isConstructor() private view returns (bool) { + // extcodesize checks the size of the code stored in an address, and + // address returns the current address. Since the code is still not + // deployed when running a constructor, any checks on its code size will + // yield zero, making it an effective way to detect if a contract is + // under construction or not. + uint256 cs; + //solium-disable-next-line + assembly { + cs := extcodesize(address()) + } + return cs == 0; + } + + // Reserved storage space to allow for layout changes in the future. + uint256[50] private ______gap; +} + +/** + * @title Helpers library + * @author Aave + */ +library Helpers { + /** + * @dev Fetches the user current stable and variable debt balances + * @param user The user address + * @param reserve The reserve data object + * @return The stable and variable debt balance + **/ + function getUserCurrentDebt(address user, DataTypes.ReserveData storage reserve) + internal + view + returns (uint256, uint256) + { + return ( + IERC20(reserve.stableDebtTokenAddress).balanceOf(user), + IERC20(reserve.variableDebtTokenAddress).balanceOf(user) + ); + } + + function getUserCurrentDebtMemory(address user, DataTypes.ReserveData memory reserve) + internal + view + returns (uint256, uint256) + { + return ( + IERC20(reserve.stableDebtTokenAddress).balanceOf(user), + IERC20(reserve.variableDebtTokenAddress).balanceOf(user) + ); + } +} + +library Errors { + //common errors + string public constant CALLER_NOT_POOL_ADMIN = '33'; // 'The caller must be the pool admin' + string public constant BORROW_ALLOWANCE_NOT_ENOUGH = '59'; // User borrows on behalf, but allowance are too small + + //contract specific errors + string public constant VL_INVALID_AMOUNT = '1'; // 'Amount must be greater than 0' + string public constant VL_NO_ACTIVE_RESERVE = '2'; // 'Action requires an active reserve' + string public constant VL_RESERVE_FROZEN = '3'; // 'Action cannot be performed because the reserve is frozen' + string public constant VL_CURRENT_AVAILABLE_LIQUIDITY_NOT_ENOUGH = '4'; // 'The current liquidity is not enough' + string public constant VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE = '5'; // 'User cannot withdraw more than the available balance' + string public constant VL_TRANSFER_NOT_ALLOWED = '6'; // 'Transfer cannot be allowed.' + string public constant VL_BORROWING_NOT_ENABLED = '7'; // 'Borrowing is not enabled' + string public constant VL_INVALID_INTEREST_RATE_MODE_SELECTED = '8'; // 'Invalid interest rate mode selected' + string public constant VL_COLLATERAL_BALANCE_IS_0 = '9'; // 'The collateral balance is 0' + string public constant VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = '10'; // 'Health factor is lesser than the liquidation threshold' + string public constant VL_COLLATERAL_CANNOT_COVER_NEW_BORROW = '11'; // 'There is not enough collateral to cover a new borrow' + string public constant VL_STABLE_BORROWING_NOT_ENABLED = '12'; // stable borrowing not enabled + string public constant VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY = '13'; // collateral is (mostly) the same currency that is being borrowed + string public constant VL_AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE = '14'; // 'The requested amount is greater than the max loan size in stable rate mode + string public constant VL_NO_DEBT_OF_SELECTED_TYPE = '15'; // 'for repayment of stable debt, the user needs to have stable debt, otherwise, he needs to have variable debt' + string public constant VL_NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = '16'; // 'To repay on behalf of an user an explicit amount to repay is needed' + string public constant VL_NO_STABLE_RATE_LOAN_IN_RESERVE = '17'; // 'User does not have a stable rate loan in progress on this reserve' + string public constant VL_NO_VARIABLE_RATE_LOAN_IN_RESERVE = '18'; // 'User does not have a variable rate loan in progress on this reserve' + string public constant VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0 = '19'; // 'The underlying balance needs to be greater than 0' + string public constant VL_DEPOSIT_ALREADY_IN_USE = '20'; // 'User deposit is already being used as collateral' + string public constant LP_NOT_ENOUGH_STABLE_BORROW_BALANCE = '21'; // 'User does not have any stable rate loan for this reserve' + string public constant LP_INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET = '22'; // 'Interest rate rebalance conditions were not met' + string public constant LP_LIQUIDATION_CALL_FAILED = '23'; // 'Liquidation call failed' + string public constant LP_NOT_ENOUGH_LIQUIDITY_TO_BORROW = '24'; // 'There is not enough liquidity available to borrow' + string public constant LP_REQUESTED_AMOUNT_TOO_SMALL = '25'; // 'The requested amount is too small for a FlashLoan.' + string public constant LP_INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '26'; // 'The actual balance of the protocol is inconsistent' + string public constant LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR = '27'; // 'The caller of the function is not the lending pool configurator' + string public constant LP_INCONSISTENT_FLASHLOAN_PARAMS = '28'; + string public constant CT_CALLER_MUST_BE_LENDING_POOL = '29'; // 'The caller of this function must be a lending pool' + string public constant CT_CANNOT_GIVE_ALLOWANCE_TO_HIMSELF = '30'; // 'User cannot give allowance to himself' + string public constant CT_TRANSFER_AMOUNT_NOT_GT_0 = '31'; // 'Transferred amount needs to be greater than zero' + string public constant RL_RESERVE_ALREADY_INITIALIZED = '32'; // 'Reserve has already been initialized' + string public constant LPC_RESERVE_LIQUIDITY_NOT_0 = '34'; // 'The liquidity of the reserve needs to be 0' + string public constant LPC_INVALID_ATOKEN_POOL_ADDRESS = '35'; // 'The liquidity of the reserve needs to be 0' + string public constant LPC_INVALID_STABLE_DEBT_TOKEN_POOL_ADDRESS = '36'; // 'The liquidity of the reserve needs to be 0' + string public constant LPC_INVALID_VARIABLE_DEBT_TOKEN_POOL_ADDRESS = '37'; // 'The liquidity of the reserve needs to be 0' + string public constant LPC_INVALID_STABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = '38'; // 'The liquidity of the reserve needs to be 0' + string public constant LPC_INVALID_VARIABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = '39'; // 'The liquidity of the reserve needs to be 0' + string public constant LPC_INVALID_ADDRESSES_PROVIDER_ID = '40'; // 'The liquidity of the reserve needs to be 0' + string public constant LPC_INVALID_CONFIGURATION = '75'; // 'Invalid risk parameters for the reserve' + string public constant LPC_CALLER_NOT_EMERGENCY_ADMIN = '76'; // 'The caller must be the emergency admin' + string public constant LPAPR_PROVIDER_NOT_REGISTERED = '41'; // 'Provider is not registered' + string public constant LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD = '42'; // 'Health factor is not below the threshold' + string public constant LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED = '43'; // 'The collateral chosen cannot be liquidated' + string public constant LPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = '44'; // 'User did not borrow the specified currency' + string public constant LPCM_NOT_ENOUGH_LIQUIDITY_TO_LIQUIDATE = '45'; // "There isn't enough liquidity available to liquidate" + string public constant LPCM_NO_ERRORS = '46'; // 'No errors' + string public constant LP_INVALID_FLASHLOAN_MODE = '47'; //Invalid flashloan mode selected + string public constant MATH_MULTIPLICATION_OVERFLOW = '48'; + string public constant MATH_ADDITION_OVERFLOW = '49'; + string public constant MATH_DIVISION_BY_ZERO = '50'; + string public constant RL_LIQUIDITY_INDEX_OVERFLOW = '51'; // Liquidity index overflows uint128 + string public constant RL_VARIABLE_BORROW_INDEX_OVERFLOW = '52'; // Variable borrow index overflows uint128 + string public constant RL_LIQUIDITY_RATE_OVERFLOW = '53'; // Liquidity rate overflows uint128 + string public constant RL_VARIABLE_BORROW_RATE_OVERFLOW = '54'; // Variable borrow rate overflows uint128 + string public constant RL_STABLE_BORROW_RATE_OVERFLOW = '55'; // Stable borrow rate overflows uint128 + string public constant CT_INVALID_MINT_AMOUNT = '56'; //invalid amount to mint + string public constant LP_FAILED_REPAY_WITH_COLLATERAL = '57'; + string public constant CT_INVALID_BURN_AMOUNT = '58'; //invalid amount to burn + string public constant LP_FAILED_COLLATERAL_SWAP = '60'; + string public constant LP_INVALID_EQUAL_ASSETS_TO_SWAP = '61'; + string public constant LP_REENTRANCY_NOT_ALLOWED = '62'; + string public constant LP_CALLER_MUST_BE_AN_ATOKEN = '63'; + string public constant LP_IS_PAUSED = '64'; // 'Pool is paused' + string public constant LP_NO_MORE_RESERVES_ALLOWED = '65'; + string public constant LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN = '66'; + string public constant RC_INVALID_LTV = '67'; + string public constant RC_INVALID_LIQ_THRESHOLD = '68'; + string public constant RC_INVALID_LIQ_BONUS = '69'; + string public constant RC_INVALID_DECIMALS = '70'; + string public constant RC_INVALID_RESERVE_FACTOR = '71'; + string public constant LPAPR_INVALID_ADDRESSES_PROVIDER_ID = '72'; + string public constant VL_INCONSISTENT_FLASHLOAN_PARAMS = '73'; + string public constant LP_INCONSISTENT_PARAMS_LENGTH = '74'; + string public constant UL_INVALID_INDEX = '77'; + string public constant LP_NOT_CONTRACT = '78'; + string public constant SDT_STABLE_DEBT_OVERFLOW = '79'; + string public constant SDT_BURN_EXCEEDS_BALANCE = '80'; + + enum CollateralManagerErrors { + NO_ERROR, + NO_COLLATERAL_AVAILABLE, + COLLATERAL_CANNOT_BE_LIQUIDATED, + CURRRENCY_NOT_BORROWED, + HEALTH_FACTOR_ABOVE_THRESHOLD, + NOT_ENOUGH_LIQUIDITY, + NO_ACTIVE_RESERVE, + HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD, + INVALID_EQUAL_ASSETS_TO_SWAP, + FROZEN_RESERVE + } +} + +/** + * @title WadRayMath library + * @author Aave + * @dev Provides mul and div function for wads (decimal numbers with 18 digits precision) and rays (decimals with 27 digits) + **/ + +library WadRayMath { + uint256 internal constant WAD = 1e18; + uint256 internal constant halfWAD = WAD / 2; + + uint256 internal constant RAY = 1e27; + uint256 internal constant halfRAY = RAY / 2; + + uint256 internal constant WAD_RAY_RATIO = 1e9; + + /** + * @return One ray, 1e27 + **/ + function ray() internal pure returns (uint256) { + return RAY; + } + + /** + * @return One wad, 1e18 + **/ + + function wad() internal pure returns (uint256) { + return WAD; + } + + /** + * @return Half ray, 1e27/2 + **/ + function halfRay() internal pure returns (uint256) { + return halfRAY; + } + + /** + * @return Half ray, 1e18/2 + **/ + function halfWad() internal pure returns (uint256) { + return halfWAD; + } + + /** + * @dev Multiplies two wad, rounding half up to the nearest wad + * @param a Wad + * @param b Wad + * @return The result of a*b, in wad + **/ + function wadMul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0 || b == 0) { + return 0; + } + + require(a <= (type(uint256).max - halfWAD) / b, Errors.MATH_MULTIPLICATION_OVERFLOW); + + return (a * b + halfWAD) / WAD; + } + + /** + * @dev Divides two wad, rounding half up to the nearest wad + * @param a Wad + * @param b Wad + * @return The result of a/b, in wad + **/ + function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) { + require(b != 0, Errors.MATH_DIVISION_BY_ZERO); + uint256 halfB = b / 2; + + require(a <= (type(uint256).max - halfB) / WAD, Errors.MATH_MULTIPLICATION_OVERFLOW); + + return (a * WAD + halfB) / b; + } + + /** + * @dev Multiplies two ray, rounding half up to the nearest ray + * @param a Ray + * @param b Ray + * @return The result of a*b, in ray + **/ + function rayMul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0 || b == 0) { + return 0; + } + + require(a <= (type(uint256).max - halfRAY) / b, Errors.MATH_MULTIPLICATION_OVERFLOW); + + return (a * b + halfRAY) / RAY; + } + + /** + * @dev Divides two ray, rounding half up to the nearest ray + * @param a Ray + * @param b Ray + * @return The result of a/b, in ray + **/ + function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) { + require(b != 0, Errors.MATH_DIVISION_BY_ZERO); + uint256 halfB = b / 2; + + require(a <= (type(uint256).max - halfB) / RAY, Errors.MATH_MULTIPLICATION_OVERFLOW); + + return (a * RAY + halfB) / b; + } + + /** + * @dev Casts ray down to wad + * @param a Ray + * @return a casted to wad, rounded half up to the nearest wad + **/ + function rayToWad(uint256 a) internal pure returns (uint256) { + uint256 halfRatio = WAD_RAY_RATIO / 2; + uint256 result = halfRatio + a; + require(result >= halfRatio, Errors.MATH_ADDITION_OVERFLOW); + + return result / WAD_RAY_RATIO; + } + + /** + * @dev Converts wad up to ray + * @param a Wad + * @return a converted in ray + **/ + function wadToRay(uint256 a) internal pure returns (uint256) { + uint256 result = a * WAD_RAY_RATIO; + require(result / WAD_RAY_RATIO == a, Errors.MATH_MULTIPLICATION_OVERFLOW); + return result; + } +} + +/** + * @title PercentageMath library + * @author Aave + * @notice Provides functions to perform percentage calculations + * @dev Percentages are defined by default with 2 decimals of precision (100.00). The precision is indicated by PERCENTAGE_FACTOR + * @dev Operations are rounded half up + **/ + +library PercentageMath { + uint256 constant PERCENTAGE_FACTOR = 1e4; //percentage plus two decimals + uint256 constant HALF_PERCENT = PERCENTAGE_FACTOR / 2; + + /** + * @dev Executes a percentage multiplication + * @param value The value of which the percentage needs to be calculated + * @param percentage The percentage of the value to be calculated + * @return The percentage of value + **/ + function percentMul(uint256 value, uint256 percentage) internal pure returns (uint256) { + if (value == 0 || percentage == 0) { + return 0; + } + + require( + value <= (type(uint256).max - HALF_PERCENT) / percentage, + Errors.MATH_MULTIPLICATION_OVERFLOW + ); + + return (value * percentage + HALF_PERCENT) / PERCENTAGE_FACTOR; + } + + /** + * @dev Executes a percentage division + * @param value The value of which the percentage needs to be calculated + * @param percentage The percentage of the value to be calculated + * @return The value divided the percentage + **/ + function percentDiv(uint256 value, uint256 percentage) internal pure returns (uint256) { + require(percentage != 0, Errors.MATH_DIVISION_BY_ZERO); + uint256 halfPercentage = percentage / 2; + + require( + value <= (type(uint256).max - halfPercentage) / PERCENTAGE_FACTOR, + Errors.MATH_MULTIPLICATION_OVERFLOW + ); + + return (value * PERCENTAGE_FACTOR + halfPercentage) / percentage; + } +} + +/** + * @title IReserveInterestRateStrategyInterface interface + * @dev Interface for the calculation of the interest rates + * @author Aave + */ +interface IReserveInterestRateStrategy { + function baseVariableBorrowRate() external view returns (uint256); + + function getMaxVariableBorrowRate() external view returns (uint256); + + function calculateInterestRates( + address reserve, + uint256 availableLiquidity, + uint256 totalStableDebt, + uint256 totalVariableDebt, + uint256 averageStableBorrowRate, + uint256 reserveFactor + ) + external + view + returns ( + uint256, + uint256, + uint256 + ); + + function calculateInterestRates( + address reserve, + address aToken, + uint256 liquidityAdded, + uint256 liquidityTaken, + uint256 totalStableDebt, + uint256 totalVariableDebt, + uint256 averageStableBorrowRate, + uint256 reserveFactor + ) + external + view + returns ( + uint256 liquidityRate, + uint256 stableBorrowRate, + uint256 variableBorrowRate + ); +} + +/** + * @title ReserveConfiguration library + * @author Aave + * @notice Implements the bitmap logic to handle the reserve configuration + */ +library ReserveConfiguration { + uint256 constant LTV_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000; // prettier-ignore + uint256 constant LIQUIDATION_THRESHOLD_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF; // prettier-ignore + uint256 constant LIQUIDATION_BONUS_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFF; // prettier-ignore + uint256 constant DECIMALS_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF; // prettier-ignore + uint256 constant ACTIVE_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFF; // prettier-ignore + uint256 constant FROZEN_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFF; // prettier-ignore + uint256 constant BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFF; // prettier-ignore + uint256 constant STABLE_BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFF; // prettier-ignore + uint256 constant RESERVE_FACTOR_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFF; // prettier-ignore + + /// @dev For the LTV, the start bit is 0 (up to 15), hence no bitshifting is needed + uint256 constant LIQUIDATION_THRESHOLD_START_BIT_POSITION = 16; + uint256 constant LIQUIDATION_BONUS_START_BIT_POSITION = 32; + uint256 constant RESERVE_DECIMALS_START_BIT_POSITION = 48; + uint256 constant IS_ACTIVE_START_BIT_POSITION = 56; + uint256 constant IS_FROZEN_START_BIT_POSITION = 57; + uint256 constant BORROWING_ENABLED_START_BIT_POSITION = 58; + uint256 constant STABLE_BORROWING_ENABLED_START_BIT_POSITION = 59; + uint256 constant RESERVE_FACTOR_START_BIT_POSITION = 64; + + uint256 constant MAX_VALID_LTV = 65535; + uint256 constant MAX_VALID_LIQUIDATION_THRESHOLD = 65535; + uint256 constant MAX_VALID_LIQUIDATION_BONUS = 65535; + uint256 constant MAX_VALID_DECIMALS = 255; + uint256 constant MAX_VALID_RESERVE_FACTOR = 65535; + + /** + * @dev Sets the Loan to Value of the reserve + * @param self The reserve configuration + * @param ltv the new ltv + **/ + function setLtv(DataTypes.ReserveConfigurationMap memory self, uint256 ltv) internal pure { + require(ltv <= MAX_VALID_LTV, Errors.RC_INVALID_LTV); + + self.data = (self.data & LTV_MASK) | ltv; + } + + /** + * @dev Gets the Loan to Value of the reserve + * @param self The reserve configuration + * @return The loan to value + **/ + function getLtv(DataTypes.ReserveConfigurationMap storage self) internal view returns (uint256) { + return self.data & ~LTV_MASK; + } + + /** + * @dev Sets the liquidation threshold of the reserve + * @param self The reserve configuration + * @param threshold The new liquidation threshold + **/ + function setLiquidationThreshold(DataTypes.ReserveConfigurationMap memory self, uint256 threshold) + internal + pure + { + require(threshold <= MAX_VALID_LIQUIDATION_THRESHOLD, Errors.RC_INVALID_LIQ_THRESHOLD); + + self.data = + (self.data & LIQUIDATION_THRESHOLD_MASK) | + (threshold << LIQUIDATION_THRESHOLD_START_BIT_POSITION); + } + + /** + * @dev Gets the liquidation threshold of the reserve + * @param self The reserve configuration + * @return The liquidation threshold + **/ + function getLiquidationThreshold(DataTypes.ReserveConfigurationMap storage self) + internal + view + returns (uint256) + { + return (self.data & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION; + } + + /** + * @dev Sets the liquidation bonus of the reserve + * @param self The reserve configuration + * @param bonus The new liquidation bonus + **/ + function setLiquidationBonus(DataTypes.ReserveConfigurationMap memory self, uint256 bonus) + internal + pure + { + require(bonus <= MAX_VALID_LIQUIDATION_BONUS, Errors.RC_INVALID_LIQ_BONUS); + + self.data = + (self.data & LIQUIDATION_BONUS_MASK) | + (bonus << LIQUIDATION_BONUS_START_BIT_POSITION); + } + + /** + * @dev Gets the liquidation bonus of the reserve + * @param self The reserve configuration + * @return The liquidation bonus + **/ + function getLiquidationBonus(DataTypes.ReserveConfigurationMap storage self) + internal + view + returns (uint256) + { + return (self.data & ~LIQUIDATION_BONUS_MASK) >> LIQUIDATION_BONUS_START_BIT_POSITION; + } + + /** + * @dev Sets the decimals of the underlying asset of the reserve + * @param self The reserve configuration + * @param decimals The decimals + **/ + function setDecimals(DataTypes.ReserveConfigurationMap memory self, uint256 decimals) + internal + pure + { + require(decimals <= MAX_VALID_DECIMALS, Errors.RC_INVALID_DECIMALS); + + self.data = (self.data & DECIMALS_MASK) | (decimals << RESERVE_DECIMALS_START_BIT_POSITION); + } + + /** + * @dev Gets the decimals of the underlying asset of the reserve + * @param self The reserve configuration + * @return The decimals of the asset + **/ + function getDecimals(DataTypes.ReserveConfigurationMap storage self) + internal + view + returns (uint256) + { + return (self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION; + } + + /** + * @dev Sets the active state of the reserve + * @param self The reserve configuration + * @param active The active state + **/ + function setActive(DataTypes.ReserveConfigurationMap memory self, bool active) internal pure { + self.data = + (self.data & ACTIVE_MASK) | + (uint256(active ? 1 : 0) << IS_ACTIVE_START_BIT_POSITION); + } + + /** + * @dev Gets the active state of the reserve + * @param self The reserve configuration + * @return The active state + **/ + function getActive(DataTypes.ReserveConfigurationMap storage self) internal view returns (bool) { + return (self.data & ~ACTIVE_MASK) != 0; + } + + /** + * @dev Sets the frozen state of the reserve + * @param self The reserve configuration + * @param frozen The frozen state + **/ + function setFrozen(DataTypes.ReserveConfigurationMap memory self, bool frozen) internal pure { + self.data = + (self.data & FROZEN_MASK) | + (uint256(frozen ? 1 : 0) << IS_FROZEN_START_BIT_POSITION); + } + + /** + * @dev Gets the frozen state of the reserve + * @param self The reserve configuration + * @return The frozen state + **/ + function getFrozen(DataTypes.ReserveConfigurationMap storage self) internal view returns (bool) { + return (self.data & ~FROZEN_MASK) != 0; + } + + /** + * @dev Enables or disables borrowing on the reserve + * @param self The reserve configuration + * @param enabled True if the borrowing needs to be enabled, false otherwise + **/ + function setBorrowingEnabled(DataTypes.ReserveConfigurationMap memory self, bool enabled) + internal + pure + { + self.data = + (self.data & BORROWING_MASK) | + (uint256(enabled ? 1 : 0) << BORROWING_ENABLED_START_BIT_POSITION); + } + + /** + * @dev Gets the borrowing state of the reserve + * @param self The reserve configuration + * @return The borrowing state + **/ + function getBorrowingEnabled(DataTypes.ReserveConfigurationMap storage self) + internal + view + returns (bool) + { + return (self.data & ~BORROWING_MASK) != 0; + } + + /** + * @dev Enables or disables stable rate borrowing on the reserve + * @param self The reserve configuration + * @param enabled True if the stable rate borrowing needs to be enabled, false otherwise + **/ + function setStableRateBorrowingEnabled( + DataTypes.ReserveConfigurationMap memory self, + bool enabled + ) internal pure { + self.data = + (self.data & STABLE_BORROWING_MASK) | + (uint256(enabled ? 1 : 0) << STABLE_BORROWING_ENABLED_START_BIT_POSITION); + } + + /** + * @dev Gets the stable rate borrowing state of the reserve + * @param self The reserve configuration + * @return The stable rate borrowing state + **/ + function getStableRateBorrowingEnabled(DataTypes.ReserveConfigurationMap storage self) + internal + view + returns (bool) + { + return (self.data & ~STABLE_BORROWING_MASK) != 0; + } + + /** + * @dev Sets the reserve factor of the reserve + * @param self The reserve configuration + * @param reserveFactor The reserve factor + **/ + function setReserveFactor(DataTypes.ReserveConfigurationMap memory self, uint256 reserveFactor) + internal + pure + { + require(reserveFactor <= MAX_VALID_RESERVE_FACTOR, Errors.RC_INVALID_RESERVE_FACTOR); + + self.data = + (self.data & RESERVE_FACTOR_MASK) | + (reserveFactor << RESERVE_FACTOR_START_BIT_POSITION); + } + + /** + * @dev Gets the reserve factor of the reserve + * @param self The reserve configuration + * @return The reserve factor + **/ + function getReserveFactor(DataTypes.ReserveConfigurationMap storage self) + internal + view + returns (uint256) + { + return (self.data & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION; + } + + /** + * @dev Gets the configuration flags of the reserve + * @param self The reserve configuration + * @return The state flags representing active, frozen, borrowing enabled, stableRateBorrowing enabled + **/ + function getFlags(DataTypes.ReserveConfigurationMap storage self) + internal + view + returns ( + bool, + bool, + bool, + bool + ) + { + uint256 dataLocal = self.data; + + return ( + (dataLocal & ~ACTIVE_MASK) != 0, + (dataLocal & ~FROZEN_MASK) != 0, + (dataLocal & ~BORROWING_MASK) != 0, + (dataLocal & ~STABLE_BORROWING_MASK) != 0 + ); + } + + /** + * @dev Gets the configuration paramters of the reserve + * @param self The reserve configuration + * @return The state params representing ltv, liquidation threshold, liquidation bonus, the reserve decimals + **/ + function getParams(DataTypes.ReserveConfigurationMap storage self) + internal + view + returns ( + uint256, + uint256, + uint256, + uint256, + uint256 + ) + { + uint256 dataLocal = self.data; + + return ( + dataLocal & ~LTV_MASK, + (dataLocal & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION, + (dataLocal & ~LIQUIDATION_BONUS_MASK) >> LIQUIDATION_BONUS_START_BIT_POSITION, + (dataLocal & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION, + (dataLocal & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION + ); + } + + /** + * @dev Gets the configuration paramters of the reserve from a memory object + * @param self The reserve configuration + * @return The state params representing ltv, liquidation threshold, liquidation bonus, the reserve decimals + **/ + function getParamsMemory(DataTypes.ReserveConfigurationMap memory self) + internal + pure + returns ( + uint256, + uint256, + uint256, + uint256, + uint256 + ) + { + return ( + self.data & ~LTV_MASK, + (self.data & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION, + (self.data & ~LIQUIDATION_BONUS_MASK) >> LIQUIDATION_BONUS_START_BIT_POSITION, + (self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION, + (self.data & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION + ); + } + + /** + * @dev Gets the configuration flags of the reserve from a memory object + * @param self The reserve configuration + * @return The state flags representing active, frozen, borrowing enabled, stableRateBorrowing enabled + **/ + function getFlagsMemory(DataTypes.ReserveConfigurationMap memory self) + internal + pure + returns ( + bool, + bool, + bool, + bool + ) + { + return ( + (self.data & ~ACTIVE_MASK) != 0, + (self.data & ~FROZEN_MASK) != 0, + (self.data & ~BORROWING_MASK) != 0, + (self.data & ~STABLE_BORROWING_MASK) != 0 + ); + } +} + +library MathUtils { + using SafeMath for uint256; + using WadRayMath for uint256; + + /// @dev Ignoring leap years + uint256 internal constant SECONDS_PER_YEAR = 365 days; + + /** + * @dev Function to calculate the interest accumulated using a linear interest rate formula + * @param rate The interest rate, in ray + * @param lastUpdateTimestamp The timestamp of the last update of the interest + * @return The interest rate linearly accumulated during the timeDelta, in ray + **/ + + function calculateLinearInterest(uint256 rate, uint40 lastUpdateTimestamp) + internal + view + returns (uint256) + { + //solium-disable-next-line + uint256 timeDifference = block.timestamp.sub(uint256(lastUpdateTimestamp)); + + return (rate.mul(timeDifference) / SECONDS_PER_YEAR).add(WadRayMath.ray()); + } + + /** + * @dev Function to calculate the interest using a compounded interest rate formula + * To avoid expensive exponentiation, the calculation is performed using a binomial approximation: + * + * (1+x)^n = 1+n*x+[n/2*(n-1)]*x^2+[n/6*(n-1)*(n-2)*x^3... + * + * The approximation slightly underpays liquidity providers and undercharges borrowers, with the advantage of great gas cost reductions + * The whitepaper contains reference to the approximation and a table showing the margin of error per different time periods + * + * @param rate The interest rate, in ray + * @param lastUpdateTimestamp The timestamp of the last update of the interest + * @return The interest rate compounded during the timeDelta, in ray + **/ + function calculateCompoundedInterest( + uint256 rate, + uint40 lastUpdateTimestamp, + uint256 currentTimestamp + ) internal pure returns (uint256) { + //solium-disable-next-line + uint256 exp = currentTimestamp.sub(uint256(lastUpdateTimestamp)); + + if (exp == 0) { + return WadRayMath.ray(); + } + + uint256 expMinusOne = exp - 1; + + uint256 expMinusTwo = exp > 2 ? exp - 2 : 0; + + uint256 ratePerSecond = rate / SECONDS_PER_YEAR; + + uint256 basePowerTwo = ratePerSecond.rayMul(ratePerSecond); + uint256 basePowerThree = basePowerTwo.rayMul(ratePerSecond); + + uint256 secondTerm = exp.mul(expMinusOne).mul(basePowerTwo) / 2; + uint256 thirdTerm = exp.mul(expMinusOne).mul(expMinusTwo).mul(basePowerThree) / 6; + + return WadRayMath.ray().add(ratePerSecond.mul(exp)).add(secondTerm).add(thirdTerm); + } + + /** + * @dev Calculates the compounded interest between the timestamp of the last update and the current block timestamp + * @param rate The interest rate (in ray) + * @param lastUpdateTimestamp The timestamp from which the interest accumulation needs to be calculated + **/ + function calculateCompoundedInterest(uint256 rate, uint40 lastUpdateTimestamp) + internal + view + returns (uint256) + { + return calculateCompoundedInterest(rate, lastUpdateTimestamp, block.timestamp); + } +} + +/** + * @title ReserveLogic library + * @author Aave + * @notice Implements the logic to update the reserves state + */ +library ReserveLogic { + using SafeMath for uint256; + using WadRayMath for uint256; + using PercentageMath for uint256; + using SafeERC20 for IERC20; + + /** + * @dev Emitted when the state of a reserve is updated + * @param asset The address of the underlying asset of the reserve + * @param liquidityRate The new liquidity rate + * @param stableBorrowRate The new stable borrow rate + * @param variableBorrowRate The new variable borrow rate + * @param liquidityIndex The new liquidity index + * @param variableBorrowIndex The new variable borrow index + **/ + event ReserveDataUpdated( + address indexed asset, + uint256 liquidityRate, + uint256 stableBorrowRate, + uint256 variableBorrowRate, + uint256 liquidityIndex, + uint256 variableBorrowIndex + ); + + using ReserveLogic for DataTypes.ReserveData; + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; + + /** + * @dev Returns the ongoing normalized income for the reserve + * A value of 1e27 means there is no income. As time passes, the income is accrued + * A value of 2*1e27 means for each unit of asset one unit of income has been accrued + * @param reserve The reserve object + * @return the normalized income. expressed in ray + **/ + function getNormalizedIncome(DataTypes.ReserveData storage reserve) + internal + view + returns (uint256) + { + uint40 timestamp = reserve.lastUpdateTimestamp; + + //solium-disable-next-line + if (timestamp == uint40(block.timestamp)) { + //if the index was updated in the same block, no need to perform any calculation + return reserve.liquidityIndex; + } + + uint256 cumulated = MathUtils + .calculateLinearInterest(reserve.currentLiquidityRate, timestamp) + .rayMul(reserve.liquidityIndex); + + return cumulated; + } + + /** + * @dev Returns the ongoing normalized variable debt for the reserve + * A value of 1e27 means there is no debt. As time passes, the income is accrued + * A value of 2*1e27 means that for each unit of debt, one unit worth of interest has been accumulated + * @param reserve The reserve object + * @return The normalized variable debt. expressed in ray + **/ + function getNormalizedDebt(DataTypes.ReserveData storage reserve) + internal + view + returns (uint256) + { + uint40 timestamp = reserve.lastUpdateTimestamp; + + //solium-disable-next-line + if (timestamp == uint40(block.timestamp)) { + //if the index was updated in the same block, no need to perform any calculation + return reserve.variableBorrowIndex; + } + + uint256 cumulated = MathUtils + .calculateCompoundedInterest(reserve.currentVariableBorrowRate, timestamp) + .rayMul(reserve.variableBorrowIndex); + + return cumulated; + } + + /** + * @dev Updates the liquidity cumulative index and the variable borrow index. + * @param reserve the reserve object + **/ + function updateState(DataTypes.ReserveData storage reserve) internal { + uint256 scaledVariableDebt = IVariableDebtToken(reserve.variableDebtTokenAddress) + .scaledTotalSupply(); + uint256 previousVariableBorrowIndex = reserve.variableBorrowIndex; + uint256 previousLiquidityIndex = reserve.liquidityIndex; + uint40 lastUpdatedTimestamp = reserve.lastUpdateTimestamp; + + (uint256 newLiquidityIndex, uint256 newVariableBorrowIndex) = _updateIndexes( + reserve, + scaledVariableDebt, + previousLiquidityIndex, + previousVariableBorrowIndex, + lastUpdatedTimestamp + ); + + _mintToTreasury( + reserve, + scaledVariableDebt, + previousVariableBorrowIndex, + newLiquidityIndex, + newVariableBorrowIndex, + lastUpdatedTimestamp + ); + } + + /** + * @dev Accumulates a predefined amount of asset to the reserve as a fixed, instantaneous income. Used for example to accumulate + * the flashloan fee to the reserve, and spread it between all the depositors + * @param reserve The reserve object + * @param totalLiquidity The total liquidity available in the reserve + * @param amount The amount to accomulate + **/ + function cumulateToLiquidityIndex( + DataTypes.ReserveData storage reserve, + uint256 totalLiquidity, + uint256 amount + ) internal { + uint256 amountToLiquidityRatio = amount.wadToRay().rayDiv(totalLiquidity.wadToRay()); + + uint256 result = amountToLiquidityRatio.add(WadRayMath.ray()); + + result = result.rayMul(reserve.liquidityIndex); + require(result <= type(uint128).max, Errors.RL_LIQUIDITY_INDEX_OVERFLOW); + + reserve.liquidityIndex = uint128(result); + } + + /** + * @dev Initializes a reserve + * @param reserve The reserve object + * @param aTokenAddress The address of the overlying atoken contract + * @param interestRateStrategyAddress The address of the interest rate strategy contract + **/ + function init( + DataTypes.ReserveData storage reserve, + address aTokenAddress, + address stableDebtTokenAddress, + address variableDebtTokenAddress, + address interestRateStrategyAddress + ) external { + require(reserve.aTokenAddress == address(0), Errors.RL_RESERVE_ALREADY_INITIALIZED); + + reserve.liquidityIndex = uint128(WadRayMath.ray()); + reserve.variableBorrowIndex = uint128(WadRayMath.ray()); + reserve.aTokenAddress = aTokenAddress; + reserve.stableDebtTokenAddress = stableDebtTokenAddress; + reserve.variableDebtTokenAddress = variableDebtTokenAddress; + reserve.interestRateStrategyAddress = interestRateStrategyAddress; + } + + struct UpdateInterestRatesLocalVars { + address stableDebtTokenAddress; + uint256 availableLiquidity; + uint256 totalStableDebt; + uint256 newLiquidityRate; + uint256 newStableRate; + uint256 newVariableRate; + uint256 avgStableRate; + uint256 totalVariableDebt; + } + + /** + * @dev Updates the reserve current stable borrow rate, the current variable borrow rate and the current liquidity rate + * @param reserve The address of the reserve to be updated + * @param liquidityAdded The amount of liquidity added to the protocol (deposit or repay) in the previous action + * @param liquidityTaken The amount of liquidity taken from the protocol (redeem or borrow) + **/ + function updateInterestRates( + DataTypes.ReserveData storage reserve, + address reserveAddress, + address aTokenAddress, + uint256 liquidityAdded, + uint256 liquidityTaken + ) internal { + UpdateInterestRatesLocalVars memory vars; + + vars.stableDebtTokenAddress = reserve.stableDebtTokenAddress; + + (vars.totalStableDebt, vars.avgStableRate) = IStableDebtToken(vars.stableDebtTokenAddress) + .getTotalSupplyAndAvgRate(); + + //calculates the total variable debt locally using the scaled total supply instead + //of totalSupply(), as it's noticeably cheaper. Also, the index has been + //updated by the previous updateState() call + vars.totalVariableDebt = IVariableDebtToken(reserve.variableDebtTokenAddress) + .scaledTotalSupply() + .rayMul(reserve.variableBorrowIndex); + + ( + vars.newLiquidityRate, + vars.newStableRate, + vars.newVariableRate + ) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates( + reserveAddress, + aTokenAddress, + liquidityAdded, + liquidityTaken, + vars.totalStableDebt, + vars.totalVariableDebt, + vars.avgStableRate, + reserve.configuration.getReserveFactor() + ); + require(vars.newLiquidityRate <= type(uint128).max, Errors.RL_LIQUIDITY_RATE_OVERFLOW); + require(vars.newStableRate <= type(uint128).max, Errors.RL_STABLE_BORROW_RATE_OVERFLOW); + require(vars.newVariableRate <= type(uint128).max, Errors.RL_VARIABLE_BORROW_RATE_OVERFLOW); + + reserve.currentLiquidityRate = uint128(vars.newLiquidityRate); + reserve.currentStableBorrowRate = uint128(vars.newStableRate); + reserve.currentVariableBorrowRate = uint128(vars.newVariableRate); + + emit ReserveDataUpdated( + reserveAddress, + vars.newLiquidityRate, + vars.newStableRate, + vars.newVariableRate, + reserve.liquidityIndex, + reserve.variableBorrowIndex + ); + } + + struct MintToTreasuryLocalVars { + uint256 currentStableDebt; + uint256 principalStableDebt; + uint256 previousStableDebt; + uint256 currentVariableDebt; + uint256 previousVariableDebt; + uint256 avgStableRate; + uint256 cumulatedStableInterest; + uint256 totalDebtAccrued; + uint256 amountToMint; + uint256 reserveFactor; + uint40 stableSupplyUpdatedTimestamp; + } + + /** + * @dev Mints part of the repaid interest to the reserve treasury as a function of the reserveFactor for the + * specific asset. + * @param reserve The reserve reserve to be updated + * @param scaledVariableDebt The current scaled total variable debt + * @param previousVariableBorrowIndex The variable borrow index before the last accumulation of the interest + * @param newLiquidityIndex The new liquidity index + * @param newVariableBorrowIndex The variable borrow index after the last accumulation of the interest + **/ + function _mintToTreasury( + DataTypes.ReserveData storage reserve, + uint256 scaledVariableDebt, + uint256 previousVariableBorrowIndex, + uint256 newLiquidityIndex, + uint256 newVariableBorrowIndex, + uint40 timestamp + ) internal { + MintToTreasuryLocalVars memory vars; + + vars.reserveFactor = reserve.configuration.getReserveFactor(); + + if (vars.reserveFactor == 0) { + return; + } + + //fetching the principal, total stable debt and the avg stable rate + ( + vars.principalStableDebt, + vars.currentStableDebt, + vars.avgStableRate, + vars.stableSupplyUpdatedTimestamp + ) = IStableDebtToken(reserve.stableDebtTokenAddress).getSupplyData(); + + //calculate the last principal variable debt + vars.previousVariableDebt = scaledVariableDebt.rayMul(previousVariableBorrowIndex); + + //calculate the new total supply after accumulation of the index + vars.currentVariableDebt = scaledVariableDebt.rayMul(newVariableBorrowIndex); + + //calculate the stable debt until the last timestamp update + vars.cumulatedStableInterest = MathUtils.calculateCompoundedInterest( + vars.avgStableRate, + vars.stableSupplyUpdatedTimestamp, + timestamp + ); + + vars.previousStableDebt = vars.principalStableDebt.rayMul(vars.cumulatedStableInterest); + + //debt accrued is the sum of the current debt minus the sum of the debt at the last update + vars.totalDebtAccrued = vars + .currentVariableDebt + .add(vars.currentStableDebt) + .sub(vars.previousVariableDebt) + .sub(vars.previousStableDebt); + + vars.amountToMint = vars.totalDebtAccrued.percentMul(vars.reserveFactor); + + if (vars.amountToMint != 0) { + IAToken(reserve.aTokenAddress).mintToTreasury(vars.amountToMint, newLiquidityIndex); + } + } + + /** + * @dev Updates the reserve indexes and the timestamp of the update + * @param reserve The reserve reserve to be updated + * @param scaledVariableDebt The scaled variable debt + * @param liquidityIndex The last stored liquidity index + * @param variableBorrowIndex The last stored variable borrow index + **/ + function _updateIndexes( + DataTypes.ReserveData storage reserve, + uint256 scaledVariableDebt, + uint256 liquidityIndex, + uint256 variableBorrowIndex, + uint40 timestamp + ) internal returns (uint256, uint256) { + uint256 currentLiquidityRate = reserve.currentLiquidityRate; + + uint256 newLiquidityIndex = liquidityIndex; + uint256 newVariableBorrowIndex = variableBorrowIndex; + + //only cumulating if there is any income being produced + if (currentLiquidityRate > 0) { + uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest( + currentLiquidityRate, + timestamp + ); + newLiquidityIndex = cumulatedLiquidityInterest.rayMul(liquidityIndex); + require(newLiquidityIndex <= type(uint128).max, Errors.RL_LIQUIDITY_INDEX_OVERFLOW); + + reserve.liquidityIndex = uint128(newLiquidityIndex); + + //as the liquidity rate might come only from stable rate loans, we need to ensure + //that there is actual variable debt before accumulating + if (scaledVariableDebt != 0) { + uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest( + reserve.currentVariableBorrowRate, + timestamp + ); + newVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(variableBorrowIndex); + require( + newVariableBorrowIndex <= type(uint128).max, + Errors.RL_VARIABLE_BORROW_INDEX_OVERFLOW + ); + reserve.variableBorrowIndex = uint128(newVariableBorrowIndex); + } + } + + //solium-disable-next-line + reserve.lastUpdateTimestamp = uint40(block.timestamp); + return (newLiquidityIndex, newVariableBorrowIndex); + } +} + +/**LI + * @title GenericLogic library + * @author Aave + * @title Implements protocol-level logic to calculate and validate the state of a user + */ +library GenericLogic { + using ReserveLogic for DataTypes.ReserveData; + using SafeMath for uint256; + using WadRayMath for uint256; + using PercentageMath for uint256; + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; + using UserConfiguration for DataTypes.UserConfigurationMap; + + uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1 ether; + + struct balanceDecreaseAllowedLocalVars { + uint256 decimals; + uint256 liquidationThreshold; + uint256 totalCollateralInETH; + uint256 totalDebtInETH; + uint256 avgLiquidationThreshold; + uint256 amountToDecreaseInETH; + uint256 collateralBalanceAfterDecrease; + uint256 liquidationThresholdAfterDecrease; + uint256 healthFactorAfterDecrease; + bool reserveUsageAsCollateralEnabled; + } + + /** + * @dev Checks if a specific balance decrease is allowed + * (i.e. doesn't bring the user borrow position health factor under HEALTH_FACTOR_LIQUIDATION_THRESHOLD) + * @param asset The address of the underlying asset of the reserve + * @param user The address of the user + * @param amount The amount to decrease + * @param reservesData The data of all the reserves + * @param userConfig The user configuration + * @param reserves The list of all the active reserves + * @param oracle The address of the oracle contract + * @return true if the decrease of the balance is allowed + **/ + function balanceDecreaseAllowed( + address asset, + address user, + uint256 amount, + mapping(address => DataTypes.ReserveData) storage reservesData, + DataTypes.UserConfigurationMap calldata userConfig, + mapping(uint256 => address) storage reserves, + uint256 reservesCount, + address oracle + ) external view returns (bool) { + if (!userConfig.isBorrowingAny() || !userConfig.isUsingAsCollateral(reservesData[asset].id)) { + return true; + } + + balanceDecreaseAllowedLocalVars memory vars; + + (, vars.liquidationThreshold, , vars.decimals, ) = reservesData[asset] + .configuration + .getParams(); + + if (vars.liquidationThreshold == 0) { + return true; + } + + ( + vars.totalCollateralInETH, + vars.totalDebtInETH, + , + vars.avgLiquidationThreshold, + + ) = calculateUserAccountData(user, reservesData, userConfig, reserves, reservesCount, oracle); + + if (vars.totalDebtInETH == 0) { + return true; + } + + vars.amountToDecreaseInETH = IPriceOracleGetter(oracle).getAssetPrice(asset).mul(amount).div( + 10**vars.decimals + ); + + vars.collateralBalanceAfterDecrease = vars.totalCollateralInETH.sub(vars.amountToDecreaseInETH); + + //if there is a borrow, there can't be 0 collateral + if (vars.collateralBalanceAfterDecrease == 0) { + return false; + } + + vars.liquidationThresholdAfterDecrease = vars + .totalCollateralInETH + .mul(vars.avgLiquidationThreshold) + .sub(vars.amountToDecreaseInETH.mul(vars.liquidationThreshold)) + .div(vars.collateralBalanceAfterDecrease); + + uint256 healthFactorAfterDecrease = calculateHealthFactorFromBalances( + vars.collateralBalanceAfterDecrease, + vars.totalDebtInETH, + vars.liquidationThresholdAfterDecrease + ); + + return healthFactorAfterDecrease >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD; + } + + struct CalculateUserAccountDataVars { + uint256 reserveUnitPrice; + uint256 tokenUnit; + uint256 compoundedLiquidityBalance; + uint256 compoundedBorrowBalance; + uint256 decimals; + uint256 ltv; + uint256 liquidationThreshold; + uint256 i; + uint256 healthFactor; + uint256 totalCollateralInETH; + uint256 totalDebtInETH; + uint256 avgLtv; + uint256 avgLiquidationThreshold; + uint256 reservesLength; + bool healthFactorBelowThreshold; + address currentReserveAddress; + bool usageAsCollateralEnabled; + bool userUsesReserveAsCollateral; + } + + /** + * @dev Calculates the user data across the reserves. + * this includes the total liquidity/collateral/borrow balances in ETH, + * the average Loan To Value, the average Liquidation Ratio, and the Health factor. + * @param user The address of the user + * @param reservesData Data of all the reserves + * @param userConfig The configuration of the user + * @param reserves The list of the available reserves + * @param oracle The price oracle address + * @return The total collateral and total debt of the user in ETH, the avg ltv, liquidation threshold and the HF + **/ + function calculateUserAccountData( + address user, + mapping(address => DataTypes.ReserveData) storage reservesData, + DataTypes.UserConfigurationMap memory userConfig, + mapping(uint256 => address) storage reserves, + uint256 reservesCount, + address oracle + ) + internal + view + returns ( + uint256, + uint256, + uint256, + uint256, + uint256 + ) + { + CalculateUserAccountDataVars memory vars; + + if (userConfig.isEmpty()) { + return (0, 0, 0, 0, uint256(-1)); + } + for (vars.i = 0; vars.i < reservesCount; vars.i++) { + if (!userConfig.isUsingAsCollateralOrBorrowing(vars.i)) { + continue; + } + + vars.currentReserveAddress = reserves[vars.i]; + DataTypes.ReserveData storage currentReserve = reservesData[vars.currentReserveAddress]; + + (vars.ltv, vars.liquidationThreshold, , vars.decimals, ) = currentReserve + .configuration + .getParams(); + + vars.tokenUnit = 10**vars.decimals; + vars.reserveUnitPrice = IPriceOracleGetter(oracle).getAssetPrice(vars.currentReserveAddress); + + if (vars.liquidationThreshold != 0 && userConfig.isUsingAsCollateral(vars.i)) { + vars.compoundedLiquidityBalance = IERC20(currentReserve.aTokenAddress).balanceOf(user); + + uint256 liquidityBalanceETH = vars + .reserveUnitPrice + .mul(vars.compoundedLiquidityBalance) + .div(vars.tokenUnit); + + vars.totalCollateralInETH = vars.totalCollateralInETH.add(liquidityBalanceETH); + + vars.avgLtv = vars.avgLtv.add(liquidityBalanceETH.mul(vars.ltv)); + vars.avgLiquidationThreshold = vars.avgLiquidationThreshold.add( + liquidityBalanceETH.mul(vars.liquidationThreshold) + ); + } + + if (userConfig.isBorrowing(vars.i)) { + vars.compoundedBorrowBalance = IERC20(currentReserve.stableDebtTokenAddress).balanceOf( + user + ); + vars.compoundedBorrowBalance = vars.compoundedBorrowBalance.add( + IERC20(currentReserve.variableDebtTokenAddress).balanceOf(user) + ); + + vars.totalDebtInETH = vars.totalDebtInETH.add( + vars.reserveUnitPrice.mul(vars.compoundedBorrowBalance).div(vars.tokenUnit) + ); + } + } + + vars.avgLtv = vars.totalCollateralInETH > 0 ? vars.avgLtv.div(vars.totalCollateralInETH) : 0; + vars.avgLiquidationThreshold = vars.totalCollateralInETH > 0 + ? vars.avgLiquidationThreshold.div(vars.totalCollateralInETH) + : 0; + + vars.healthFactor = calculateHealthFactorFromBalances( + vars.totalCollateralInETH, + vars.totalDebtInETH, + vars.avgLiquidationThreshold + ); + return ( + vars.totalCollateralInETH, + vars.totalDebtInETH, + vars.avgLtv, + vars.avgLiquidationThreshold, + vars.healthFactor + ); + } + + /** + * @dev Calculates the health factor from the corresponding balances + * @param totalCollateralInETH The total collateral in ETH + * @param totalDebtInETH The total debt in ETH + * @param liquidationThreshold The avg liquidation threshold + * @return The health factor calculated from the balances provided + **/ + function calculateHealthFactorFromBalances( + uint256 totalCollateralInETH, + uint256 totalDebtInETH, + uint256 liquidationThreshold + ) internal pure returns (uint256) { + if (totalDebtInETH == 0) return uint256(-1); + + return (totalCollateralInETH.percentMul(liquidationThreshold)).wadDiv(totalDebtInETH); + } + + /** + * @dev Calculates the equivalent amount in ETH that an user can borrow, depending on the available collateral and the + * average Loan To Value + * @param totalCollateralInETH The total collateral in ETH + * @param totalDebtInETH The total borrow balance + * @param ltv The average loan to value + * @return the amount available to borrow in ETH for the user + **/ + + function calculateAvailableBorrowsETH( + uint256 totalCollateralInETH, + uint256 totalDebtInETH, + uint256 ltv + ) internal pure returns (uint256) { + uint256 availableBorrowsETH = totalCollateralInETH.percentMul(ltv); + + if (availableBorrowsETH < totalDebtInETH) { + return 0; + } + + availableBorrowsETH = availableBorrowsETH.sub(totalDebtInETH); + return availableBorrowsETH; + } +} + +/** + * @title ReserveLogic library + * @author Aave + * @notice Implements functions to validate the different actions of the protocol + */ +library ValidationLogic { + using ReserveLogic for DataTypes.ReserveData; + using SafeMath for uint256; + using WadRayMath for uint256; + using PercentageMath for uint256; + using SafeERC20 for IERC20; + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; + using UserConfiguration for DataTypes.UserConfigurationMap; + + uint256 public constant REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD = 4000; + uint256 public constant REBALANCE_UP_USAGE_RATIO_THRESHOLD = 0.95 * 1e27; //usage ratio of 95% + + /** + * @dev Validates a deposit action + * @param reserve The reserve object on which the user is depositing + * @param amount The amount to be deposited + */ + function validateDeposit(DataTypes.ReserveData storage reserve, uint256 amount) external view { + (bool isActive, bool isFrozen, , ) = reserve.configuration.getFlags(); + + require(amount != 0, Errors.VL_INVALID_AMOUNT); + require(isActive, Errors.VL_NO_ACTIVE_RESERVE); + require(!isFrozen, Errors.VL_RESERVE_FROZEN); + } + + /** + * @dev Validates a withdraw action + * @param reserveAddress The address of the reserve + * @param amount The amount to be withdrawn + * @param userBalance The balance of the user + * @param reservesData The reserves state + * @param userConfig The user configuration + * @param reserves The addresses of the reserves + * @param reservesCount The number of reserves + * @param oracle The price oracle + */ + function validateWithdraw( + address reserveAddress, + uint256 amount, + uint256 userBalance, + mapping(address => DataTypes.ReserveData) storage reservesData, + DataTypes.UserConfigurationMap storage userConfig, + mapping(uint256 => address) storage reserves, + uint256 reservesCount, + address oracle + ) external view { + require(amount != 0, Errors.VL_INVALID_AMOUNT); + require(amount <= userBalance, Errors.VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE); + + (bool isActive, , , ) = reservesData[reserveAddress].configuration.getFlags(); + require(isActive, Errors.VL_NO_ACTIVE_RESERVE); + + require( + GenericLogic.balanceDecreaseAllowed( + reserveAddress, + msg.sender, + amount, + reservesData, + userConfig, + reserves, + reservesCount, + oracle + ), + Errors.VL_TRANSFER_NOT_ALLOWED + ); + } + + struct ValidateBorrowLocalVars { + uint256 currentLtv; + uint256 currentLiquidationThreshold; + uint256 amountOfCollateralNeededETH; + uint256 userCollateralBalanceETH; + uint256 userBorrowBalanceETH; + uint256 availableLiquidity; + uint256 healthFactor; + bool isActive; + bool isFrozen; + bool borrowingEnabled; + bool stableRateBorrowingEnabled; + } + + /** + * @dev Validates a borrow action + * @param asset The address of the asset to borrow + * @param reserve The reserve state from which the user is borrowing + * @param userAddress The address of the user + * @param amount The amount to be borrowed + * @param amountInETH The amount to be borrowed, in ETH + * @param interestRateMode The interest rate mode at which the user is borrowing + * @param maxStableLoanPercent The max amount of the liquidity that can be borrowed at stable rate, in percentage + * @param reservesData The state of all the reserves + * @param userConfig The state of the user for the specific reserve + * @param reserves The addresses of all the active reserves + * @param oracle The price oracle + */ + + function validateBorrow( + address asset, + DataTypes.ReserveData storage reserve, + address userAddress, + uint256 amount, + uint256 amountInETH, + uint256 interestRateMode, + uint256 maxStableLoanPercent, + mapping(address => DataTypes.ReserveData) storage reservesData, + DataTypes.UserConfigurationMap storage userConfig, + mapping(uint256 => address) storage reserves, + uint256 reservesCount, + address oracle + ) external view { + ValidateBorrowLocalVars memory vars; + + (vars.isActive, vars.isFrozen, vars.borrowingEnabled, vars.stableRateBorrowingEnabled) = reserve + .configuration + .getFlags(); + + require(vars.isActive, Errors.VL_NO_ACTIVE_RESERVE); + require(!vars.isFrozen, Errors.VL_RESERVE_FROZEN); + require(amount != 0, Errors.VL_INVALID_AMOUNT); + + require(vars.borrowingEnabled, Errors.VL_BORROWING_NOT_ENABLED); + + //validate interest rate mode + require( + uint256(DataTypes.InterestRateMode.VARIABLE) == interestRateMode || + uint256(DataTypes.InterestRateMode.STABLE) == interestRateMode, + Errors.VL_INVALID_INTEREST_RATE_MODE_SELECTED + ); + + ( + vars.userCollateralBalanceETH, + vars.userBorrowBalanceETH, + vars.currentLtv, + vars.currentLiquidationThreshold, + vars.healthFactor + ) = GenericLogic.calculateUserAccountData( + userAddress, + reservesData, + userConfig, + reserves, + reservesCount, + oracle + ); + + require(vars.userCollateralBalanceETH > 0, Errors.VL_COLLATERAL_BALANCE_IS_0); + + require( + vars.healthFactor > GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, + Errors.VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD + ); + + //add the current already borrowed amount to the amount requested to calculate the total collateral needed. + vars.amountOfCollateralNeededETH = vars.userBorrowBalanceETH.add(amountInETH).percentDiv( + vars.currentLtv + ); //LTV is calculated in percentage + + require( + vars.amountOfCollateralNeededETH <= vars.userCollateralBalanceETH, + Errors.VL_COLLATERAL_CANNOT_COVER_NEW_BORROW + ); + + /** + * Following conditions need to be met if the user is borrowing at a stable rate: + * 1. Reserve must be enabled for stable rate borrowing + * 2. Users cannot borrow from the reserve if their collateral is (mostly) the same currency + * they are borrowing, to prevent abuses. + * 3. Users will be able to borrow only a portion of the total available liquidity + **/ + + if (interestRateMode == uint256(DataTypes.InterestRateMode.STABLE)) { + //check if the borrow mode is stable and if stable rate borrowing is enabled on this reserve + + require(vars.stableRateBorrowingEnabled, Errors.VL_STABLE_BORROWING_NOT_ENABLED); + + require( + !userConfig.isUsingAsCollateral(reserve.id) || + reserve.configuration.getLtv() == 0 || + amount > IERC20(reserve.aTokenAddress).balanceOf(userAddress), + Errors.VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY + ); + + vars.availableLiquidity = IERC20(asset).balanceOf(reserve.aTokenAddress); + + //calculate the max available loan size in stable rate mode as a percentage of the + //available liquidity + uint256 maxLoanSizeStable = vars.availableLiquidity.percentMul(maxStableLoanPercent); + + require(amount <= maxLoanSizeStable, Errors.VL_AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE); + } + } + + /** + * @dev Validates a repay action + * @param reserve The reserve state from which the user is repaying + * @param amountSent The amount sent for the repayment. Can be an actual value or uint(-1) + * @param onBehalfOf The address of the user msg.sender is repaying for + * @param stableDebt The borrow balance of the user + * @param variableDebt The borrow balance of the user + */ + function validateRepay( + DataTypes.ReserveData storage reserve, + uint256 amountSent, + DataTypes.InterestRateMode rateMode, + address onBehalfOf, + uint256 stableDebt, + uint256 variableDebt + ) external view { + bool isActive = reserve.configuration.getActive(); + + require(isActive, Errors.VL_NO_ACTIVE_RESERVE); + + require(amountSent > 0, Errors.VL_INVALID_AMOUNT); + + require( + (stableDebt > 0 && + DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.STABLE) || + (variableDebt > 0 && + DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.VARIABLE), + Errors.VL_NO_DEBT_OF_SELECTED_TYPE + ); + + require( + amountSent != uint256(-1) || msg.sender == onBehalfOf, + Errors.VL_NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF + ); + } + + /** + * @dev Validates a swap of borrow rate mode. + * @param reserve The reserve state on which the user is swapping the rate + * @param userConfig The user reserves configuration + * @param stableDebt The stable debt of the user + * @param variableDebt The variable debt of the user + * @param currentRateMode The rate mode of the borrow + */ + function validateSwapRateMode( + DataTypes.ReserveData storage reserve, + DataTypes.UserConfigurationMap storage userConfig, + uint256 stableDebt, + uint256 variableDebt, + DataTypes.InterestRateMode currentRateMode + ) external view { + (bool isActive, bool isFrozen, , bool stableRateEnabled) = reserve.configuration.getFlags(); + + require(isActive, Errors.VL_NO_ACTIVE_RESERVE); + require(!isFrozen, Errors.VL_RESERVE_FROZEN); + + if (currentRateMode == DataTypes.InterestRateMode.STABLE) { + require(stableDebt > 0, Errors.VL_NO_STABLE_RATE_LOAN_IN_RESERVE); + } else if (currentRateMode == DataTypes.InterestRateMode.VARIABLE) { + require(variableDebt > 0, Errors.VL_NO_VARIABLE_RATE_LOAN_IN_RESERVE); + /** + * user wants to swap to stable, before swapping we need to ensure that + * 1. stable borrow rate is enabled on the reserve + * 2. user is not trying to abuse the reserve by depositing + * more collateral than he is borrowing, artificially lowering + * the interest rate, borrowing at variable, and switching to stable + **/ + require(stableRateEnabled, Errors.VL_STABLE_BORROWING_NOT_ENABLED); + + require( + !userConfig.isUsingAsCollateral(reserve.id) || + reserve.configuration.getLtv() == 0 || + stableDebt.add(variableDebt) > IERC20(reserve.aTokenAddress).balanceOf(msg.sender), + Errors.VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY + ); + } else { + revert(Errors.VL_INVALID_INTEREST_RATE_MODE_SELECTED); + } + } + + /** + * @dev Validates a stable borrow rate rebalance action + * @param reserve The reserve state on which the user is getting rebalanced + * @param reserveAddress The address of the reserve + * @param stableDebtToken The stable debt token instance + * @param variableDebtToken The variable debt token instance + * @param aTokenAddress The address of the aToken contract + */ + function validateRebalanceStableBorrowRate( + DataTypes.ReserveData storage reserve, + address reserveAddress, + IERC20 stableDebtToken, + IERC20 variableDebtToken, + address aTokenAddress + ) external view { + (bool isActive, , , ) = reserve.configuration.getFlags(); + + require(isActive, Errors.VL_NO_ACTIVE_RESERVE); + + //if the usage ratio is below 95%, no rebalances are needed + uint256 totalDebt = stableDebtToken + .totalSupply() + .add(variableDebtToken.totalSupply()) + .wadToRay(); + uint256 availableLiquidity = IERC20(reserveAddress).balanceOf(aTokenAddress).wadToRay(); + uint256 usageRatio = totalDebt == 0 ? 0 : totalDebt.rayDiv(availableLiquidity.add(totalDebt)); + + //if the liquidity rate is below REBALANCE_UP_THRESHOLD of the max variable APR at 95% usage, + //then we allow rebalancing of the stable rate positions. + + uint256 currentLiquidityRate = reserve.currentLiquidityRate; + uint256 maxVariableBorrowRate = IReserveInterestRateStrategy( + reserve.interestRateStrategyAddress + ).getMaxVariableBorrowRate(); + + require( + usageRatio >= REBALANCE_UP_USAGE_RATIO_THRESHOLD && + currentLiquidityRate <= + maxVariableBorrowRate.percentMul(REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD), + Errors.LP_INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET + ); + } + + /** + * @dev Validates the action of setting an asset as collateral + * @param reserve The state of the reserve that the user is enabling or disabling as collateral + * @param reserveAddress The address of the reserve + * @param reservesData The data of all the reserves + * @param userConfig The state of the user for the specific reserve + * @param reserves The addresses of all the active reserves + * @param oracle The price oracle + */ + function validateSetUseReserveAsCollateral( + DataTypes.ReserveData storage reserve, + address reserveAddress, + bool useAsCollateral, + mapping(address => DataTypes.ReserveData) storage reservesData, + DataTypes.UserConfigurationMap storage userConfig, + mapping(uint256 => address) storage reserves, + uint256 reservesCount, + address oracle + ) external view { + uint256 underlyingBalance = IERC20(reserve.aTokenAddress).balanceOf(msg.sender); + + require(underlyingBalance > 0, Errors.VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0); + + require( + useAsCollateral || + GenericLogic.balanceDecreaseAllowed( + reserveAddress, + msg.sender, + underlyingBalance, + reservesData, + userConfig, + reserves, + reservesCount, + oracle + ), + Errors.VL_DEPOSIT_ALREADY_IN_USE + ); + } + + /** + * @dev Validates a flashloan action + * @param assets The assets being flashborrowed + * @param amounts The amounts for each asset being borrowed + **/ + function validateFlashloan(address[] memory assets, uint256[] memory amounts) internal pure { + require(assets.length == amounts.length, Errors.VL_INCONSISTENT_FLASHLOAN_PARAMS); + } + + /** + * @dev Validates the liquidation action + * @param collateralReserve The reserve data of the collateral + * @param principalReserve The reserve data of the principal + * @param userConfig The user configuration + * @param userHealthFactor The user's health factor + * @param userStableDebt Total stable debt balance of the user + * @param userVariableDebt Total variable debt balance of the user + **/ + function validateLiquidationCall( + DataTypes.ReserveData storage collateralReserve, + DataTypes.ReserveData storage principalReserve, + DataTypes.UserConfigurationMap storage userConfig, + uint256 userHealthFactor, + uint256 userStableDebt, + uint256 userVariableDebt + ) internal view returns (uint256, string memory) { + if ( + !collateralReserve.configuration.getActive() || !principalReserve.configuration.getActive() + ) { + return ( + uint256(Errors.CollateralManagerErrors.NO_ACTIVE_RESERVE), + Errors.VL_NO_ACTIVE_RESERVE + ); + } + + if (userHealthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD) { + return ( + uint256(Errors.CollateralManagerErrors.HEALTH_FACTOR_ABOVE_THRESHOLD), + Errors.LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD + ); + } + + bool isCollateralEnabled = collateralReserve.configuration.getLiquidationThreshold() > 0 && + userConfig.isUsingAsCollateral(collateralReserve.id); + + //if collateral isn't enabled as collateral by user, it cannot be liquidated + if (!isCollateralEnabled) { + return ( + uint256(Errors.CollateralManagerErrors.COLLATERAL_CANNOT_BE_LIQUIDATED), + Errors.LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED + ); + } + + if (userStableDebt == 0 && userVariableDebt == 0) { + return ( + uint256(Errors.CollateralManagerErrors.CURRRENCY_NOT_BORROWED), + Errors.LPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER + ); + } + + return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.LPCM_NO_ERRORS); + } + + /** + * @dev Validates an aToken transfer + * @param from The user from which the aTokens are being transferred + * @param reservesData The state of all the reserves + * @param userConfig The state of the user for the specific reserve + * @param reserves The addresses of all the active reserves + * @param oracle The price oracle + */ + function validateTransfer( + address from, + mapping(address => DataTypes.ReserveData) storage reservesData, + DataTypes.UserConfigurationMap storage userConfig, + mapping(uint256 => address) storage reserves, + uint256 reservesCount, + address oracle + ) internal view { + (, , , , uint256 healthFactor) = GenericLogic.calculateUserAccountData( + from, + reservesData, + userConfig, + reserves, + reservesCount, + oracle + ); + + require( + healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, + Errors.VL_TRANSFER_NOT_ALLOWED + ); + } +} + +contract LendingPoolStorage { + using ReserveLogic for DataTypes.ReserveData; + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; + using UserConfiguration for DataTypes.UserConfigurationMap; + + ILendingPoolAddressesProvider internal _addressesProvider; + + mapping(address => DataTypes.ReserveData) internal _reserves; + mapping(address => DataTypes.UserConfigurationMap) internal _usersConfig; + + // the list of the available reserves, structured as a mapping for gas savings reasons + mapping(uint256 => address) internal _reservesList; + + uint256 internal _reservesCount; + + bool internal _paused; + + uint256 internal _maxStableRateBorrowSizePercent; + + uint256 internal _flashLoanPremiumTotal; + + uint256 internal _maxNumberOfReserves; +} + +/** + * @title LendingPool contract + * @dev Main point of interaction with an Aave protocol's market + * - Users can: + * # Deposit + * # Withdraw + * # Borrow + * # Repay + * # Swap their loans between variable and stable rate + * # Enable/disable their deposits as collateral rebalance stable rate borrow positions + * # Liquidate positions + * # Execute Flash Loans + * - To be covered by a proxy contract, owned by the LendingPoolAddressesProvider of the specific market + * - All admin functions are callable by the LendingPoolConfigurator contract defined also in the + * LendingPoolAddressesProvider + * @author Aave + **/ +contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage { + using SafeMath for uint256; + using WadRayMath for uint256; + using PercentageMath for uint256; + using SafeERC20 for IERC20; + + uint256 public constant LENDINGPOOL_REVISION = 0x2; + + modifier whenNotPaused() { + _whenNotPaused(); + _; + } + + modifier onlyLendingPoolConfigurator() { + _onlyLendingPoolConfigurator(); + _; + } + + function _whenNotPaused() internal view { + require(!_paused, Errors.LP_IS_PAUSED); + } + + function _onlyLendingPoolConfigurator() internal view { + require( + _addressesProvider.getLendingPoolConfigurator() == msg.sender, + Errors.LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR + ); + } + + function getRevision() internal pure override returns (uint256) { + return LENDINGPOOL_REVISION; + } + + /** + * @dev Function is invoked by the proxy contract when the LendingPool contract is added to the + * LendingPoolAddressesProvider of the market. + * - Caching the address of the LendingPoolAddressesProvider in order to reduce gas consumption + * on subsequent operations + * @param provider The address of the LendingPoolAddressesProvider + **/ + function initialize(ILendingPoolAddressesProvider provider) public initializer { + _addressesProvider = provider; + _maxStableRateBorrowSizePercent = 2500; + _flashLoanPremiumTotal = 9; + _maxNumberOfReserves = 128; + } + + /** + * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. + * - E.g. User deposits 100 USDC and gets in return 100 aUSDC + * @param asset The address of the underlying asset to deposit + * @param amount The amount to be deposited + * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user + * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens + * is a different wallet + * @param referralCode Code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + **/ + function deposit( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) external override whenNotPaused { + DataTypes.ReserveData storage reserve = _reserves[asset]; + + ValidationLogic.validateDeposit(reserve, amount); + + address aToken = reserve.aTokenAddress; + + reserve.updateState(); + reserve.updateInterestRates(asset, aToken, amount, 0); + + IERC20(asset).safeTransferFrom(msg.sender, aToken, amount); + + bool isFirstDeposit = IAToken(aToken).mint(onBehalfOf, amount, reserve.liquidityIndex); + + if (isFirstDeposit) { + _usersConfig[onBehalfOf].setUsingAsCollateral(reserve.id, true); + emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf); + } + + emit Deposit(asset, msg.sender, onBehalfOf, amount, referralCode); + } + + /** + * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned + * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC + * @param asset The address of the underlying asset to withdraw + * @param amount The underlying amount to be withdrawn + * - Send the value type(uint256).max in order to withdraw the whole aToken balance + * @param to Address that will receive the underlying, same as msg.sender if the user + * wants to receive it on his own wallet, or a different address if the beneficiary is a + * different wallet + * @return The final amount withdrawn + **/ + function withdraw( + address asset, + uint256 amount, + address to + ) external override whenNotPaused returns (uint256) { + DataTypes.ReserveData storage reserve = _reserves[asset]; + + address aToken = reserve.aTokenAddress; + + uint256 userBalance = IAToken(aToken).balanceOf(msg.sender); + + uint256 amountToWithdraw = amount; + + if (amount == type(uint256).max) { + amountToWithdraw = userBalance; + } + + ValidationLogic.validateWithdraw( + asset, + amountToWithdraw, + userBalance, + _reserves, + _usersConfig[msg.sender], + _reservesList, + _reservesCount, + _addressesProvider.getPriceOracle() + ); + + reserve.updateState(); + + reserve.updateInterestRates(asset, aToken, 0, amountToWithdraw); + + if (amountToWithdraw == userBalance) { + _usersConfig[msg.sender].setUsingAsCollateral(reserve.id, false); + emit ReserveUsedAsCollateralDisabled(asset, msg.sender); + } + + IAToken(aToken).burn(msg.sender, to, amountToWithdraw, reserve.liquidityIndex); + + emit Withdraw(asset, msg.sender, to, amountToWithdraw); + + return amountToWithdraw; + } + + /** + * @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower + * already deposited enough collateral, or he was given enough allowance by a credit delegator on the + * corresponding debt token (StableDebtToken or VariableDebtToken) + * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet + * and 100 stable/variable debt tokens, depending on the `interestRateMode` + * @param asset The address of the underlying asset to borrow + * @param amount The amount to be borrowed + * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable + * @param referralCode Code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself + * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator + * if he has been given credit delegation allowance + **/ + function borrow( + address asset, + uint256 amount, + uint256 interestRateMode, + uint16 referralCode, + address onBehalfOf + ) external override whenNotPaused { + DataTypes.ReserveData storage reserve = _reserves[asset]; + + _executeBorrow( + ExecuteBorrowParams( + asset, + msg.sender, + onBehalfOf, + amount, + interestRateMode, + reserve.aTokenAddress, + referralCode, + true + ) + ); + } + + /** + * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned + * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` + * @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable + * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the + * user calling the function if he wants to reduce/remove his own debt, or the address of any other + * other borrower whose debt should be removed + * @return The final amount repaid + **/ + function repay( + address asset, + uint256 amount, + uint256 rateMode, + address onBehalfOf + ) external override whenNotPaused returns (uint256) { + DataTypes.ReserveData storage reserve = _reserves[asset]; + + (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve); + + DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode); + + ValidationLogic.validateRepay( + reserve, + amount, + interestRateMode, + onBehalfOf, + stableDebt, + variableDebt + ); + + uint256 paybackAmount = interestRateMode == DataTypes.InterestRateMode.STABLE + ? stableDebt + : variableDebt; + + if (amount < paybackAmount) { + paybackAmount = amount; + } + + reserve.updateState(); + + if (interestRateMode == DataTypes.InterestRateMode.STABLE) { + IStableDebtToken(reserve.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount); + } else { + IVariableDebtToken(reserve.variableDebtTokenAddress).burn( + onBehalfOf, + paybackAmount, + reserve.variableBorrowIndex + ); + } + + address aToken = reserve.aTokenAddress; + reserve.updateInterestRates(asset, aToken, paybackAmount, 0); + + if (stableDebt.add(variableDebt).sub(paybackAmount) == 0) { + _usersConfig[onBehalfOf].setBorrowing(reserve.id, false); + } + + IERC20(asset).safeTransferFrom(msg.sender, aToken, paybackAmount); + + IAToken(aToken).handleRepayment(msg.sender, paybackAmount); + + emit Repay(asset, onBehalfOf, msg.sender, paybackAmount); + + return paybackAmount; + } + + /** + * @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa + * @param asset The address of the underlying asset borrowed + * @param rateMode The rate mode that the user wants to swap to + **/ + function swapBorrowRateMode(address asset, uint256 rateMode) external override whenNotPaused { + DataTypes.ReserveData storage reserve = _reserves[asset]; + + (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve); + + DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode); + + ValidationLogic.validateSwapRateMode( + reserve, + _usersConfig[msg.sender], + stableDebt, + variableDebt, + interestRateMode + ); + + reserve.updateState(); + + if (interestRateMode == DataTypes.InterestRateMode.STABLE) { + IStableDebtToken(reserve.stableDebtTokenAddress).burn(msg.sender, stableDebt); + IVariableDebtToken(reserve.variableDebtTokenAddress).mint( + msg.sender, + msg.sender, + stableDebt, + reserve.variableBorrowIndex + ); + } else { + IVariableDebtToken(reserve.variableDebtTokenAddress).burn( + msg.sender, + variableDebt, + reserve.variableBorrowIndex + ); + IStableDebtToken(reserve.stableDebtTokenAddress).mint( + msg.sender, + msg.sender, + variableDebt, + reserve.currentStableBorrowRate + ); + } + + reserve.updateInterestRates(asset, reserve.aTokenAddress, 0, 0); + + emit Swap(asset, msg.sender, rateMode); + } + + /** + * @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve. + * - Users can be rebalanced if the following conditions are satisfied: + * 1. Usage ratio is above 95% + * 2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been + * borrowed at a stable rate and depositors are not earning enough + * @param asset The address of the underlying asset borrowed + * @param user The address of the user to be rebalanced + **/ + function rebalanceStableBorrowRate(address asset, address user) external override whenNotPaused { + DataTypes.ReserveData storage reserve = _reserves[asset]; + + IERC20 stableDebtToken = IERC20(reserve.stableDebtTokenAddress); + IERC20 variableDebtToken = IERC20(reserve.variableDebtTokenAddress); + address aTokenAddress = reserve.aTokenAddress; + + uint256 stableDebt = IERC20(stableDebtToken).balanceOf(user); + + ValidationLogic.validateRebalanceStableBorrowRate( + reserve, + asset, + stableDebtToken, + variableDebtToken, + aTokenAddress + ); + + reserve.updateState(); + + IStableDebtToken(address(stableDebtToken)).burn(user, stableDebt); + IStableDebtToken(address(stableDebtToken)).mint( + user, + user, + stableDebt, + reserve.currentStableBorrowRate + ); + + reserve.updateInterestRates(asset, aTokenAddress, 0, 0); + + emit RebalanceStableBorrowRate(asset, user); + } + + /** + * @dev Allows depositors to enable/disable a specific deposited asset as collateral + * @param asset The address of the underlying asset deposited + * @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise + **/ + function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) + external + override + whenNotPaused + { + DataTypes.ReserveData storage reserve = _reserves[asset]; + + ValidationLogic.validateSetUseReserveAsCollateral( + reserve, + asset, + useAsCollateral, + _reserves, + _usersConfig[msg.sender], + _reservesList, + _reservesCount, + _addressesProvider.getPriceOracle() + ); + + _usersConfig[msg.sender].setUsingAsCollateral(reserve.id, useAsCollateral); + + if (useAsCollateral) { + emit ReserveUsedAsCollateralEnabled(asset, msg.sender); + } else { + emit ReserveUsedAsCollateralDisabled(asset, msg.sender); + } + } + + /** + * @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1 + * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives + * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk + * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation + * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation + * @param user The address of the borrower getting liquidated + * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover + * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants + * to receive the underlying collateral asset directly + **/ + function liquidationCall( + address collateralAsset, + address debtAsset, + address user, + uint256 debtToCover, + bool receiveAToken + ) external override whenNotPaused { + address collateralManager = _addressesProvider.getLendingPoolCollateralManager(); + + //solium-disable-next-line + (bool success, bytes memory result) = collateralManager.delegatecall( + abi.encodeWithSignature( + 'liquidationCall(address,address,address,uint256,bool)', + collateralAsset, + debtAsset, + user, + debtToCover, + receiveAToken + ) + ); + + require(success, Errors.LP_LIQUIDATION_CALL_FAILED); + + (uint256 returnCode, string memory returnMessage) = abi.decode(result, (uint256, string)); + + require(returnCode == 0, string(abi.encodePacked(returnMessage))); + } + + struct FlashLoanLocalVars { + IFlashLoanReceiver receiver; + address oracle; + uint256 i; + address currentAsset; + address currentATokenAddress; + uint256 currentAmount; + uint256 currentPremium; + uint256 currentAmountPlusPremium; + address debtToken; + } + + /** + * @dev Allows smartcontracts to access the liquidity of the pool within one transaction, + * as long as the amount taken plus a fee is returned. + * IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration. + * For further details please visit https://developers.aave.com + * @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface + * @param assets The addresses of the assets being flash-borrowed + * @param amounts The amounts amounts being flash-borrowed + * @param modes Types of the debt to open if the flash loan is not returned: + * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver + * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address + * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address + * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2 + * @param params Variadic packed params to pass to the receiver as extra information + * @param referralCode Code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + **/ + function flashLoan( + address receiverAddress, + address[] calldata assets, + uint256[] calldata amounts, + uint256[] calldata modes, + address onBehalfOf, + bytes calldata params, + uint16 referralCode + ) external override whenNotPaused { + FlashLoanLocalVars memory vars; + + ValidationLogic.validateFlashloan(assets, amounts); + + address[] memory aTokenAddresses = new address[](assets.length); + uint256[] memory premiums = new uint256[](assets.length); + + vars.receiver = IFlashLoanReceiver(receiverAddress); + + for (vars.i = 0; vars.i < assets.length; vars.i++) { + aTokenAddresses[vars.i] = _reserves[assets[vars.i]].aTokenAddress; + + premiums[vars.i] = amounts[vars.i].mul(_flashLoanPremiumTotal).div(10000); + + IAToken(aTokenAddresses[vars.i]).transferUnderlyingTo(receiverAddress, amounts[vars.i]); + } + + require( + vars.receiver.executeOperation(assets, amounts, premiums, msg.sender, params), + Errors.LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN + ); + + for (vars.i = 0; vars.i < assets.length; vars.i++) { + vars.currentAsset = assets[vars.i]; + vars.currentAmount = amounts[vars.i]; + vars.currentPremium = premiums[vars.i]; + vars.currentATokenAddress = aTokenAddresses[vars.i]; + vars.currentAmountPlusPremium = vars.currentAmount.add(vars.currentPremium); + + if (DataTypes.InterestRateMode(modes[vars.i]) == DataTypes.InterestRateMode.NONE) { + _reserves[vars.currentAsset].updateState(); + _reserves[vars.currentAsset].cumulateToLiquidityIndex( + IERC20(vars.currentATokenAddress).totalSupply(), + vars.currentPremium + ); + _reserves[vars.currentAsset].updateInterestRates( + vars.currentAsset, + vars.currentATokenAddress, + vars.currentAmountPlusPremium, + 0 + ); + + IERC20(vars.currentAsset).safeTransferFrom( + receiverAddress, + vars.currentATokenAddress, + vars.currentAmountPlusPremium + ); + } else { + // If the user chose to not return the funds, the system checks if there is enough collateral and + // eventually opens a debt position + _executeBorrow( + ExecuteBorrowParams( + vars.currentAsset, + msg.sender, + onBehalfOf, + vars.currentAmount, + modes[vars.i], + vars.currentATokenAddress, + referralCode, + false + ) + ); + } + emit FlashLoan( + receiverAddress, + msg.sender, + vars.currentAsset, + vars.currentAmount, + vars.currentPremium, + referralCode + ); + } + } + + /** + * @dev Returns the state and configuration of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The state of the reserve + **/ + function getReserveData(address asset) + external + view + override + returns (DataTypes.ReserveData memory) + { + return _reserves[asset]; + } + + /** + * @dev Returns the user account data across all the reserves + * @param user The address of the user + * @return totalCollateralETH the total collateral in ETH of the user + * @return totalDebtETH the total debt in ETH of the user + * @return availableBorrowsETH the borrowing power left of the user + * @return currentLiquidationThreshold the liquidation threshold of the user + * @return ltv the loan to value of the user + * @return healthFactor the current health factor of the user + **/ + function getUserAccountData(address user) + external + view + override + returns ( + uint256 totalCollateralETH, + uint256 totalDebtETH, + uint256 availableBorrowsETH, + uint256 currentLiquidationThreshold, + uint256 ltv, + uint256 healthFactor + ) + { + ( + totalCollateralETH, + totalDebtETH, + ltv, + currentLiquidationThreshold, + healthFactor + ) = GenericLogic.calculateUserAccountData( + user, + _reserves, + _usersConfig[user], + _reservesList, + _reservesCount, + _addressesProvider.getPriceOracle() + ); + + availableBorrowsETH = GenericLogic.calculateAvailableBorrowsETH( + totalCollateralETH, + totalDebtETH, + ltv + ); + } + + /** + * @dev Returns the configuration of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The configuration of the reserve + **/ + function getConfiguration(address asset) + external + view + override + returns (DataTypes.ReserveConfigurationMap memory) + { + return _reserves[asset].configuration; + } + + /** + * @dev Returns the configuration of the user across all the reserves + * @param user The user address + * @return The configuration of the user + **/ + function getUserConfiguration(address user) + external + view + override + returns (DataTypes.UserConfigurationMap memory) + { + return _usersConfig[user]; + } + + /** + * @dev Returns the normalized income per unit of asset + * @param asset The address of the underlying asset of the reserve + * @return The reserve's normalized income + */ + function getReserveNormalizedIncome(address asset) + external + view + virtual + override + returns (uint256) + { + return _reserves[asset].getNormalizedIncome(); + } + + /** + * @dev Returns the normalized variable debt per unit of asset + * @param asset The address of the underlying asset of the reserve + * @return The reserve normalized variable debt + */ + function getReserveNormalizedVariableDebt(address asset) + external + view + override + returns (uint256) + { + return _reserves[asset].getNormalizedDebt(); + } + + /** + * @dev Returns if the LendingPool is paused + */ + function paused() external view override returns (bool) { + return _paused; + } + + /** + * @dev Returns the list of the initialized reserves + **/ + function getReservesList() external view override returns (address[] memory) { + address[] memory _activeReserves = new address[](_reservesCount); + + for (uint256 i = 0; i < _reservesCount; i++) { + _activeReserves[i] = _reservesList[i]; + } + return _activeReserves; + } + + /** + * @dev Returns the cached LendingPoolAddressesProvider connected to this contract + **/ + function getAddressesProvider() external view override returns (ILendingPoolAddressesProvider) { + return _addressesProvider; + } + + /** + * @dev Returns the percentage of available liquidity that can be borrowed at once at stable rate + */ + function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() public view returns (uint256) { + return _maxStableRateBorrowSizePercent; + } + + /** + * @dev Returns the fee on flash loans + */ + function FLASHLOAN_PREMIUM_TOTAL() public view returns (uint256) { + return _flashLoanPremiumTotal; + } + + /** + * @dev Returns the maximum number of reserves supported to be listed in this LendingPool + */ + function MAX_NUMBER_RESERVES() public view returns (uint256) { + return _maxNumberOfReserves; + } + + /** + * @dev Validates and finalizes an aToken transfer + * - Only callable by the overlying aToken of the `asset` + * @param asset The address of the underlying asset of the aToken + * @param from The user from which the aTokens are transferred + * @param to The user receiving the aTokens + * @param amount The amount being transferred/withdrawn + * @param balanceFromBefore The aToken balance of the `from` user before the transfer + * @param balanceToBefore The aToken balance of the `to` user before the transfer + */ + function finalizeTransfer( + address asset, + address from, + address to, + uint256 amount, + uint256 balanceFromBefore, + uint256 balanceToBefore + ) external override whenNotPaused { + require(msg.sender == _reserves[asset].aTokenAddress, Errors.LP_CALLER_MUST_BE_AN_ATOKEN); + + ValidationLogic.validateTransfer( + from, + _reserves, + _usersConfig[from], + _reservesList, + _reservesCount, + _addressesProvider.getPriceOracle() + ); + + uint256 reserveId = _reserves[asset].id; + + if (from != to) { + if (balanceFromBefore.sub(amount) == 0) { + DataTypes.UserConfigurationMap storage fromConfig = _usersConfig[from]; + fromConfig.setUsingAsCollateral(reserveId, false); + emit ReserveUsedAsCollateralDisabled(asset, from); + } + + if (balanceToBefore == 0 && amount != 0) { + DataTypes.UserConfigurationMap storage toConfig = _usersConfig[to]; + toConfig.setUsingAsCollateral(reserveId, true); + emit ReserveUsedAsCollateralEnabled(asset, to); + } + } + } + + /** + * @dev Initializes a reserve, activating it, assigning an aToken and debt tokens and an + * interest rate strategy + * - Only callable by the LendingPoolConfigurator contract + * @param asset The address of the underlying asset of the reserve + * @param aTokenAddress The address of the aToken that will be assigned to the reserve + * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the reserve + * @param aTokenAddress The address of the VariableDebtToken that will be assigned to the reserve + * @param interestRateStrategyAddress The address of the interest rate strategy contract + **/ + function initReserve( + address asset, + address aTokenAddress, + address stableDebtAddress, + address variableDebtAddress, + address interestRateStrategyAddress + ) external override onlyLendingPoolConfigurator { + require(Address.isContract(asset), Errors.LP_NOT_CONTRACT); + _reserves[asset].init( + aTokenAddress, + stableDebtAddress, + variableDebtAddress, + interestRateStrategyAddress + ); + _addReserveToList(asset); + } + + /** + * @dev Updates the address of the interest rate strategy contract + * - Only callable by the LendingPoolConfigurator contract + * @param asset The address of the underlying asset of the reserve + * @param rateStrategyAddress The address of the interest rate strategy contract + **/ + function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress) + external + override + onlyLendingPoolConfigurator + { + _reserves[asset].interestRateStrategyAddress = rateStrategyAddress; + } + + /** + * @dev Sets the configuration bitmap of the reserve as a whole + * - Only callable by the LendingPoolConfigurator contract + * @param asset The address of the underlying asset of the reserve + * @param configuration The new configuration bitmap + **/ + function setConfiguration(address asset, uint256 configuration) + external + override + onlyLendingPoolConfigurator + { + _reserves[asset].configuration.data = configuration; + } + + /** + * @dev Set the _pause state of a reserve + * - Only callable by the LendingPoolConfigurator contract + * @param val `true` to pause the reserve, `false` to un-pause it + */ + function setPause(bool val) external override onlyLendingPoolConfigurator { + _paused = val; + if (_paused) { + emit Paused(); + } else { + emit Unpaused(); + } + } + + struct ExecuteBorrowParams { + address asset; + address user; + address onBehalfOf; + uint256 amount; + uint256 interestRateMode; + address aTokenAddress; + uint16 referralCode; + bool releaseUnderlying; + } + + function _executeBorrow(ExecuteBorrowParams memory vars) internal { + DataTypes.ReserveData storage reserve = _reserves[vars.asset]; + DataTypes.UserConfigurationMap storage userConfig = _usersConfig[vars.onBehalfOf]; + + address oracle = _addressesProvider.getPriceOracle(); + + uint256 amountInETH = IPriceOracleGetter(oracle).getAssetPrice(vars.asset).mul(vars.amount).div( + 10**reserve.configuration.getDecimals() + ); + + ValidationLogic.validateBorrow( + vars.asset, + reserve, + vars.onBehalfOf, + vars.amount, + amountInETH, + vars.interestRateMode, + _maxStableRateBorrowSizePercent, + _reserves, + userConfig, + _reservesList, + _reservesCount, + oracle + ); + + reserve.updateState(); + + uint256 currentStableRate = 0; + + bool isFirstBorrowing = false; + if (DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE) { + currentStableRate = reserve.currentStableBorrowRate; + + isFirstBorrowing = IStableDebtToken(reserve.stableDebtTokenAddress).mint( + vars.user, + vars.onBehalfOf, + vars.amount, + currentStableRate + ); + } else { + isFirstBorrowing = IVariableDebtToken(reserve.variableDebtTokenAddress).mint( + vars.user, + vars.onBehalfOf, + vars.amount, + reserve.variableBorrowIndex + ); + } + + if (isFirstBorrowing) { + userConfig.setBorrowing(reserve.id, true); + } + + reserve.updateInterestRates( + vars.asset, + vars.aTokenAddress, + 0, + vars.releaseUnderlying ? vars.amount : 0 + ); + + if (vars.releaseUnderlying) { + IAToken(vars.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount); + } + + emit Borrow( + vars.asset, + vars.user, + vars.onBehalfOf, + vars.amount, + vars.interestRateMode, + DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE + ? currentStableRate + : reserve.currentVariableBorrowRate, + vars.referralCode + ); + } + + function _addReserveToList(address asset) internal { + uint256 reservesCount = _reservesCount; + + require(reservesCount < _maxNumberOfReserves, Errors.LP_NO_MORE_RESERVES_ALLOWED); + + bool reserveAlreadyAdded = _reserves[asset].id != 0 || _reservesList[0] == asset; + + if (!reserveAlreadyAdded) { + _reserves[asset].id = uint8(reservesCount); + _reservesList[reservesCount] = asset; + + _reservesCount = reservesCount + 1; + } + } +} From 44109b54fb0b129a236b00e9687f7d4472922e37 Mon Sep 17 00:00:00 2001 From: x-moola Date: Fri, 17 Jun 2022 13:53:21 -0700 Subject: [PATCH 05/11] Update configurators --- .../lendingpool/GNT/GNTConfiguratorAlfajores.sol | 4 ++-- .../protocol/lendingpool/GNT/GNTConfiguratorCelo.sol | 8 ++++---- .../protocol/lendingpool/UBE/UBEConfiguratorCelo.sol | 9 ++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/contracts/protocol/lendingpool/GNT/GNTConfiguratorAlfajores.sol b/contracts/protocol/lendingpool/GNT/GNTConfiguratorAlfajores.sol index 67c03036..e2549b0f 100644 --- a/contracts/protocol/lendingpool/GNT/GNTConfiguratorAlfajores.sol +++ b/contracts/protocol/lendingpool/GNT/GNTConfiguratorAlfajores.sol @@ -12,7 +12,7 @@ contract GNTConfiguratorAlfajores is Ownable { LendingPoolConfigurator public lendingPoolConfigurator = LendingPoolConfigurator(lendingPoolConfiguratorAddress); - address constant assetAddress = 0xDe37f36C9c045164CE89D3cEaeC67949EfACC398; + address constant assetAddress = 0xcd8148C6f63C1559a1f95962569a915AA7907Eb7; bytes constant params = '0x10'; bool constant stableBorrowRateEnabled = true; @@ -20,7 +20,7 @@ contract GNTConfiguratorAlfajores is Ownable { address constant aTokenImpl = 0xe8B286649713447D8d5fBeBC28c731830d19B6C9; address constant stableDebtTokenImpl = 0xB6a5059A228a16Fa2827E28E52ceC96BBC63D639; address constant variableDebtTokenImpl = 0xB65b6a6a6F78E4daABF259c756567ae346699687; - address constant interestRateStrategyAddress = 0x5B41b0c78659636c6664f08F7cCb620ceA3F1206; + address constant interestRateStrategyAddress = 0x3C06Fb2f5Ab65b0e35F91073d88afE2b017D04b8; address constant treasury = 0x643C574128c7C56A1835e021Ad0EcC2592E72624; address constant incentivesController = 0x0000000000000000000000000000000000000000; string constant underlyingAssetName = 'CarbonCreditBundleToken'; diff --git a/contracts/protocol/lendingpool/GNT/GNTConfiguratorCelo.sol b/contracts/protocol/lendingpool/GNT/GNTConfiguratorCelo.sol index f8958f94..b0271bc4 100644 --- a/contracts/protocol/lendingpool/GNT/GNTConfiguratorCelo.sol +++ b/contracts/protocol/lendingpool/GNT/GNTConfiguratorCelo.sol @@ -12,7 +12,7 @@ contract GNTConfiguratorCelo is Ownable { LendingPoolConfigurator public lendingPoolConfigurator = LendingPoolConfigurator(lendingPoolConfiguratorAddress); - address constant assetAddress = 0x122013fd7dF1C6F636a5bb8f03108E876548b455; + address constant assetAddress = 0x16FDA7073b085e0231824499345c7334a68f7783; bytes constant params = '0x10'; bool constant stableBorrowRateEnabled = true; @@ -20,17 +20,17 @@ contract GNTConfiguratorCelo is Ownable { address constant aTokenImpl = 0x55bFCED2451b2154e06604D4269c9349F31141e6; address constant stableDebtTokenImpl = 0xaCdb7B3e2b0a038F1f4eF04736728E0065b689DA; address constant variableDebtTokenImpl = 0x0301Cf8F1FCD9255BD32FB7e0fE5B3494f445C2C; - address constant interestRateStrategyAddress = 0xb3072f5F0d5e8B9036aEC29F37baB70E86EA0018; + address constant interestRateStrategyAddress = 0x801443470c119F2eac65F13886D9e293CdecE2DF; address constant treasury = 0x313bc86D3D6e86ba164B2B451cB0D9CfA7943e5c; address constant incentivesController = 0x0000000000000000000000000000000000000000; - string constant underlyingAssetName = 'Wrapped Ether'; + string constant underlyingAssetName = 'CarbonCreditBundleToken'; string constant aTokenName = 'Moola interest bearing GNT'; string constant aTokenSymbol = 'mGNT'; string constant variableDebtTokenName = 'Moola variable debt bearing mGNT'; string constant variableDebtTokenSymbol = 'variableDebtmGNT'; string constant stableDebtTokenName = 'Moola stable debt bearing mGNT'; string constant stableDebtTokenSymbol = 'stableDebtmGNT'; - uint256 constant baseLTV = 5000; // TODO-- wait for params + uint256 constant baseLTV = 5000; // TODO: update after mainnet params are confirmed uint256 constant liquidationThreshold = 6500; uint256 constant liquidationBonus = 11000; uint256 constant reserveFactor = 1000; diff --git a/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol b/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol index 5c0c9966..a3f43f7a 100644 --- a/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol +++ b/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol @@ -17,11 +17,11 @@ contract UBEConfiguratorCelo is Ownable { bytes constant params = '0x10'; bool constant stableBorrowRateEnabled = true; uint8 constant underlyingAssetDecimals = 18; - address constant aTokenImpl = 0xe8B286649713447D8d5fBeBC28c731830d19B6C9; - address constant stableDebtTokenImpl = 0xB6a5059A228a16Fa2827E28E52ceC96BBC63D639; - address constant variableDebtTokenImpl = 0xB65b6a6a6F78E4daABF259c756567ae346699687; + address constant aTokenImpl = 0x55bFCED2451b2154e06604D4269c9349F31141e6; + address constant stableDebtTokenImpl = 0xaCdb7B3e2b0a038F1f4eF04736728E0065b689DA; + address constant variableDebtTokenImpl = 0x0301Cf8F1FCD9255BD32FB7e0fE5B3494f445C2C; address constant interestRateStrategyAddress = 0x801443470c119F2eac65F13886D9e293CdecE2DF; - address constant treasury = 0x643C574128c7C56A1835e021Ad0EcC2592E72624; + address constant treasury = 0x313bc86D3D6e86ba164B2B451cB0D9CfA7943e5c; address constant incentivesController = 0x0000000000000000000000000000000000000000; string constant underlyingAssetName = 'Ubeswap'; string constant aTokenName = 'Moola interest bearing UBE'; @@ -32,7 +32,6 @@ contract UBEConfiguratorCelo is Ownable { string constant stableDebtTokenSymbol = 'stableDebtmUBE'; uint256 constant baseLTV = 5000; // TODO-- wait for params uint256 constant liquidationThreshold = 6500; - uint256 constant liquidationThreshold = 6500; uint256 constant liquidationBonus = 11000; uint256 constant reserveFactor = 1000; From b148b39853a89f3e3204d21c39de7958d4c1241a Mon Sep 17 00:00:00 2001 From: x-moola Date: Fri, 17 Jun 2022 13:56:31 -0700 Subject: [PATCH 06/11] Remove linting changes --- contracts/protocol/.DS_Store | Bin 6148 -> 0 bytes contracts/protocol/lendingpool/test.sol | 4308 ----------------------- 2 files changed, 4308 deletions(-) delete mode 100644 contracts/protocol/.DS_Store delete mode 100644 contracts/protocol/lendingpool/test.sol diff --git a/contracts/protocol/.DS_Store b/contracts/protocol/.DS_Store deleted file mode 100644 index ddc54e7cb9a2f82365c60a3ef66f2944cda4fab2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKJ8HvF5S)!&7~HsY`L2)~JdAS!Um%5p2?#j^l3G>Hm7`_$LqLcSH)+DG*q!%Q zJ5Oi|trmbC-p=>H4#0-)hz}1-^ZV`#yQ_>5={(~ZBQAKsmDg?N+${z?k$Il+hxgO# zI9$g|o_^bLs*(ayKnh3!DIf)YQNVjIZL>{Olmb#f3VbWz--kwb?1fWed^#9n1R$=N z4&ypz31agEu@_E>%+M^U#H3n{7?yPATh;Z#DKY7=8a}L^Y&D@+Je}vaD2Me#MJXT! z<_fHGyYv44K>uO>pOdtc0#e{#DPZg4>3HBPRc~FqocG#Bf24cOC*6(fpfE%`CPq8v g#@q2ein6Zxn)iF*lo)j8gHF`Xfa@ZY0)MT*7fqNJ8UO$Q diff --git a/contracts/protocol/lendingpool/test.sol b/contracts/protocol/lendingpool/test.sol deleted file mode 100644 index 65816839..00000000 --- a/contracts/protocol/lendingpool/test.sol +++ /dev/null @@ -1,4308 +0,0 @@ -// SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.6.12; -pragma experimental ABIEncoderV2; - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, 'SafeMath: addition overflow'); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot overflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, 'SafeMath: subtraction overflow'); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot overflow. - */ - function sub( - uint256 a, - uint256 b, - string memory errorMessage - ) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, 'SafeMath: multiplication overflow'); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, 'SafeMath: division by zero'); - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts with custom message on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div( - uint256 a, - uint256 b, - string memory errorMessage - ) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, 'SafeMath: modulo by zero'); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod( - uint256 a, - uint256 b, - string memory errorMessage - ) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - -/** - * @dev Interface of the ERC20 standard as defined in the EIP. - */ -interface IERC20 { - /** - * @dev Returns the amount of tokens in existence. - */ - function totalSupply() external view returns (uint256); - - /** - * @dev Returns the amount of tokens owned by `account`. - */ - function balanceOf(address account) external view returns (uint256); - - /** - * @dev Moves `amount` tokens from the caller's account to `recipient`. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transfer(address recipient, uint256 amount) external returns (bool); - - /** - * @dev Returns the remaining number of tokens that `spender` will be - * allowed to spend on behalf of `owner` through {transferFrom}. This is - * zero by default. - * - * This value changes when {approve} or {transferFrom} are called. - */ - function allowance(address owner, address spender) external view returns (uint256); - - /** - * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * IMPORTANT: Beware that changing an allowance with this method brings the risk - * that someone may use both the old and the new allowance by unfortunate - * transaction ordering. One possible solution to mitigate this race - * condition is to first reduce the spender's allowance to 0 and set the - * desired value afterwards: - * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 - * - * Emits an {Approval} event. - */ - function approve(address spender, uint256 amount) external returns (bool); - - /** - * @dev Moves `amount` tokens from `sender` to `recipient` using the - * allowance mechanism. `amount` is then deducted from the caller's - * allowance. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transferFrom( - address sender, - address recipient, - uint256 amount - ) external returns (bool); - - /** - * @dev Emitted when `value` tokens are moved from one account (`from`) to - * another (`to`). - * - * Note that `value` may be zero. - */ - event Transfer(address indexed from, address indexed to, uint256 value); - - /** - * @dev Emitted when the allowance of a `spender` for an `owner` is set by - * a call to {approve}. `value` is the new allowance. - */ - event Approval(address indexed owner, address indexed spender, uint256 value); -} - -/** - * @dev Collection of functions related to the address type - */ -library Address { - /** - * @dev Returns true if `account` is a contract. - * - * [IMPORTANT] - * ==== - * It is unsafe to assume that an address for which this function returns - * false is an externally-owned account (EOA) and not a contract. - * - * Among others, `isContract` will return false for the following - * types of addresses: - * - * - an externally-owned account - * - a contract in construction - * - an address where a contract will be created - * - an address where a contract lived, but was destroyed - * ==== - */ - function isContract(address account) internal view returns (bool) { - // According to EIP-1052, 0x0 is the value returned for not-yet created accounts - // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned - // for accounts without code, i.e. `keccak256('')` - bytes32 codehash; - bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; - // solhint-disable-next-line no-inline-assembly - assembly { - codehash := extcodehash(account) - } - return (codehash != accountHash && codehash != 0x0); - } - - /** - * @dev Replacement for Solidity's `transfer`: sends `amount` wei to - * `recipient`, forwarding all available gas and reverting on errors. - * - * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost - * of certain opcodes, possibly making contracts go over the 2300 gas limit - * imposed by `transfer`, making them unable to receive funds via - * `transfer`. {sendValue} removes this limitation. - * - * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. - * - * IMPORTANT: because control is transferred to `recipient`, care must be - * taken to not create reentrancy vulnerabilities. Consider using - * {ReentrancyGuard} or the - * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. - */ - function sendValue(address payable recipient, uint256 amount) internal { - require(address(this).balance >= amount, 'Address: insufficient balance'); - - // solhint-disable-next-line avoid-low-level-calls, avoid-call-value - (bool success, ) = recipient.call{value: amount}(''); - require(success, 'Address: unable to send value, recipient may have reverted'); - } -} - -/** - * @title SafeERC20 - * @dev Wrappers around ERC20 operations that throw on failure (when the token - * contract returns false). Tokens that return no value (and instead revert or - * throw on failure) are also supported, non-reverting calls are assumed to be - * successful. - * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, - * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. - */ -library SafeERC20 { - using SafeMath for uint256; - using Address for address; - - function safeTransfer( - IERC20 token, - address to, - uint256 value - ) internal { - callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); - } - - function safeTransferFrom( - IERC20 token, - address from, - address to, - uint256 value - ) internal { - callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); - } - - function safeApprove( - IERC20 token, - address spender, - uint256 value - ) internal { - require( - (value == 0) || (token.allowance(address(this), spender) == 0), - 'SafeERC20: approve from non-zero to non-zero allowance' - ); - callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); - } - - function callOptionalReturn(IERC20 token, bytes memory data) private { - require(address(token).isContract(), 'SafeERC20: call to non-contract'); - - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory returndata) = address(token).call(data); - require(success, 'SafeERC20: low-level call failed'); - - if (returndata.length > 0) { - // Return data is optional - // solhint-disable-next-line max-line-length - require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed'); - } - } -} - -/** - * @title LendingPoolAddressesProvider contract - * @dev Main registry of addresses part of or connected to the protocol, including permissioned roles - * - Acting also as factory of proxies and admin of those, so with right to change its implementations - * - Owned by the Aave Governance - * @author Aave - **/ -interface ILendingPoolAddressesProvider { - event MarketIdSet(string newMarketId); - event LendingPoolUpdated(address indexed newAddress); - event ConfigurationAdminUpdated(address indexed newAddress); - event EmergencyAdminUpdated(address indexed newAddress); - event LendingPoolConfiguratorUpdated(address indexed newAddress); - event LendingPoolCollateralManagerUpdated(address indexed newAddress); - event PriceOracleUpdated(address indexed newAddress); - event LendingRateOracleUpdated(address indexed newAddress); - event ProxyCreated(bytes32 id, address indexed newAddress); - event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy); - - function getMarketId() external view returns (string memory); - - function setMarketId(string calldata marketId) external; - - function setAddress(bytes32 id, address newAddress) external; - - function setAddressAsProxy(bytes32 id, address impl) external; - - function getAddress(bytes32 id) external view returns (address); - - function getLendingPool() external view returns (address); - - function setLendingPoolImpl(address pool) external; - - function getLendingPoolConfigurator() external view returns (address); - - function setLendingPoolConfiguratorImpl(address configurator) external; - - function getLendingPoolCollateralManager() external view returns (address); - - function setLendingPoolCollateralManager(address manager) external; - - function getPoolAdmin() external view returns (address); - - function setPoolAdmin(address admin) external; - - function getEmergencyAdmin() external view returns (address); - - function setEmergencyAdmin(address admin) external; - - function getPriceOracle() external view returns (address); - - function setPriceOracle(address priceOracle) external; - - function getLendingRateOracle() external view returns (address); - - function setLendingRateOracle(address lendingRateOracle) external; -} - -interface IScaledBalanceToken { - /** - * @dev Returns the scaled balance of the user. The scaled balance is the sum of all the - * updated stored balance divided by the reserve's liquidity index at the moment of the update - * @param user The user whose balance is calculated - * @return The scaled balance of the user - **/ - function scaledBalanceOf(address user) external view returns (uint256); - - /** - * @dev Returns the scaled balance of the user and the scaled total supply. - * @param user The address of the user - * @return The scaled balance of the user - * @return The scaled balance and the scaled total supply - **/ - function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256); - - /** - * @dev Returns the scaled total supply of the variable debt token. Represents sum(debt/index) - * @return The scaled total supply - **/ - function scaledTotalSupply() external view returns (uint256); -} - -library DataTypes { - // refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties. - struct ReserveData { - //stores the reserve configuration - ReserveConfigurationMap configuration; - //the liquidity index. Expressed in ray - uint128 liquidityIndex; - //variable borrow index. Expressed in ray - uint128 variableBorrowIndex; - //the current supply rate. Expressed in ray - uint128 currentLiquidityRate; - //the current variable borrow rate. Expressed in ray - uint128 currentVariableBorrowRate; - //the current stable borrow rate. Expressed in ray - uint128 currentStableBorrowRate; - uint40 lastUpdateTimestamp; - //tokens addresses - address aTokenAddress; - address stableDebtTokenAddress; - address variableDebtTokenAddress; - //address of the interest rate strategy - address interestRateStrategyAddress; - //the id of the reserve. Represents the position in the list of the active reserves - uint8 id; - } - - struct ReserveConfigurationMap { - //bit 0-15: LTV - //bit 16-31: Liq. threshold - //bit 32-47: Liq. bonus - //bit 48-55: Decimals - //bit 56: Reserve is active - //bit 57: reserve is frozen - //bit 58: borrowing is enabled - //bit 59: stable rate borrowing enabled - //bit 60-63: reserved - //bit 64-79: reserve factor - uint256 data; - } - - struct UserConfigurationMap { - uint256 data; - } - - enum InterestRateMode { - NONE, - STABLE, - VARIABLE - } -} - -/** - * @title UserConfiguration library - * @author Aave - * @notice Implements the bitmap logic to handle the user configuration - */ -library UserConfiguration { - uint256 internal constant BORROWING_MASK = - 0x5555555555555555555555555555555555555555555555555555555555555555; - - /** - * @dev Sets if the user is borrowing the reserve identified by reserveIndex - * @param self The configuration object - * @param reserveIndex The index of the reserve in the bitmap - * @param borrowing True if the user is borrowing the reserve, false otherwise - **/ - function setBorrowing( - DataTypes.UserConfigurationMap storage self, - uint256 reserveIndex, - bool borrowing - ) internal { - require(reserveIndex < 128, Errors.UL_INVALID_INDEX); - self.data = - (self.data & ~(1 << (reserveIndex * 2))) | - (uint256(borrowing ? 1 : 0) << (reserveIndex * 2)); - } - - /** - * @dev Sets if the user is using as collateral the reserve identified by reserveIndex - * @param self The configuration object - * @param reserveIndex The index of the reserve in the bitmap - * @param usingAsCollateral True if the user is usin the reserve as collateral, false otherwise - **/ - function setUsingAsCollateral( - DataTypes.UserConfigurationMap storage self, - uint256 reserveIndex, - bool usingAsCollateral - ) internal { - require(reserveIndex < 128, Errors.UL_INVALID_INDEX); - self.data = - (self.data & ~(1 << (reserveIndex * 2 + 1))) | - (uint256(usingAsCollateral ? 1 : 0) << (reserveIndex * 2 + 1)); - } - - /** - * @dev Used to validate if a user has been using the reserve for borrowing or as collateral - * @param self The configuration object - * @param reserveIndex The index of the reserve in the bitmap - * @return True if the user has been using a reserve for borrowing or as collateral, false otherwise - **/ - function isUsingAsCollateralOrBorrowing( - DataTypes.UserConfigurationMap memory self, - uint256 reserveIndex - ) internal pure returns (bool) { - require(reserveIndex < 128, Errors.UL_INVALID_INDEX); - return (self.data >> (reserveIndex * 2)) & 3 != 0; - } - - /** - * @dev Used to validate if a user has been using the reserve for borrowing - * @param self The configuration object - * @param reserveIndex The index of the reserve in the bitmap - * @return True if the user has been using a reserve for borrowing, false otherwise - **/ - function isBorrowing(DataTypes.UserConfigurationMap memory self, uint256 reserveIndex) - internal - pure - returns (bool) - { - require(reserveIndex < 128, Errors.UL_INVALID_INDEX); - return (self.data >> (reserveIndex * 2)) & 1 != 0; - } - - /** - * @dev Used to validate if a user has been using the reserve as collateral - * @param self The configuration object - * @param reserveIndex The index of the reserve in the bitmap - * @return True if the user has been using a reserve as collateral, false otherwise - **/ - function isUsingAsCollateral(DataTypes.UserConfigurationMap memory self, uint256 reserveIndex) - internal - pure - returns (bool) - { - require(reserveIndex < 128, Errors.UL_INVALID_INDEX); - return (self.data >> (reserveIndex * 2 + 1)) & 1 != 0; - } - - /** - * @dev Used to validate if a user has been borrowing from any reserve - * @param self The configuration object - * @return True if the user has been borrowing any reserve, false otherwise - **/ - function isBorrowingAny(DataTypes.UserConfigurationMap memory self) internal pure returns (bool) { - return self.data & BORROWING_MASK != 0; - } - - /** - * @dev Used to validate if a user has not been using any reserve - * @param self The configuration object - * @return True if the user has been borrowing any reserve, false otherwise - **/ - function isEmpty(DataTypes.UserConfigurationMap memory self) internal pure returns (bool) { - return self.data == 0; - } -} - -interface ILendingPool { - /** - * @dev Emitted on deposit() - * @param reserve The address of the underlying asset of the reserve - * @param user The address initiating the deposit - * @param onBehalfOf The beneficiary of the deposit, receiving the aTokens - * @param amount The amount deposited - * @param referral The referral code used - **/ - event Deposit( - address indexed reserve, - address user, - address indexed onBehalfOf, - uint256 amount, - uint16 indexed referral - ); - - /** - * @dev Emitted on withdraw() - * @param reserve The address of the underlyng asset being withdrawn - * @param user The address initiating the withdrawal, owner of aTokens - * @param to Address that will receive the underlying - * @param amount The amount to be withdrawn - **/ - event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount); - - /** - * @dev Emitted on borrow() and flashLoan() when debt needs to be opened - * @param reserve The address of the underlying asset being borrowed - * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just - * initiator of the transaction on flashLoan() - * @param onBehalfOf The address that will be getting the debt - * @param amount The amount borrowed out - * @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable - * @param borrowRate The numeric rate at which the user has borrowed - * @param referral The referral code used - **/ - event Borrow( - address indexed reserve, - address user, - address indexed onBehalfOf, - uint256 amount, - uint256 borrowRateMode, - uint256 borrowRate, - uint16 indexed referral - ); - - /** - * @dev Emitted on repay() - * @param reserve The address of the underlying asset of the reserve - * @param user The beneficiary of the repayment, getting his debt reduced - * @param repayer The address of the user initiating the repay(), providing the funds - * @param amount The amount repaid - **/ - event Repay( - address indexed reserve, - address indexed user, - address indexed repayer, - uint256 amount - ); - - /** - * @dev Emitted on swapBorrowRateMode() - * @param reserve The address of the underlying asset of the reserve - * @param user The address of the user swapping his rate mode - * @param rateMode The rate mode that the user wants to swap to - **/ - event Swap(address indexed reserve, address indexed user, uint256 rateMode); - - /** - * @dev Emitted on setUserUseReserveAsCollateral() - * @param reserve The address of the underlying asset of the reserve - * @param user The address of the user enabling the usage as collateral - **/ - event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); - - /** - * @dev Emitted on setUserUseReserveAsCollateral() - * @param reserve The address of the underlying asset of the reserve - * @param user The address of the user enabling the usage as collateral - **/ - event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); - - /** - * @dev Emitted on rebalanceStableBorrowRate() - * @param reserve The address of the underlying asset of the reserve - * @param user The address of the user for which the rebalance has been executed - **/ - event RebalanceStableBorrowRate(address indexed reserve, address indexed user); - - /** - * @dev Emitted on flashLoan() - * @param target The address of the flash loan receiver contract - * @param initiator The address initiating the flash loan - * @param asset The address of the asset being flash borrowed - * @param amount The amount flash borrowed - * @param premium The fee flash borrowed - * @param referralCode The referral code used - **/ - event FlashLoan( - address indexed target, - address indexed initiator, - address indexed asset, - uint256 amount, - uint256 premium, - uint16 referralCode - ); - - /** - * @dev Emitted when the pause is triggered. - */ - event Paused(); - - /** - * @dev Emitted when the pause is lifted. - */ - event Unpaused(); - - /** - * @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via - * LendingPoolCollateral manager using a DELEGATECALL - * This allows to have the events in the generated ABI for LendingPool. - * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation - * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation - * @param user The address of the borrower getting liquidated - * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover - * @param liquidatedCollateralAmount The amount of collateral received by the liiquidator - * @param liquidator The address of the liquidator - * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants - * to receive the underlying collateral asset directly - **/ - event LiquidationCall( - address indexed collateralAsset, - address indexed debtAsset, - address indexed user, - uint256 debtToCover, - uint256 liquidatedCollateralAmount, - address liquidator, - bool receiveAToken - ); - - /** - * @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared - * in the ReserveLogic library and emitted in the updateInterestRates() function. Since the function is internal, - * the event will actually be fired by the LendingPool contract. The event is therefore replicated here so it - * gets added to the LendingPool ABI - * @param reserve The address of the underlying asset of the reserve - * @param liquidityRate The new liquidity rate - * @param stableBorrowRate The new stable borrow rate - * @param variableBorrowRate The new variable borrow rate - * @param liquidityIndex The new liquidity index - * @param variableBorrowIndex The new variable borrow index - **/ - event ReserveDataUpdated( - address indexed reserve, - uint256 liquidityRate, - uint256 stableBorrowRate, - uint256 variableBorrowRate, - uint256 liquidityIndex, - uint256 variableBorrowIndex - ); - - /** - * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. - * - E.g. User deposits 100 USDC and gets in return 100 aUSDC - * @param asset The address of the underlying asset to deposit - * @param amount The amount to be deposited - * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user - * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens - * is a different wallet - * @param referralCode Code used to register the integrator originating the operation, for potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - **/ - function deposit( - address asset, - uint256 amount, - address onBehalfOf, - uint16 referralCode - ) external; - - /** - * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned - * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC - * @param asset The address of the underlying asset to withdraw - * @param amount The underlying amount to be withdrawn - * - Send the value type(uint256).max in order to withdraw the whole aToken balance - * @param to Address that will receive the underlying, same as msg.sender if the user - * wants to receive it on his own wallet, or a different address if the beneficiary is a - * different wallet - * @return The final amount withdrawn - **/ - function withdraw( - address asset, - uint256 amount, - address to - ) external returns (uint256); - - /** - * @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower - * already deposited enough collateral, or he was given enough allowance by a credit delegator on the - * corresponding debt token (StableDebtToken or VariableDebtToken) - * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet - * and 100 stable/variable debt tokens, depending on the `interestRateMode` - * @param asset The address of the underlying asset to borrow - * @param amount The amount to be borrowed - * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable - * @param referralCode Code used to register the integrator originating the operation, for potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - * @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself - * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator - * if he has been given credit delegation allowance - **/ - function borrow( - address asset, - uint256 amount, - uint256 interestRateMode, - uint16 referralCode, - address onBehalfOf - ) external; - - /** - * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned - * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address - * @param asset The address of the borrowed underlying asset previously borrowed - * @param amount The amount to repay - * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` - * @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable - * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the - * user calling the function if he wants to reduce/remove his own debt, or the address of any other - * other borrower whose debt should be removed - * @return The final amount repaid - **/ - function repay( - address asset, - uint256 amount, - uint256 rateMode, - address onBehalfOf - ) external returns (uint256); - - /** - * @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa - * @param asset The address of the underlying asset borrowed - * @param rateMode The rate mode that the user wants to swap to - **/ - function swapBorrowRateMode(address asset, uint256 rateMode) external; - - /** - * @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve. - * - Users can be rebalanced if the following conditions are satisfied: - * 1. Usage ratio is above 95% - * 2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been - * borrowed at a stable rate and depositors are not earning enough - * @param asset The address of the underlying asset borrowed - * @param user The address of the user to be rebalanced - **/ - function rebalanceStableBorrowRate(address asset, address user) external; - - /** - * @dev Allows depositors to enable/disable a specific deposited asset as collateral - * @param asset The address of the underlying asset deposited - * @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise - **/ - function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external; - - /** - * @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1 - * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives - * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk - * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation - * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation - * @param user The address of the borrower getting liquidated - * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover - * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants - * to receive the underlying collateral asset directly - **/ - function liquidationCall( - address collateralAsset, - address debtAsset, - address user, - uint256 debtToCover, - bool receiveAToken - ) external; - - /** - * @dev Allows smartcontracts to access the liquidity of the pool within one transaction, - * as long as the amount taken plus a fee is returned. - * IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration. - * For further details please visit https://developers.aave.com - * @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface - * @param assets The addresses of the assets being flash-borrowed - * @param amounts The amounts amounts being flash-borrowed - * @param modes Types of the debt to open if the flash loan is not returned: - * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver - * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address - * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address - * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2 - * @param params Variadic packed params to pass to the receiver as extra information - * @param referralCode Code used to register the integrator originating the operation, for potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - **/ - function flashLoan( - address receiverAddress, - address[] calldata assets, - uint256[] calldata amounts, - uint256[] calldata modes, - address onBehalfOf, - bytes calldata params, - uint16 referralCode - ) external; - - /** - * @dev Returns the user account data across all the reserves - * @param user The address of the user - * @return totalCollateralETH the total collateral in ETH of the user - * @return totalDebtETH the total debt in ETH of the user - * @return availableBorrowsETH the borrowing power left of the user - * @return currentLiquidationThreshold the liquidation threshold of the user - * @return ltv the loan to value of the user - * @return healthFactor the current health factor of the user - **/ - function getUserAccountData(address user) - external - view - returns ( - uint256 totalCollateralETH, - uint256 totalDebtETH, - uint256 availableBorrowsETH, - uint256 currentLiquidationThreshold, - uint256 ltv, - uint256 healthFactor - ); - - function initReserve( - address reserve, - address aTokenAddress, - address stableDebtAddress, - address variableDebtAddress, - address interestRateStrategyAddress - ) external; - - function setReserveInterestRateStrategyAddress(address reserve, address rateStrategyAddress) - external; - - function setConfiguration(address reserve, uint256 configuration) external; - - /** - * @dev Returns the configuration of the reserve - * @param asset The address of the underlying asset of the reserve - * @return The configuration of the reserve - **/ - function getConfiguration(address asset) - external - view - returns (DataTypes.ReserveConfigurationMap memory); - - /** - * @dev Returns the configuration of the user across all the reserves - * @param user The user address - * @return The configuration of the user - **/ - function getUserConfiguration(address user) - external - view - returns (DataTypes.UserConfigurationMap memory); - - /** - * @dev Returns the normalized income normalized income of the reserve - * @param asset The address of the underlying asset of the reserve - * @return The reserve's normalized income - */ - function getReserveNormalizedIncome(address asset) external view returns (uint256); - - /** - * @dev Returns the normalized variable debt per unit of asset - * @param asset The address of the underlying asset of the reserve - * @return The reserve normalized variable debt - */ - function getReserveNormalizedVariableDebt(address asset) external view returns (uint256); - - /** - * @dev Returns the state and configuration of the reserve - * @param asset The address of the underlying asset of the reserve - * @return The state of the reserve - **/ - function getReserveData(address asset) external view returns (DataTypes.ReserveData memory); - - function finalizeTransfer( - address asset, - address from, - address to, - uint256 amount, - uint256 balanceFromAfter, - uint256 balanceToBefore - ) external; - - function getReservesList() external view returns (address[] memory); - - function getAddressesProvider() external view returns (ILendingPoolAddressesProvider); - - function setPause(bool val) external; - - function paused() external view returns (bool); -} - -interface IAaveIncentivesController { - function handleAction( - address user, - uint256 userBalance, - uint256 totalSupply - ) external; -} - -/** - * @title IInitializableAToken - * @notice Interface for the initialize function on AToken - * @author Aave - **/ -interface IInitializableAToken { - /** - * @dev Emitted when an aToken is initialized - * @param underlyingAsset The address of the underlying asset - * @param pool The address of the associated lending pool - * @param treasury The address of the treasury - * @param incentivesController The address of the incentives controller for this aToken - * @param aTokenDecimals the decimals of the underlying - * @param aTokenName the name of the aToken - * @param aTokenSymbol the symbol of the aToken - * @param params A set of encoded parameters for additional initialization - **/ - event Initialized( - address indexed underlyingAsset, - address indexed pool, - address treasury, - address incentivesController, - uint8 aTokenDecimals, - string aTokenName, - string aTokenSymbol, - bytes params - ); - - /** - * @dev Initializes the aToken - * @param pool The address of the lending pool where this aToken will be used - * @param treasury The address of the Aave treasury, receiving the fees on this aToken - * @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH) - * @param incentivesController The smart contract managing potential incentives distribution - * @param aTokenDecimals The decimals of the aToken, same as the underlying asset's - * @param aTokenName The name of the aToken - * @param aTokenSymbol The symbol of the aToken - */ - function initialize( - ILendingPool pool, - address treasury, - address underlyingAsset, - IAaveIncentivesController incentivesController, - uint8 aTokenDecimals, - string calldata aTokenName, - string calldata aTokenSymbol, - bytes calldata params - ) external; -} - -interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken { - /** - * @dev Emitted after the mint action - * @param from The address performing the mint - * @param value The amount being - * @param index The new liquidity index of the reserve - **/ - event Mint(address indexed from, uint256 value, uint256 index); - - /** - * @dev Mints `amount` aTokens to `user` - * @param user The address receiving the minted tokens - * @param amount The amount of tokens getting minted - * @param index The new liquidity index of the reserve - * @return `true` if the the previous balance of the user was 0 - */ - function mint( - address user, - uint256 amount, - uint256 index - ) external returns (bool); - - /** - * @dev Emitted after aTokens are burned - * @param from The owner of the aTokens, getting them burned - * @param target The address that will receive the underlying - * @param value The amount being burned - * @param index The new liquidity index of the reserve - **/ - event Burn(address indexed from, address indexed target, uint256 value, uint256 index); - - /** - * @dev Emitted during the transfer action - * @param from The user whose tokens are being transferred - * @param to The recipient - * @param value The amount being transferred - * @param index The new liquidity index of the reserve - **/ - event BalanceTransfer(address indexed from, address indexed to, uint256 value, uint256 index); - - /** - * @dev Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying` - * @param user The owner of the aTokens, getting them burned - * @param receiverOfUnderlying The address that will receive the underlying - * @param amount The amount being burned - * @param index The new liquidity index of the reserve - **/ - function burn( - address user, - address receiverOfUnderlying, - uint256 amount, - uint256 index - ) external; - - /** - * @dev Mints aTokens to the reserve treasury - * @param amount The amount of tokens getting minted - * @param index The new liquidity index of the reserve - */ - function mintToTreasury(uint256 amount, uint256 index) external; - - /** - * @dev Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken - * @param from The address getting liquidated, current owner of the aTokens - * @param to The recipient - * @param value The amount of tokens getting transferred - **/ - function transferOnLiquidation( - address from, - address to, - uint256 value - ) external; - - /** - * @dev Transfers the underlying asset to `target`. Used by the LendingPool to transfer - * assets in borrow(), withdraw() and flashLoan() - * @param user The recipient of the underlying - * @param amount The amount getting transferred - * @return The amount transferred - **/ - function transferUnderlyingTo(address user, uint256 amount) external returns (uint256); - - /** - * @dev Invoked to execute actions on the aToken side after a repayment. - * @param user The user executing the repayment - * @param amount The amount getting repaid - **/ - function handleRepayment(address user, uint256 amount) external; - - /** - * @dev Returns the address of the incentives controller contract - **/ - function getIncentivesController() external view returns (IAaveIncentivesController); -} - -/** - * @title IInitializableDebtToken - * @notice Interface for the initialize function common between debt tokens - * @author Aave - **/ -interface IInitializableDebtToken { - /** - * @dev Emitted when a debt token is initialized - * @param underlyingAsset The address of the underlying asset - * @param pool The address of the associated lending pool - * @param incentivesController The address of the incentives controller for this aToken - * @param debtTokenDecimals the decimals of the debt token - * @param debtTokenName the name of the debt token - * @param debtTokenSymbol the symbol of the debt token - * @param params A set of encoded parameters for additional initialization - **/ - event Initialized( - address indexed underlyingAsset, - address indexed pool, - address incentivesController, - uint8 debtTokenDecimals, - string debtTokenName, - string debtTokenSymbol, - bytes params - ); - - /** - * @dev Initializes the debt token. - * @param pool The address of the lending pool where this aToken will be used - * @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH) - * @param incentivesController The smart contract managing potential incentives distribution - * @param debtTokenDecimals The decimals of the debtToken, same as the underlying asset's - * @param debtTokenName The name of the token - * @param debtTokenSymbol The symbol of the token - */ - function initialize( - ILendingPool pool, - address underlyingAsset, - IAaveIncentivesController incentivesController, - uint8 debtTokenDecimals, - string memory debtTokenName, - string memory debtTokenSymbol, - bytes calldata params - ) external; -} - -/** - * @title IVariableDebtToken - * @author Aave - * @notice Defines the basic interface for a variable debt token. - **/ -interface IVariableDebtToken is IScaledBalanceToken, IInitializableDebtToken { - /** - * @dev Emitted after the mint action - * @param from The address performing the mint - * @param onBehalfOf The address of the user on which behalf minting has been performed - * @param value The amount to be minted - * @param index The last index of the reserve - **/ - event Mint(address indexed from, address indexed onBehalfOf, uint256 value, uint256 index); - - /** - * @dev Mints debt token to the `onBehalfOf` address - * @param user The address receiving the borrowed underlying, being the delegatee in case - * of credit delegate, or same as `onBehalfOf` otherwise - * @param onBehalfOf The address receiving the debt tokens - * @param amount The amount of debt being minted - * @param index The variable debt index of the reserve - * @return `true` if the the previous balance of the user is 0 - **/ - function mint( - address user, - address onBehalfOf, - uint256 amount, - uint256 index - ) external returns (bool); - - /** - * @dev Emitted when variable debt is burnt - * @param user The user which debt has been burned - * @param amount The amount of debt being burned - * @param index The index of the user - **/ - event Burn(address indexed user, uint256 amount, uint256 index); - - /** - * @dev Burns user variable debt - * @param user The user which debt is burnt - * @param index The variable debt index of the reserve - **/ - function burn( - address user, - uint256 amount, - uint256 index - ) external; - - /** - * @dev Returns the address of the incentives controller contract - **/ - function getIncentivesController() external view returns (IAaveIncentivesController); -} - -/** - * @title IFlashLoanReceiver interface - * @notice Interface for the Aave fee IFlashLoanReceiver. - * @author Aave - * @dev implement this interface to develop a flashloan-compatible flashLoanReceiver contract - **/ -interface IFlashLoanReceiver { - function executeOperation( - address[] calldata assets, - uint256[] calldata amounts, - uint256[] calldata premiums, - address initiator, - bytes calldata params - ) external returns (bool); - - function ADDRESSES_PROVIDER() external view returns (ILendingPoolAddressesProvider); - - function LENDING_POOL() external view returns (ILendingPool); -} - -/** - * @title IPriceOracleGetter interface - * @notice Interface for the Aave price oracle. - **/ - -interface IPriceOracleGetter { - /** - * @dev returns the asset price in ETH - * @param asset the address of the asset - * @return the ETH price of the asset - **/ - function getAssetPrice(address asset) external view returns (uint256); -} - -/** - * @title IStableDebtToken - * @notice Defines the interface for the stable debt token - * @dev It does not inherit from IERC20 to save in code size - * @author Aave - **/ - -interface IStableDebtToken is IInitializableDebtToken { - /** - * @dev Emitted when new stable debt is minted - * @param user The address of the user who triggered the minting - * @param onBehalfOf The recipient of stable debt tokens - * @param amount The amount minted - * @param currentBalance The current balance of the user - * @param balanceIncrease The increase in balance since the last action of the user - * @param newRate The rate of the debt after the minting - * @param avgStableRate The new average stable rate after the minting - * @param newTotalSupply The new total supply of the stable debt token after the action - **/ - event Mint( - address indexed user, - address indexed onBehalfOf, - uint256 amount, - uint256 currentBalance, - uint256 balanceIncrease, - uint256 newRate, - uint256 avgStableRate, - uint256 newTotalSupply - ); - - /** - * @dev Emitted when new stable debt is burned - * @param user The address of the user - * @param amount The amount being burned - * @param currentBalance The current balance of the user - * @param balanceIncrease The the increase in balance since the last action of the user - * @param avgStableRate The new average stable rate after the burning - * @param newTotalSupply The new total supply of the stable debt token after the action - **/ - event Burn( - address indexed user, - uint256 amount, - uint256 currentBalance, - uint256 balanceIncrease, - uint256 avgStableRate, - uint256 newTotalSupply - ); - - /** - * @dev Mints debt token to the `onBehalfOf` address. - * - The resulting rate is the weighted average between the rate of the new debt - * and the rate of the previous debt - * @param user The address receiving the borrowed underlying, being the delegatee in case - * of credit delegate, or same as `onBehalfOf` otherwise - * @param onBehalfOf The address receiving the debt tokens - * @param amount The amount of debt tokens to mint - * @param rate The rate of the debt being minted - **/ - function mint( - address user, - address onBehalfOf, - uint256 amount, - uint256 rate - ) external returns (bool); - - /** - * @dev Burns debt of `user` - * - The resulting rate is the weighted average between the rate of the new debt - * and the rate of the previous debt - * @param user The address of the user getting his debt burned - * @param amount The amount of debt tokens getting burned - **/ - function burn(address user, uint256 amount) external; - - /** - * @dev Returns the average rate of all the stable rate loans. - * @return The average stable rate - **/ - function getAverageStableRate() external view returns (uint256); - - /** - * @dev Returns the stable rate of the user debt - * @return The stable rate of the user - **/ - function getUserStableRate(address user) external view returns (uint256); - - /** - * @dev Returns the timestamp of the last update of the user - * @return The timestamp - **/ - function getUserLastUpdated(address user) external view returns (uint40); - - /** - * @dev Returns the principal, the total supply and the average stable rate - **/ - function getSupplyData() - external - view - returns ( - uint256, - uint256, - uint256, - uint40 - ); - - /** - * @dev Returns the timestamp of the last update of the total supply - * @return The timestamp - **/ - function getTotalSupplyLastUpdated() external view returns (uint40); - - /** - * @dev Returns the total supply and the average stable rate - **/ - function getTotalSupplyAndAvgRate() external view returns (uint256, uint256); - - /** - * @dev Returns the principal debt balance of the user - * @return The debt balance of the user since the last burn/mint action - **/ - function principalBalanceOf(address user) external view returns (uint256); - - /** - * @dev Returns the address of the incentives controller contract - **/ - function getIncentivesController() external view returns (IAaveIncentivesController); -} - -/** - * @title VersionedInitializable - * - * @dev Helper contract to implement initializer functions. To use it, replace - * the constructor with a function that has the `initializer` modifier. - * WARNING: Unlike constructors, initializer functions must be manually - * invoked. This applies both to deploying an Initializable contract, as well - * as extending an Initializable contract via inheritance. - * WARNING: When used with inheritance, manual care must be taken to not invoke - * a parent initializer twice, or ensure that all initializers are idempotent, - * because this is not dealt with automatically as with constructors. - * - * @author Aave, inspired by the OpenZeppelin Initializable contract - */ -abstract contract VersionedInitializable { - /** - * @dev Indicates that the contract has been initialized. - */ - uint256 private lastInitializedRevision = 0; - - /** - * @dev Indicates that the contract is in the process of being initialized. - */ - bool private initializing; - - /** - * @dev Modifier to use in the initializer function of a contract. - */ - modifier initializer() { - uint256 revision = getRevision(); - require( - initializing || isConstructor() || revision > lastInitializedRevision, - 'Contract instance has already been initialized' - ); - - bool isTopLevelCall = !initializing; - if (isTopLevelCall) { - initializing = true; - lastInitializedRevision = revision; - } - - _; - - if (isTopLevelCall) { - initializing = false; - } - } - - /** - * @dev returns the revision number of the contract - * Needs to be defined in the inherited class as a constant. - **/ - function getRevision() internal pure virtual returns (uint256); - - /** - * @dev Returns true if and only if the function is running in the constructor - **/ - function isConstructor() private view returns (bool) { - // extcodesize checks the size of the code stored in an address, and - // address returns the current address. Since the code is still not - // deployed when running a constructor, any checks on its code size will - // yield zero, making it an effective way to detect if a contract is - // under construction or not. - uint256 cs; - //solium-disable-next-line - assembly { - cs := extcodesize(address()) - } - return cs == 0; - } - - // Reserved storage space to allow for layout changes in the future. - uint256[50] private ______gap; -} - -/** - * @title Helpers library - * @author Aave - */ -library Helpers { - /** - * @dev Fetches the user current stable and variable debt balances - * @param user The user address - * @param reserve The reserve data object - * @return The stable and variable debt balance - **/ - function getUserCurrentDebt(address user, DataTypes.ReserveData storage reserve) - internal - view - returns (uint256, uint256) - { - return ( - IERC20(reserve.stableDebtTokenAddress).balanceOf(user), - IERC20(reserve.variableDebtTokenAddress).balanceOf(user) - ); - } - - function getUserCurrentDebtMemory(address user, DataTypes.ReserveData memory reserve) - internal - view - returns (uint256, uint256) - { - return ( - IERC20(reserve.stableDebtTokenAddress).balanceOf(user), - IERC20(reserve.variableDebtTokenAddress).balanceOf(user) - ); - } -} - -library Errors { - //common errors - string public constant CALLER_NOT_POOL_ADMIN = '33'; // 'The caller must be the pool admin' - string public constant BORROW_ALLOWANCE_NOT_ENOUGH = '59'; // User borrows on behalf, but allowance are too small - - //contract specific errors - string public constant VL_INVALID_AMOUNT = '1'; // 'Amount must be greater than 0' - string public constant VL_NO_ACTIVE_RESERVE = '2'; // 'Action requires an active reserve' - string public constant VL_RESERVE_FROZEN = '3'; // 'Action cannot be performed because the reserve is frozen' - string public constant VL_CURRENT_AVAILABLE_LIQUIDITY_NOT_ENOUGH = '4'; // 'The current liquidity is not enough' - string public constant VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE = '5'; // 'User cannot withdraw more than the available balance' - string public constant VL_TRANSFER_NOT_ALLOWED = '6'; // 'Transfer cannot be allowed.' - string public constant VL_BORROWING_NOT_ENABLED = '7'; // 'Borrowing is not enabled' - string public constant VL_INVALID_INTEREST_RATE_MODE_SELECTED = '8'; // 'Invalid interest rate mode selected' - string public constant VL_COLLATERAL_BALANCE_IS_0 = '9'; // 'The collateral balance is 0' - string public constant VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = '10'; // 'Health factor is lesser than the liquidation threshold' - string public constant VL_COLLATERAL_CANNOT_COVER_NEW_BORROW = '11'; // 'There is not enough collateral to cover a new borrow' - string public constant VL_STABLE_BORROWING_NOT_ENABLED = '12'; // stable borrowing not enabled - string public constant VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY = '13'; // collateral is (mostly) the same currency that is being borrowed - string public constant VL_AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE = '14'; // 'The requested amount is greater than the max loan size in stable rate mode - string public constant VL_NO_DEBT_OF_SELECTED_TYPE = '15'; // 'for repayment of stable debt, the user needs to have stable debt, otherwise, he needs to have variable debt' - string public constant VL_NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = '16'; // 'To repay on behalf of an user an explicit amount to repay is needed' - string public constant VL_NO_STABLE_RATE_LOAN_IN_RESERVE = '17'; // 'User does not have a stable rate loan in progress on this reserve' - string public constant VL_NO_VARIABLE_RATE_LOAN_IN_RESERVE = '18'; // 'User does not have a variable rate loan in progress on this reserve' - string public constant VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0 = '19'; // 'The underlying balance needs to be greater than 0' - string public constant VL_DEPOSIT_ALREADY_IN_USE = '20'; // 'User deposit is already being used as collateral' - string public constant LP_NOT_ENOUGH_STABLE_BORROW_BALANCE = '21'; // 'User does not have any stable rate loan for this reserve' - string public constant LP_INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET = '22'; // 'Interest rate rebalance conditions were not met' - string public constant LP_LIQUIDATION_CALL_FAILED = '23'; // 'Liquidation call failed' - string public constant LP_NOT_ENOUGH_LIQUIDITY_TO_BORROW = '24'; // 'There is not enough liquidity available to borrow' - string public constant LP_REQUESTED_AMOUNT_TOO_SMALL = '25'; // 'The requested amount is too small for a FlashLoan.' - string public constant LP_INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '26'; // 'The actual balance of the protocol is inconsistent' - string public constant LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR = '27'; // 'The caller of the function is not the lending pool configurator' - string public constant LP_INCONSISTENT_FLASHLOAN_PARAMS = '28'; - string public constant CT_CALLER_MUST_BE_LENDING_POOL = '29'; // 'The caller of this function must be a lending pool' - string public constant CT_CANNOT_GIVE_ALLOWANCE_TO_HIMSELF = '30'; // 'User cannot give allowance to himself' - string public constant CT_TRANSFER_AMOUNT_NOT_GT_0 = '31'; // 'Transferred amount needs to be greater than zero' - string public constant RL_RESERVE_ALREADY_INITIALIZED = '32'; // 'Reserve has already been initialized' - string public constant LPC_RESERVE_LIQUIDITY_NOT_0 = '34'; // 'The liquidity of the reserve needs to be 0' - string public constant LPC_INVALID_ATOKEN_POOL_ADDRESS = '35'; // 'The liquidity of the reserve needs to be 0' - string public constant LPC_INVALID_STABLE_DEBT_TOKEN_POOL_ADDRESS = '36'; // 'The liquidity of the reserve needs to be 0' - string public constant LPC_INVALID_VARIABLE_DEBT_TOKEN_POOL_ADDRESS = '37'; // 'The liquidity of the reserve needs to be 0' - string public constant LPC_INVALID_STABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = '38'; // 'The liquidity of the reserve needs to be 0' - string public constant LPC_INVALID_VARIABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = '39'; // 'The liquidity of the reserve needs to be 0' - string public constant LPC_INVALID_ADDRESSES_PROVIDER_ID = '40'; // 'The liquidity of the reserve needs to be 0' - string public constant LPC_INVALID_CONFIGURATION = '75'; // 'Invalid risk parameters for the reserve' - string public constant LPC_CALLER_NOT_EMERGENCY_ADMIN = '76'; // 'The caller must be the emergency admin' - string public constant LPAPR_PROVIDER_NOT_REGISTERED = '41'; // 'Provider is not registered' - string public constant LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD = '42'; // 'Health factor is not below the threshold' - string public constant LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED = '43'; // 'The collateral chosen cannot be liquidated' - string public constant LPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = '44'; // 'User did not borrow the specified currency' - string public constant LPCM_NOT_ENOUGH_LIQUIDITY_TO_LIQUIDATE = '45'; // "There isn't enough liquidity available to liquidate" - string public constant LPCM_NO_ERRORS = '46'; // 'No errors' - string public constant LP_INVALID_FLASHLOAN_MODE = '47'; //Invalid flashloan mode selected - string public constant MATH_MULTIPLICATION_OVERFLOW = '48'; - string public constant MATH_ADDITION_OVERFLOW = '49'; - string public constant MATH_DIVISION_BY_ZERO = '50'; - string public constant RL_LIQUIDITY_INDEX_OVERFLOW = '51'; // Liquidity index overflows uint128 - string public constant RL_VARIABLE_BORROW_INDEX_OVERFLOW = '52'; // Variable borrow index overflows uint128 - string public constant RL_LIQUIDITY_RATE_OVERFLOW = '53'; // Liquidity rate overflows uint128 - string public constant RL_VARIABLE_BORROW_RATE_OVERFLOW = '54'; // Variable borrow rate overflows uint128 - string public constant RL_STABLE_BORROW_RATE_OVERFLOW = '55'; // Stable borrow rate overflows uint128 - string public constant CT_INVALID_MINT_AMOUNT = '56'; //invalid amount to mint - string public constant LP_FAILED_REPAY_WITH_COLLATERAL = '57'; - string public constant CT_INVALID_BURN_AMOUNT = '58'; //invalid amount to burn - string public constant LP_FAILED_COLLATERAL_SWAP = '60'; - string public constant LP_INVALID_EQUAL_ASSETS_TO_SWAP = '61'; - string public constant LP_REENTRANCY_NOT_ALLOWED = '62'; - string public constant LP_CALLER_MUST_BE_AN_ATOKEN = '63'; - string public constant LP_IS_PAUSED = '64'; // 'Pool is paused' - string public constant LP_NO_MORE_RESERVES_ALLOWED = '65'; - string public constant LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN = '66'; - string public constant RC_INVALID_LTV = '67'; - string public constant RC_INVALID_LIQ_THRESHOLD = '68'; - string public constant RC_INVALID_LIQ_BONUS = '69'; - string public constant RC_INVALID_DECIMALS = '70'; - string public constant RC_INVALID_RESERVE_FACTOR = '71'; - string public constant LPAPR_INVALID_ADDRESSES_PROVIDER_ID = '72'; - string public constant VL_INCONSISTENT_FLASHLOAN_PARAMS = '73'; - string public constant LP_INCONSISTENT_PARAMS_LENGTH = '74'; - string public constant UL_INVALID_INDEX = '77'; - string public constant LP_NOT_CONTRACT = '78'; - string public constant SDT_STABLE_DEBT_OVERFLOW = '79'; - string public constant SDT_BURN_EXCEEDS_BALANCE = '80'; - - enum CollateralManagerErrors { - NO_ERROR, - NO_COLLATERAL_AVAILABLE, - COLLATERAL_CANNOT_BE_LIQUIDATED, - CURRRENCY_NOT_BORROWED, - HEALTH_FACTOR_ABOVE_THRESHOLD, - NOT_ENOUGH_LIQUIDITY, - NO_ACTIVE_RESERVE, - HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD, - INVALID_EQUAL_ASSETS_TO_SWAP, - FROZEN_RESERVE - } -} - -/** - * @title WadRayMath library - * @author Aave - * @dev Provides mul and div function for wads (decimal numbers with 18 digits precision) and rays (decimals with 27 digits) - **/ - -library WadRayMath { - uint256 internal constant WAD = 1e18; - uint256 internal constant halfWAD = WAD / 2; - - uint256 internal constant RAY = 1e27; - uint256 internal constant halfRAY = RAY / 2; - - uint256 internal constant WAD_RAY_RATIO = 1e9; - - /** - * @return One ray, 1e27 - **/ - function ray() internal pure returns (uint256) { - return RAY; - } - - /** - * @return One wad, 1e18 - **/ - - function wad() internal pure returns (uint256) { - return WAD; - } - - /** - * @return Half ray, 1e27/2 - **/ - function halfRay() internal pure returns (uint256) { - return halfRAY; - } - - /** - * @return Half ray, 1e18/2 - **/ - function halfWad() internal pure returns (uint256) { - return halfWAD; - } - - /** - * @dev Multiplies two wad, rounding half up to the nearest wad - * @param a Wad - * @param b Wad - * @return The result of a*b, in wad - **/ - function wadMul(uint256 a, uint256 b) internal pure returns (uint256) { - if (a == 0 || b == 0) { - return 0; - } - - require(a <= (type(uint256).max - halfWAD) / b, Errors.MATH_MULTIPLICATION_OVERFLOW); - - return (a * b + halfWAD) / WAD; - } - - /** - * @dev Divides two wad, rounding half up to the nearest wad - * @param a Wad - * @param b Wad - * @return The result of a/b, in wad - **/ - function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) { - require(b != 0, Errors.MATH_DIVISION_BY_ZERO); - uint256 halfB = b / 2; - - require(a <= (type(uint256).max - halfB) / WAD, Errors.MATH_MULTIPLICATION_OVERFLOW); - - return (a * WAD + halfB) / b; - } - - /** - * @dev Multiplies two ray, rounding half up to the nearest ray - * @param a Ray - * @param b Ray - * @return The result of a*b, in ray - **/ - function rayMul(uint256 a, uint256 b) internal pure returns (uint256) { - if (a == 0 || b == 0) { - return 0; - } - - require(a <= (type(uint256).max - halfRAY) / b, Errors.MATH_MULTIPLICATION_OVERFLOW); - - return (a * b + halfRAY) / RAY; - } - - /** - * @dev Divides two ray, rounding half up to the nearest ray - * @param a Ray - * @param b Ray - * @return The result of a/b, in ray - **/ - function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) { - require(b != 0, Errors.MATH_DIVISION_BY_ZERO); - uint256 halfB = b / 2; - - require(a <= (type(uint256).max - halfB) / RAY, Errors.MATH_MULTIPLICATION_OVERFLOW); - - return (a * RAY + halfB) / b; - } - - /** - * @dev Casts ray down to wad - * @param a Ray - * @return a casted to wad, rounded half up to the nearest wad - **/ - function rayToWad(uint256 a) internal pure returns (uint256) { - uint256 halfRatio = WAD_RAY_RATIO / 2; - uint256 result = halfRatio + a; - require(result >= halfRatio, Errors.MATH_ADDITION_OVERFLOW); - - return result / WAD_RAY_RATIO; - } - - /** - * @dev Converts wad up to ray - * @param a Wad - * @return a converted in ray - **/ - function wadToRay(uint256 a) internal pure returns (uint256) { - uint256 result = a * WAD_RAY_RATIO; - require(result / WAD_RAY_RATIO == a, Errors.MATH_MULTIPLICATION_OVERFLOW); - return result; - } -} - -/** - * @title PercentageMath library - * @author Aave - * @notice Provides functions to perform percentage calculations - * @dev Percentages are defined by default with 2 decimals of precision (100.00). The precision is indicated by PERCENTAGE_FACTOR - * @dev Operations are rounded half up - **/ - -library PercentageMath { - uint256 constant PERCENTAGE_FACTOR = 1e4; //percentage plus two decimals - uint256 constant HALF_PERCENT = PERCENTAGE_FACTOR / 2; - - /** - * @dev Executes a percentage multiplication - * @param value The value of which the percentage needs to be calculated - * @param percentage The percentage of the value to be calculated - * @return The percentage of value - **/ - function percentMul(uint256 value, uint256 percentage) internal pure returns (uint256) { - if (value == 0 || percentage == 0) { - return 0; - } - - require( - value <= (type(uint256).max - HALF_PERCENT) / percentage, - Errors.MATH_MULTIPLICATION_OVERFLOW - ); - - return (value * percentage + HALF_PERCENT) / PERCENTAGE_FACTOR; - } - - /** - * @dev Executes a percentage division - * @param value The value of which the percentage needs to be calculated - * @param percentage The percentage of the value to be calculated - * @return The value divided the percentage - **/ - function percentDiv(uint256 value, uint256 percentage) internal pure returns (uint256) { - require(percentage != 0, Errors.MATH_DIVISION_BY_ZERO); - uint256 halfPercentage = percentage / 2; - - require( - value <= (type(uint256).max - halfPercentage) / PERCENTAGE_FACTOR, - Errors.MATH_MULTIPLICATION_OVERFLOW - ); - - return (value * PERCENTAGE_FACTOR + halfPercentage) / percentage; - } -} - -/** - * @title IReserveInterestRateStrategyInterface interface - * @dev Interface for the calculation of the interest rates - * @author Aave - */ -interface IReserveInterestRateStrategy { - function baseVariableBorrowRate() external view returns (uint256); - - function getMaxVariableBorrowRate() external view returns (uint256); - - function calculateInterestRates( - address reserve, - uint256 availableLiquidity, - uint256 totalStableDebt, - uint256 totalVariableDebt, - uint256 averageStableBorrowRate, - uint256 reserveFactor - ) - external - view - returns ( - uint256, - uint256, - uint256 - ); - - function calculateInterestRates( - address reserve, - address aToken, - uint256 liquidityAdded, - uint256 liquidityTaken, - uint256 totalStableDebt, - uint256 totalVariableDebt, - uint256 averageStableBorrowRate, - uint256 reserveFactor - ) - external - view - returns ( - uint256 liquidityRate, - uint256 stableBorrowRate, - uint256 variableBorrowRate - ); -} - -/** - * @title ReserveConfiguration library - * @author Aave - * @notice Implements the bitmap logic to handle the reserve configuration - */ -library ReserveConfiguration { - uint256 constant LTV_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000; // prettier-ignore - uint256 constant LIQUIDATION_THRESHOLD_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF; // prettier-ignore - uint256 constant LIQUIDATION_BONUS_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFF; // prettier-ignore - uint256 constant DECIMALS_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF; // prettier-ignore - uint256 constant ACTIVE_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFF; // prettier-ignore - uint256 constant FROZEN_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFF; // prettier-ignore - uint256 constant BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFF; // prettier-ignore - uint256 constant STABLE_BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFF; // prettier-ignore - uint256 constant RESERVE_FACTOR_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFF; // prettier-ignore - - /// @dev For the LTV, the start bit is 0 (up to 15), hence no bitshifting is needed - uint256 constant LIQUIDATION_THRESHOLD_START_BIT_POSITION = 16; - uint256 constant LIQUIDATION_BONUS_START_BIT_POSITION = 32; - uint256 constant RESERVE_DECIMALS_START_BIT_POSITION = 48; - uint256 constant IS_ACTIVE_START_BIT_POSITION = 56; - uint256 constant IS_FROZEN_START_BIT_POSITION = 57; - uint256 constant BORROWING_ENABLED_START_BIT_POSITION = 58; - uint256 constant STABLE_BORROWING_ENABLED_START_BIT_POSITION = 59; - uint256 constant RESERVE_FACTOR_START_BIT_POSITION = 64; - - uint256 constant MAX_VALID_LTV = 65535; - uint256 constant MAX_VALID_LIQUIDATION_THRESHOLD = 65535; - uint256 constant MAX_VALID_LIQUIDATION_BONUS = 65535; - uint256 constant MAX_VALID_DECIMALS = 255; - uint256 constant MAX_VALID_RESERVE_FACTOR = 65535; - - /** - * @dev Sets the Loan to Value of the reserve - * @param self The reserve configuration - * @param ltv the new ltv - **/ - function setLtv(DataTypes.ReserveConfigurationMap memory self, uint256 ltv) internal pure { - require(ltv <= MAX_VALID_LTV, Errors.RC_INVALID_LTV); - - self.data = (self.data & LTV_MASK) | ltv; - } - - /** - * @dev Gets the Loan to Value of the reserve - * @param self The reserve configuration - * @return The loan to value - **/ - function getLtv(DataTypes.ReserveConfigurationMap storage self) internal view returns (uint256) { - return self.data & ~LTV_MASK; - } - - /** - * @dev Sets the liquidation threshold of the reserve - * @param self The reserve configuration - * @param threshold The new liquidation threshold - **/ - function setLiquidationThreshold(DataTypes.ReserveConfigurationMap memory self, uint256 threshold) - internal - pure - { - require(threshold <= MAX_VALID_LIQUIDATION_THRESHOLD, Errors.RC_INVALID_LIQ_THRESHOLD); - - self.data = - (self.data & LIQUIDATION_THRESHOLD_MASK) | - (threshold << LIQUIDATION_THRESHOLD_START_BIT_POSITION); - } - - /** - * @dev Gets the liquidation threshold of the reserve - * @param self The reserve configuration - * @return The liquidation threshold - **/ - function getLiquidationThreshold(DataTypes.ReserveConfigurationMap storage self) - internal - view - returns (uint256) - { - return (self.data & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION; - } - - /** - * @dev Sets the liquidation bonus of the reserve - * @param self The reserve configuration - * @param bonus The new liquidation bonus - **/ - function setLiquidationBonus(DataTypes.ReserveConfigurationMap memory self, uint256 bonus) - internal - pure - { - require(bonus <= MAX_VALID_LIQUIDATION_BONUS, Errors.RC_INVALID_LIQ_BONUS); - - self.data = - (self.data & LIQUIDATION_BONUS_MASK) | - (bonus << LIQUIDATION_BONUS_START_BIT_POSITION); - } - - /** - * @dev Gets the liquidation bonus of the reserve - * @param self The reserve configuration - * @return The liquidation bonus - **/ - function getLiquidationBonus(DataTypes.ReserveConfigurationMap storage self) - internal - view - returns (uint256) - { - return (self.data & ~LIQUIDATION_BONUS_MASK) >> LIQUIDATION_BONUS_START_BIT_POSITION; - } - - /** - * @dev Sets the decimals of the underlying asset of the reserve - * @param self The reserve configuration - * @param decimals The decimals - **/ - function setDecimals(DataTypes.ReserveConfigurationMap memory self, uint256 decimals) - internal - pure - { - require(decimals <= MAX_VALID_DECIMALS, Errors.RC_INVALID_DECIMALS); - - self.data = (self.data & DECIMALS_MASK) | (decimals << RESERVE_DECIMALS_START_BIT_POSITION); - } - - /** - * @dev Gets the decimals of the underlying asset of the reserve - * @param self The reserve configuration - * @return The decimals of the asset - **/ - function getDecimals(DataTypes.ReserveConfigurationMap storage self) - internal - view - returns (uint256) - { - return (self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION; - } - - /** - * @dev Sets the active state of the reserve - * @param self The reserve configuration - * @param active The active state - **/ - function setActive(DataTypes.ReserveConfigurationMap memory self, bool active) internal pure { - self.data = - (self.data & ACTIVE_MASK) | - (uint256(active ? 1 : 0) << IS_ACTIVE_START_BIT_POSITION); - } - - /** - * @dev Gets the active state of the reserve - * @param self The reserve configuration - * @return The active state - **/ - function getActive(DataTypes.ReserveConfigurationMap storage self) internal view returns (bool) { - return (self.data & ~ACTIVE_MASK) != 0; - } - - /** - * @dev Sets the frozen state of the reserve - * @param self The reserve configuration - * @param frozen The frozen state - **/ - function setFrozen(DataTypes.ReserveConfigurationMap memory self, bool frozen) internal pure { - self.data = - (self.data & FROZEN_MASK) | - (uint256(frozen ? 1 : 0) << IS_FROZEN_START_BIT_POSITION); - } - - /** - * @dev Gets the frozen state of the reserve - * @param self The reserve configuration - * @return The frozen state - **/ - function getFrozen(DataTypes.ReserveConfigurationMap storage self) internal view returns (bool) { - return (self.data & ~FROZEN_MASK) != 0; - } - - /** - * @dev Enables or disables borrowing on the reserve - * @param self The reserve configuration - * @param enabled True if the borrowing needs to be enabled, false otherwise - **/ - function setBorrowingEnabled(DataTypes.ReserveConfigurationMap memory self, bool enabled) - internal - pure - { - self.data = - (self.data & BORROWING_MASK) | - (uint256(enabled ? 1 : 0) << BORROWING_ENABLED_START_BIT_POSITION); - } - - /** - * @dev Gets the borrowing state of the reserve - * @param self The reserve configuration - * @return The borrowing state - **/ - function getBorrowingEnabled(DataTypes.ReserveConfigurationMap storage self) - internal - view - returns (bool) - { - return (self.data & ~BORROWING_MASK) != 0; - } - - /** - * @dev Enables or disables stable rate borrowing on the reserve - * @param self The reserve configuration - * @param enabled True if the stable rate borrowing needs to be enabled, false otherwise - **/ - function setStableRateBorrowingEnabled( - DataTypes.ReserveConfigurationMap memory self, - bool enabled - ) internal pure { - self.data = - (self.data & STABLE_BORROWING_MASK) | - (uint256(enabled ? 1 : 0) << STABLE_BORROWING_ENABLED_START_BIT_POSITION); - } - - /** - * @dev Gets the stable rate borrowing state of the reserve - * @param self The reserve configuration - * @return The stable rate borrowing state - **/ - function getStableRateBorrowingEnabled(DataTypes.ReserveConfigurationMap storage self) - internal - view - returns (bool) - { - return (self.data & ~STABLE_BORROWING_MASK) != 0; - } - - /** - * @dev Sets the reserve factor of the reserve - * @param self The reserve configuration - * @param reserveFactor The reserve factor - **/ - function setReserveFactor(DataTypes.ReserveConfigurationMap memory self, uint256 reserveFactor) - internal - pure - { - require(reserveFactor <= MAX_VALID_RESERVE_FACTOR, Errors.RC_INVALID_RESERVE_FACTOR); - - self.data = - (self.data & RESERVE_FACTOR_MASK) | - (reserveFactor << RESERVE_FACTOR_START_BIT_POSITION); - } - - /** - * @dev Gets the reserve factor of the reserve - * @param self The reserve configuration - * @return The reserve factor - **/ - function getReserveFactor(DataTypes.ReserveConfigurationMap storage self) - internal - view - returns (uint256) - { - return (self.data & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION; - } - - /** - * @dev Gets the configuration flags of the reserve - * @param self The reserve configuration - * @return The state flags representing active, frozen, borrowing enabled, stableRateBorrowing enabled - **/ - function getFlags(DataTypes.ReserveConfigurationMap storage self) - internal - view - returns ( - bool, - bool, - bool, - bool - ) - { - uint256 dataLocal = self.data; - - return ( - (dataLocal & ~ACTIVE_MASK) != 0, - (dataLocal & ~FROZEN_MASK) != 0, - (dataLocal & ~BORROWING_MASK) != 0, - (dataLocal & ~STABLE_BORROWING_MASK) != 0 - ); - } - - /** - * @dev Gets the configuration paramters of the reserve - * @param self The reserve configuration - * @return The state params representing ltv, liquidation threshold, liquidation bonus, the reserve decimals - **/ - function getParams(DataTypes.ReserveConfigurationMap storage self) - internal - view - returns ( - uint256, - uint256, - uint256, - uint256, - uint256 - ) - { - uint256 dataLocal = self.data; - - return ( - dataLocal & ~LTV_MASK, - (dataLocal & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION, - (dataLocal & ~LIQUIDATION_BONUS_MASK) >> LIQUIDATION_BONUS_START_BIT_POSITION, - (dataLocal & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION, - (dataLocal & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION - ); - } - - /** - * @dev Gets the configuration paramters of the reserve from a memory object - * @param self The reserve configuration - * @return The state params representing ltv, liquidation threshold, liquidation bonus, the reserve decimals - **/ - function getParamsMemory(DataTypes.ReserveConfigurationMap memory self) - internal - pure - returns ( - uint256, - uint256, - uint256, - uint256, - uint256 - ) - { - return ( - self.data & ~LTV_MASK, - (self.data & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION, - (self.data & ~LIQUIDATION_BONUS_MASK) >> LIQUIDATION_BONUS_START_BIT_POSITION, - (self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION, - (self.data & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION - ); - } - - /** - * @dev Gets the configuration flags of the reserve from a memory object - * @param self The reserve configuration - * @return The state flags representing active, frozen, borrowing enabled, stableRateBorrowing enabled - **/ - function getFlagsMemory(DataTypes.ReserveConfigurationMap memory self) - internal - pure - returns ( - bool, - bool, - bool, - bool - ) - { - return ( - (self.data & ~ACTIVE_MASK) != 0, - (self.data & ~FROZEN_MASK) != 0, - (self.data & ~BORROWING_MASK) != 0, - (self.data & ~STABLE_BORROWING_MASK) != 0 - ); - } -} - -library MathUtils { - using SafeMath for uint256; - using WadRayMath for uint256; - - /// @dev Ignoring leap years - uint256 internal constant SECONDS_PER_YEAR = 365 days; - - /** - * @dev Function to calculate the interest accumulated using a linear interest rate formula - * @param rate The interest rate, in ray - * @param lastUpdateTimestamp The timestamp of the last update of the interest - * @return The interest rate linearly accumulated during the timeDelta, in ray - **/ - - function calculateLinearInterest(uint256 rate, uint40 lastUpdateTimestamp) - internal - view - returns (uint256) - { - //solium-disable-next-line - uint256 timeDifference = block.timestamp.sub(uint256(lastUpdateTimestamp)); - - return (rate.mul(timeDifference) / SECONDS_PER_YEAR).add(WadRayMath.ray()); - } - - /** - * @dev Function to calculate the interest using a compounded interest rate formula - * To avoid expensive exponentiation, the calculation is performed using a binomial approximation: - * - * (1+x)^n = 1+n*x+[n/2*(n-1)]*x^2+[n/6*(n-1)*(n-2)*x^3... - * - * The approximation slightly underpays liquidity providers and undercharges borrowers, with the advantage of great gas cost reductions - * The whitepaper contains reference to the approximation and a table showing the margin of error per different time periods - * - * @param rate The interest rate, in ray - * @param lastUpdateTimestamp The timestamp of the last update of the interest - * @return The interest rate compounded during the timeDelta, in ray - **/ - function calculateCompoundedInterest( - uint256 rate, - uint40 lastUpdateTimestamp, - uint256 currentTimestamp - ) internal pure returns (uint256) { - //solium-disable-next-line - uint256 exp = currentTimestamp.sub(uint256(lastUpdateTimestamp)); - - if (exp == 0) { - return WadRayMath.ray(); - } - - uint256 expMinusOne = exp - 1; - - uint256 expMinusTwo = exp > 2 ? exp - 2 : 0; - - uint256 ratePerSecond = rate / SECONDS_PER_YEAR; - - uint256 basePowerTwo = ratePerSecond.rayMul(ratePerSecond); - uint256 basePowerThree = basePowerTwo.rayMul(ratePerSecond); - - uint256 secondTerm = exp.mul(expMinusOne).mul(basePowerTwo) / 2; - uint256 thirdTerm = exp.mul(expMinusOne).mul(expMinusTwo).mul(basePowerThree) / 6; - - return WadRayMath.ray().add(ratePerSecond.mul(exp)).add(secondTerm).add(thirdTerm); - } - - /** - * @dev Calculates the compounded interest between the timestamp of the last update and the current block timestamp - * @param rate The interest rate (in ray) - * @param lastUpdateTimestamp The timestamp from which the interest accumulation needs to be calculated - **/ - function calculateCompoundedInterest(uint256 rate, uint40 lastUpdateTimestamp) - internal - view - returns (uint256) - { - return calculateCompoundedInterest(rate, lastUpdateTimestamp, block.timestamp); - } -} - -/** - * @title ReserveLogic library - * @author Aave - * @notice Implements the logic to update the reserves state - */ -library ReserveLogic { - using SafeMath for uint256; - using WadRayMath for uint256; - using PercentageMath for uint256; - using SafeERC20 for IERC20; - - /** - * @dev Emitted when the state of a reserve is updated - * @param asset The address of the underlying asset of the reserve - * @param liquidityRate The new liquidity rate - * @param stableBorrowRate The new stable borrow rate - * @param variableBorrowRate The new variable borrow rate - * @param liquidityIndex The new liquidity index - * @param variableBorrowIndex The new variable borrow index - **/ - event ReserveDataUpdated( - address indexed asset, - uint256 liquidityRate, - uint256 stableBorrowRate, - uint256 variableBorrowRate, - uint256 liquidityIndex, - uint256 variableBorrowIndex - ); - - using ReserveLogic for DataTypes.ReserveData; - using ReserveConfiguration for DataTypes.ReserveConfigurationMap; - - /** - * @dev Returns the ongoing normalized income for the reserve - * A value of 1e27 means there is no income. As time passes, the income is accrued - * A value of 2*1e27 means for each unit of asset one unit of income has been accrued - * @param reserve The reserve object - * @return the normalized income. expressed in ray - **/ - function getNormalizedIncome(DataTypes.ReserveData storage reserve) - internal - view - returns (uint256) - { - uint40 timestamp = reserve.lastUpdateTimestamp; - - //solium-disable-next-line - if (timestamp == uint40(block.timestamp)) { - //if the index was updated in the same block, no need to perform any calculation - return reserve.liquidityIndex; - } - - uint256 cumulated = MathUtils - .calculateLinearInterest(reserve.currentLiquidityRate, timestamp) - .rayMul(reserve.liquidityIndex); - - return cumulated; - } - - /** - * @dev Returns the ongoing normalized variable debt for the reserve - * A value of 1e27 means there is no debt. As time passes, the income is accrued - * A value of 2*1e27 means that for each unit of debt, one unit worth of interest has been accumulated - * @param reserve The reserve object - * @return The normalized variable debt. expressed in ray - **/ - function getNormalizedDebt(DataTypes.ReserveData storage reserve) - internal - view - returns (uint256) - { - uint40 timestamp = reserve.lastUpdateTimestamp; - - //solium-disable-next-line - if (timestamp == uint40(block.timestamp)) { - //if the index was updated in the same block, no need to perform any calculation - return reserve.variableBorrowIndex; - } - - uint256 cumulated = MathUtils - .calculateCompoundedInterest(reserve.currentVariableBorrowRate, timestamp) - .rayMul(reserve.variableBorrowIndex); - - return cumulated; - } - - /** - * @dev Updates the liquidity cumulative index and the variable borrow index. - * @param reserve the reserve object - **/ - function updateState(DataTypes.ReserveData storage reserve) internal { - uint256 scaledVariableDebt = IVariableDebtToken(reserve.variableDebtTokenAddress) - .scaledTotalSupply(); - uint256 previousVariableBorrowIndex = reserve.variableBorrowIndex; - uint256 previousLiquidityIndex = reserve.liquidityIndex; - uint40 lastUpdatedTimestamp = reserve.lastUpdateTimestamp; - - (uint256 newLiquidityIndex, uint256 newVariableBorrowIndex) = _updateIndexes( - reserve, - scaledVariableDebt, - previousLiquidityIndex, - previousVariableBorrowIndex, - lastUpdatedTimestamp - ); - - _mintToTreasury( - reserve, - scaledVariableDebt, - previousVariableBorrowIndex, - newLiquidityIndex, - newVariableBorrowIndex, - lastUpdatedTimestamp - ); - } - - /** - * @dev Accumulates a predefined amount of asset to the reserve as a fixed, instantaneous income. Used for example to accumulate - * the flashloan fee to the reserve, and spread it between all the depositors - * @param reserve The reserve object - * @param totalLiquidity The total liquidity available in the reserve - * @param amount The amount to accomulate - **/ - function cumulateToLiquidityIndex( - DataTypes.ReserveData storage reserve, - uint256 totalLiquidity, - uint256 amount - ) internal { - uint256 amountToLiquidityRatio = amount.wadToRay().rayDiv(totalLiquidity.wadToRay()); - - uint256 result = amountToLiquidityRatio.add(WadRayMath.ray()); - - result = result.rayMul(reserve.liquidityIndex); - require(result <= type(uint128).max, Errors.RL_LIQUIDITY_INDEX_OVERFLOW); - - reserve.liquidityIndex = uint128(result); - } - - /** - * @dev Initializes a reserve - * @param reserve The reserve object - * @param aTokenAddress The address of the overlying atoken contract - * @param interestRateStrategyAddress The address of the interest rate strategy contract - **/ - function init( - DataTypes.ReserveData storage reserve, - address aTokenAddress, - address stableDebtTokenAddress, - address variableDebtTokenAddress, - address interestRateStrategyAddress - ) external { - require(reserve.aTokenAddress == address(0), Errors.RL_RESERVE_ALREADY_INITIALIZED); - - reserve.liquidityIndex = uint128(WadRayMath.ray()); - reserve.variableBorrowIndex = uint128(WadRayMath.ray()); - reserve.aTokenAddress = aTokenAddress; - reserve.stableDebtTokenAddress = stableDebtTokenAddress; - reserve.variableDebtTokenAddress = variableDebtTokenAddress; - reserve.interestRateStrategyAddress = interestRateStrategyAddress; - } - - struct UpdateInterestRatesLocalVars { - address stableDebtTokenAddress; - uint256 availableLiquidity; - uint256 totalStableDebt; - uint256 newLiquidityRate; - uint256 newStableRate; - uint256 newVariableRate; - uint256 avgStableRate; - uint256 totalVariableDebt; - } - - /** - * @dev Updates the reserve current stable borrow rate, the current variable borrow rate and the current liquidity rate - * @param reserve The address of the reserve to be updated - * @param liquidityAdded The amount of liquidity added to the protocol (deposit or repay) in the previous action - * @param liquidityTaken The amount of liquidity taken from the protocol (redeem or borrow) - **/ - function updateInterestRates( - DataTypes.ReserveData storage reserve, - address reserveAddress, - address aTokenAddress, - uint256 liquidityAdded, - uint256 liquidityTaken - ) internal { - UpdateInterestRatesLocalVars memory vars; - - vars.stableDebtTokenAddress = reserve.stableDebtTokenAddress; - - (vars.totalStableDebt, vars.avgStableRate) = IStableDebtToken(vars.stableDebtTokenAddress) - .getTotalSupplyAndAvgRate(); - - //calculates the total variable debt locally using the scaled total supply instead - //of totalSupply(), as it's noticeably cheaper. Also, the index has been - //updated by the previous updateState() call - vars.totalVariableDebt = IVariableDebtToken(reserve.variableDebtTokenAddress) - .scaledTotalSupply() - .rayMul(reserve.variableBorrowIndex); - - ( - vars.newLiquidityRate, - vars.newStableRate, - vars.newVariableRate - ) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates( - reserveAddress, - aTokenAddress, - liquidityAdded, - liquidityTaken, - vars.totalStableDebt, - vars.totalVariableDebt, - vars.avgStableRate, - reserve.configuration.getReserveFactor() - ); - require(vars.newLiquidityRate <= type(uint128).max, Errors.RL_LIQUIDITY_RATE_OVERFLOW); - require(vars.newStableRate <= type(uint128).max, Errors.RL_STABLE_BORROW_RATE_OVERFLOW); - require(vars.newVariableRate <= type(uint128).max, Errors.RL_VARIABLE_BORROW_RATE_OVERFLOW); - - reserve.currentLiquidityRate = uint128(vars.newLiquidityRate); - reserve.currentStableBorrowRate = uint128(vars.newStableRate); - reserve.currentVariableBorrowRate = uint128(vars.newVariableRate); - - emit ReserveDataUpdated( - reserveAddress, - vars.newLiquidityRate, - vars.newStableRate, - vars.newVariableRate, - reserve.liquidityIndex, - reserve.variableBorrowIndex - ); - } - - struct MintToTreasuryLocalVars { - uint256 currentStableDebt; - uint256 principalStableDebt; - uint256 previousStableDebt; - uint256 currentVariableDebt; - uint256 previousVariableDebt; - uint256 avgStableRate; - uint256 cumulatedStableInterest; - uint256 totalDebtAccrued; - uint256 amountToMint; - uint256 reserveFactor; - uint40 stableSupplyUpdatedTimestamp; - } - - /** - * @dev Mints part of the repaid interest to the reserve treasury as a function of the reserveFactor for the - * specific asset. - * @param reserve The reserve reserve to be updated - * @param scaledVariableDebt The current scaled total variable debt - * @param previousVariableBorrowIndex The variable borrow index before the last accumulation of the interest - * @param newLiquidityIndex The new liquidity index - * @param newVariableBorrowIndex The variable borrow index after the last accumulation of the interest - **/ - function _mintToTreasury( - DataTypes.ReserveData storage reserve, - uint256 scaledVariableDebt, - uint256 previousVariableBorrowIndex, - uint256 newLiquidityIndex, - uint256 newVariableBorrowIndex, - uint40 timestamp - ) internal { - MintToTreasuryLocalVars memory vars; - - vars.reserveFactor = reserve.configuration.getReserveFactor(); - - if (vars.reserveFactor == 0) { - return; - } - - //fetching the principal, total stable debt and the avg stable rate - ( - vars.principalStableDebt, - vars.currentStableDebt, - vars.avgStableRate, - vars.stableSupplyUpdatedTimestamp - ) = IStableDebtToken(reserve.stableDebtTokenAddress).getSupplyData(); - - //calculate the last principal variable debt - vars.previousVariableDebt = scaledVariableDebt.rayMul(previousVariableBorrowIndex); - - //calculate the new total supply after accumulation of the index - vars.currentVariableDebt = scaledVariableDebt.rayMul(newVariableBorrowIndex); - - //calculate the stable debt until the last timestamp update - vars.cumulatedStableInterest = MathUtils.calculateCompoundedInterest( - vars.avgStableRate, - vars.stableSupplyUpdatedTimestamp, - timestamp - ); - - vars.previousStableDebt = vars.principalStableDebt.rayMul(vars.cumulatedStableInterest); - - //debt accrued is the sum of the current debt minus the sum of the debt at the last update - vars.totalDebtAccrued = vars - .currentVariableDebt - .add(vars.currentStableDebt) - .sub(vars.previousVariableDebt) - .sub(vars.previousStableDebt); - - vars.amountToMint = vars.totalDebtAccrued.percentMul(vars.reserveFactor); - - if (vars.amountToMint != 0) { - IAToken(reserve.aTokenAddress).mintToTreasury(vars.amountToMint, newLiquidityIndex); - } - } - - /** - * @dev Updates the reserve indexes and the timestamp of the update - * @param reserve The reserve reserve to be updated - * @param scaledVariableDebt The scaled variable debt - * @param liquidityIndex The last stored liquidity index - * @param variableBorrowIndex The last stored variable borrow index - **/ - function _updateIndexes( - DataTypes.ReserveData storage reserve, - uint256 scaledVariableDebt, - uint256 liquidityIndex, - uint256 variableBorrowIndex, - uint40 timestamp - ) internal returns (uint256, uint256) { - uint256 currentLiquidityRate = reserve.currentLiquidityRate; - - uint256 newLiquidityIndex = liquidityIndex; - uint256 newVariableBorrowIndex = variableBorrowIndex; - - //only cumulating if there is any income being produced - if (currentLiquidityRate > 0) { - uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest( - currentLiquidityRate, - timestamp - ); - newLiquidityIndex = cumulatedLiquidityInterest.rayMul(liquidityIndex); - require(newLiquidityIndex <= type(uint128).max, Errors.RL_LIQUIDITY_INDEX_OVERFLOW); - - reserve.liquidityIndex = uint128(newLiquidityIndex); - - //as the liquidity rate might come only from stable rate loans, we need to ensure - //that there is actual variable debt before accumulating - if (scaledVariableDebt != 0) { - uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest( - reserve.currentVariableBorrowRate, - timestamp - ); - newVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(variableBorrowIndex); - require( - newVariableBorrowIndex <= type(uint128).max, - Errors.RL_VARIABLE_BORROW_INDEX_OVERFLOW - ); - reserve.variableBorrowIndex = uint128(newVariableBorrowIndex); - } - } - - //solium-disable-next-line - reserve.lastUpdateTimestamp = uint40(block.timestamp); - return (newLiquidityIndex, newVariableBorrowIndex); - } -} - -/**LI - * @title GenericLogic library - * @author Aave - * @title Implements protocol-level logic to calculate and validate the state of a user - */ -library GenericLogic { - using ReserveLogic for DataTypes.ReserveData; - using SafeMath for uint256; - using WadRayMath for uint256; - using PercentageMath for uint256; - using ReserveConfiguration for DataTypes.ReserveConfigurationMap; - using UserConfiguration for DataTypes.UserConfigurationMap; - - uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1 ether; - - struct balanceDecreaseAllowedLocalVars { - uint256 decimals; - uint256 liquidationThreshold; - uint256 totalCollateralInETH; - uint256 totalDebtInETH; - uint256 avgLiquidationThreshold; - uint256 amountToDecreaseInETH; - uint256 collateralBalanceAfterDecrease; - uint256 liquidationThresholdAfterDecrease; - uint256 healthFactorAfterDecrease; - bool reserveUsageAsCollateralEnabled; - } - - /** - * @dev Checks if a specific balance decrease is allowed - * (i.e. doesn't bring the user borrow position health factor under HEALTH_FACTOR_LIQUIDATION_THRESHOLD) - * @param asset The address of the underlying asset of the reserve - * @param user The address of the user - * @param amount The amount to decrease - * @param reservesData The data of all the reserves - * @param userConfig The user configuration - * @param reserves The list of all the active reserves - * @param oracle The address of the oracle contract - * @return true if the decrease of the balance is allowed - **/ - function balanceDecreaseAllowed( - address asset, - address user, - uint256 amount, - mapping(address => DataTypes.ReserveData) storage reservesData, - DataTypes.UserConfigurationMap calldata userConfig, - mapping(uint256 => address) storage reserves, - uint256 reservesCount, - address oracle - ) external view returns (bool) { - if (!userConfig.isBorrowingAny() || !userConfig.isUsingAsCollateral(reservesData[asset].id)) { - return true; - } - - balanceDecreaseAllowedLocalVars memory vars; - - (, vars.liquidationThreshold, , vars.decimals, ) = reservesData[asset] - .configuration - .getParams(); - - if (vars.liquidationThreshold == 0) { - return true; - } - - ( - vars.totalCollateralInETH, - vars.totalDebtInETH, - , - vars.avgLiquidationThreshold, - - ) = calculateUserAccountData(user, reservesData, userConfig, reserves, reservesCount, oracle); - - if (vars.totalDebtInETH == 0) { - return true; - } - - vars.amountToDecreaseInETH = IPriceOracleGetter(oracle).getAssetPrice(asset).mul(amount).div( - 10**vars.decimals - ); - - vars.collateralBalanceAfterDecrease = vars.totalCollateralInETH.sub(vars.amountToDecreaseInETH); - - //if there is a borrow, there can't be 0 collateral - if (vars.collateralBalanceAfterDecrease == 0) { - return false; - } - - vars.liquidationThresholdAfterDecrease = vars - .totalCollateralInETH - .mul(vars.avgLiquidationThreshold) - .sub(vars.amountToDecreaseInETH.mul(vars.liquidationThreshold)) - .div(vars.collateralBalanceAfterDecrease); - - uint256 healthFactorAfterDecrease = calculateHealthFactorFromBalances( - vars.collateralBalanceAfterDecrease, - vars.totalDebtInETH, - vars.liquidationThresholdAfterDecrease - ); - - return healthFactorAfterDecrease >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD; - } - - struct CalculateUserAccountDataVars { - uint256 reserveUnitPrice; - uint256 tokenUnit; - uint256 compoundedLiquidityBalance; - uint256 compoundedBorrowBalance; - uint256 decimals; - uint256 ltv; - uint256 liquidationThreshold; - uint256 i; - uint256 healthFactor; - uint256 totalCollateralInETH; - uint256 totalDebtInETH; - uint256 avgLtv; - uint256 avgLiquidationThreshold; - uint256 reservesLength; - bool healthFactorBelowThreshold; - address currentReserveAddress; - bool usageAsCollateralEnabled; - bool userUsesReserveAsCollateral; - } - - /** - * @dev Calculates the user data across the reserves. - * this includes the total liquidity/collateral/borrow balances in ETH, - * the average Loan To Value, the average Liquidation Ratio, and the Health factor. - * @param user The address of the user - * @param reservesData Data of all the reserves - * @param userConfig The configuration of the user - * @param reserves The list of the available reserves - * @param oracle The price oracle address - * @return The total collateral and total debt of the user in ETH, the avg ltv, liquidation threshold and the HF - **/ - function calculateUserAccountData( - address user, - mapping(address => DataTypes.ReserveData) storage reservesData, - DataTypes.UserConfigurationMap memory userConfig, - mapping(uint256 => address) storage reserves, - uint256 reservesCount, - address oracle - ) - internal - view - returns ( - uint256, - uint256, - uint256, - uint256, - uint256 - ) - { - CalculateUserAccountDataVars memory vars; - - if (userConfig.isEmpty()) { - return (0, 0, 0, 0, uint256(-1)); - } - for (vars.i = 0; vars.i < reservesCount; vars.i++) { - if (!userConfig.isUsingAsCollateralOrBorrowing(vars.i)) { - continue; - } - - vars.currentReserveAddress = reserves[vars.i]; - DataTypes.ReserveData storage currentReserve = reservesData[vars.currentReserveAddress]; - - (vars.ltv, vars.liquidationThreshold, , vars.decimals, ) = currentReserve - .configuration - .getParams(); - - vars.tokenUnit = 10**vars.decimals; - vars.reserveUnitPrice = IPriceOracleGetter(oracle).getAssetPrice(vars.currentReserveAddress); - - if (vars.liquidationThreshold != 0 && userConfig.isUsingAsCollateral(vars.i)) { - vars.compoundedLiquidityBalance = IERC20(currentReserve.aTokenAddress).balanceOf(user); - - uint256 liquidityBalanceETH = vars - .reserveUnitPrice - .mul(vars.compoundedLiquidityBalance) - .div(vars.tokenUnit); - - vars.totalCollateralInETH = vars.totalCollateralInETH.add(liquidityBalanceETH); - - vars.avgLtv = vars.avgLtv.add(liquidityBalanceETH.mul(vars.ltv)); - vars.avgLiquidationThreshold = vars.avgLiquidationThreshold.add( - liquidityBalanceETH.mul(vars.liquidationThreshold) - ); - } - - if (userConfig.isBorrowing(vars.i)) { - vars.compoundedBorrowBalance = IERC20(currentReserve.stableDebtTokenAddress).balanceOf( - user - ); - vars.compoundedBorrowBalance = vars.compoundedBorrowBalance.add( - IERC20(currentReserve.variableDebtTokenAddress).balanceOf(user) - ); - - vars.totalDebtInETH = vars.totalDebtInETH.add( - vars.reserveUnitPrice.mul(vars.compoundedBorrowBalance).div(vars.tokenUnit) - ); - } - } - - vars.avgLtv = vars.totalCollateralInETH > 0 ? vars.avgLtv.div(vars.totalCollateralInETH) : 0; - vars.avgLiquidationThreshold = vars.totalCollateralInETH > 0 - ? vars.avgLiquidationThreshold.div(vars.totalCollateralInETH) - : 0; - - vars.healthFactor = calculateHealthFactorFromBalances( - vars.totalCollateralInETH, - vars.totalDebtInETH, - vars.avgLiquidationThreshold - ); - return ( - vars.totalCollateralInETH, - vars.totalDebtInETH, - vars.avgLtv, - vars.avgLiquidationThreshold, - vars.healthFactor - ); - } - - /** - * @dev Calculates the health factor from the corresponding balances - * @param totalCollateralInETH The total collateral in ETH - * @param totalDebtInETH The total debt in ETH - * @param liquidationThreshold The avg liquidation threshold - * @return The health factor calculated from the balances provided - **/ - function calculateHealthFactorFromBalances( - uint256 totalCollateralInETH, - uint256 totalDebtInETH, - uint256 liquidationThreshold - ) internal pure returns (uint256) { - if (totalDebtInETH == 0) return uint256(-1); - - return (totalCollateralInETH.percentMul(liquidationThreshold)).wadDiv(totalDebtInETH); - } - - /** - * @dev Calculates the equivalent amount in ETH that an user can borrow, depending on the available collateral and the - * average Loan To Value - * @param totalCollateralInETH The total collateral in ETH - * @param totalDebtInETH The total borrow balance - * @param ltv The average loan to value - * @return the amount available to borrow in ETH for the user - **/ - - function calculateAvailableBorrowsETH( - uint256 totalCollateralInETH, - uint256 totalDebtInETH, - uint256 ltv - ) internal pure returns (uint256) { - uint256 availableBorrowsETH = totalCollateralInETH.percentMul(ltv); - - if (availableBorrowsETH < totalDebtInETH) { - return 0; - } - - availableBorrowsETH = availableBorrowsETH.sub(totalDebtInETH); - return availableBorrowsETH; - } -} - -/** - * @title ReserveLogic library - * @author Aave - * @notice Implements functions to validate the different actions of the protocol - */ -library ValidationLogic { - using ReserveLogic for DataTypes.ReserveData; - using SafeMath for uint256; - using WadRayMath for uint256; - using PercentageMath for uint256; - using SafeERC20 for IERC20; - using ReserveConfiguration for DataTypes.ReserveConfigurationMap; - using UserConfiguration for DataTypes.UserConfigurationMap; - - uint256 public constant REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD = 4000; - uint256 public constant REBALANCE_UP_USAGE_RATIO_THRESHOLD = 0.95 * 1e27; //usage ratio of 95% - - /** - * @dev Validates a deposit action - * @param reserve The reserve object on which the user is depositing - * @param amount The amount to be deposited - */ - function validateDeposit(DataTypes.ReserveData storage reserve, uint256 amount) external view { - (bool isActive, bool isFrozen, , ) = reserve.configuration.getFlags(); - - require(amount != 0, Errors.VL_INVALID_AMOUNT); - require(isActive, Errors.VL_NO_ACTIVE_RESERVE); - require(!isFrozen, Errors.VL_RESERVE_FROZEN); - } - - /** - * @dev Validates a withdraw action - * @param reserveAddress The address of the reserve - * @param amount The amount to be withdrawn - * @param userBalance The balance of the user - * @param reservesData The reserves state - * @param userConfig The user configuration - * @param reserves The addresses of the reserves - * @param reservesCount The number of reserves - * @param oracle The price oracle - */ - function validateWithdraw( - address reserveAddress, - uint256 amount, - uint256 userBalance, - mapping(address => DataTypes.ReserveData) storage reservesData, - DataTypes.UserConfigurationMap storage userConfig, - mapping(uint256 => address) storage reserves, - uint256 reservesCount, - address oracle - ) external view { - require(amount != 0, Errors.VL_INVALID_AMOUNT); - require(amount <= userBalance, Errors.VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE); - - (bool isActive, , , ) = reservesData[reserveAddress].configuration.getFlags(); - require(isActive, Errors.VL_NO_ACTIVE_RESERVE); - - require( - GenericLogic.balanceDecreaseAllowed( - reserveAddress, - msg.sender, - amount, - reservesData, - userConfig, - reserves, - reservesCount, - oracle - ), - Errors.VL_TRANSFER_NOT_ALLOWED - ); - } - - struct ValidateBorrowLocalVars { - uint256 currentLtv; - uint256 currentLiquidationThreshold; - uint256 amountOfCollateralNeededETH; - uint256 userCollateralBalanceETH; - uint256 userBorrowBalanceETH; - uint256 availableLiquidity; - uint256 healthFactor; - bool isActive; - bool isFrozen; - bool borrowingEnabled; - bool stableRateBorrowingEnabled; - } - - /** - * @dev Validates a borrow action - * @param asset The address of the asset to borrow - * @param reserve The reserve state from which the user is borrowing - * @param userAddress The address of the user - * @param amount The amount to be borrowed - * @param amountInETH The amount to be borrowed, in ETH - * @param interestRateMode The interest rate mode at which the user is borrowing - * @param maxStableLoanPercent The max amount of the liquidity that can be borrowed at stable rate, in percentage - * @param reservesData The state of all the reserves - * @param userConfig The state of the user for the specific reserve - * @param reserves The addresses of all the active reserves - * @param oracle The price oracle - */ - - function validateBorrow( - address asset, - DataTypes.ReserveData storage reserve, - address userAddress, - uint256 amount, - uint256 amountInETH, - uint256 interestRateMode, - uint256 maxStableLoanPercent, - mapping(address => DataTypes.ReserveData) storage reservesData, - DataTypes.UserConfigurationMap storage userConfig, - mapping(uint256 => address) storage reserves, - uint256 reservesCount, - address oracle - ) external view { - ValidateBorrowLocalVars memory vars; - - (vars.isActive, vars.isFrozen, vars.borrowingEnabled, vars.stableRateBorrowingEnabled) = reserve - .configuration - .getFlags(); - - require(vars.isActive, Errors.VL_NO_ACTIVE_RESERVE); - require(!vars.isFrozen, Errors.VL_RESERVE_FROZEN); - require(amount != 0, Errors.VL_INVALID_AMOUNT); - - require(vars.borrowingEnabled, Errors.VL_BORROWING_NOT_ENABLED); - - //validate interest rate mode - require( - uint256(DataTypes.InterestRateMode.VARIABLE) == interestRateMode || - uint256(DataTypes.InterestRateMode.STABLE) == interestRateMode, - Errors.VL_INVALID_INTEREST_RATE_MODE_SELECTED - ); - - ( - vars.userCollateralBalanceETH, - vars.userBorrowBalanceETH, - vars.currentLtv, - vars.currentLiquidationThreshold, - vars.healthFactor - ) = GenericLogic.calculateUserAccountData( - userAddress, - reservesData, - userConfig, - reserves, - reservesCount, - oracle - ); - - require(vars.userCollateralBalanceETH > 0, Errors.VL_COLLATERAL_BALANCE_IS_0); - - require( - vars.healthFactor > GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, - Errors.VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD - ); - - //add the current already borrowed amount to the amount requested to calculate the total collateral needed. - vars.amountOfCollateralNeededETH = vars.userBorrowBalanceETH.add(amountInETH).percentDiv( - vars.currentLtv - ); //LTV is calculated in percentage - - require( - vars.amountOfCollateralNeededETH <= vars.userCollateralBalanceETH, - Errors.VL_COLLATERAL_CANNOT_COVER_NEW_BORROW - ); - - /** - * Following conditions need to be met if the user is borrowing at a stable rate: - * 1. Reserve must be enabled for stable rate borrowing - * 2. Users cannot borrow from the reserve if their collateral is (mostly) the same currency - * they are borrowing, to prevent abuses. - * 3. Users will be able to borrow only a portion of the total available liquidity - **/ - - if (interestRateMode == uint256(DataTypes.InterestRateMode.STABLE)) { - //check if the borrow mode is stable and if stable rate borrowing is enabled on this reserve - - require(vars.stableRateBorrowingEnabled, Errors.VL_STABLE_BORROWING_NOT_ENABLED); - - require( - !userConfig.isUsingAsCollateral(reserve.id) || - reserve.configuration.getLtv() == 0 || - amount > IERC20(reserve.aTokenAddress).balanceOf(userAddress), - Errors.VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY - ); - - vars.availableLiquidity = IERC20(asset).balanceOf(reserve.aTokenAddress); - - //calculate the max available loan size in stable rate mode as a percentage of the - //available liquidity - uint256 maxLoanSizeStable = vars.availableLiquidity.percentMul(maxStableLoanPercent); - - require(amount <= maxLoanSizeStable, Errors.VL_AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE); - } - } - - /** - * @dev Validates a repay action - * @param reserve The reserve state from which the user is repaying - * @param amountSent The amount sent for the repayment. Can be an actual value or uint(-1) - * @param onBehalfOf The address of the user msg.sender is repaying for - * @param stableDebt The borrow balance of the user - * @param variableDebt The borrow balance of the user - */ - function validateRepay( - DataTypes.ReserveData storage reserve, - uint256 amountSent, - DataTypes.InterestRateMode rateMode, - address onBehalfOf, - uint256 stableDebt, - uint256 variableDebt - ) external view { - bool isActive = reserve.configuration.getActive(); - - require(isActive, Errors.VL_NO_ACTIVE_RESERVE); - - require(amountSent > 0, Errors.VL_INVALID_AMOUNT); - - require( - (stableDebt > 0 && - DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.STABLE) || - (variableDebt > 0 && - DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.VARIABLE), - Errors.VL_NO_DEBT_OF_SELECTED_TYPE - ); - - require( - amountSent != uint256(-1) || msg.sender == onBehalfOf, - Errors.VL_NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF - ); - } - - /** - * @dev Validates a swap of borrow rate mode. - * @param reserve The reserve state on which the user is swapping the rate - * @param userConfig The user reserves configuration - * @param stableDebt The stable debt of the user - * @param variableDebt The variable debt of the user - * @param currentRateMode The rate mode of the borrow - */ - function validateSwapRateMode( - DataTypes.ReserveData storage reserve, - DataTypes.UserConfigurationMap storage userConfig, - uint256 stableDebt, - uint256 variableDebt, - DataTypes.InterestRateMode currentRateMode - ) external view { - (bool isActive, bool isFrozen, , bool stableRateEnabled) = reserve.configuration.getFlags(); - - require(isActive, Errors.VL_NO_ACTIVE_RESERVE); - require(!isFrozen, Errors.VL_RESERVE_FROZEN); - - if (currentRateMode == DataTypes.InterestRateMode.STABLE) { - require(stableDebt > 0, Errors.VL_NO_STABLE_RATE_LOAN_IN_RESERVE); - } else if (currentRateMode == DataTypes.InterestRateMode.VARIABLE) { - require(variableDebt > 0, Errors.VL_NO_VARIABLE_RATE_LOAN_IN_RESERVE); - /** - * user wants to swap to stable, before swapping we need to ensure that - * 1. stable borrow rate is enabled on the reserve - * 2. user is not trying to abuse the reserve by depositing - * more collateral than he is borrowing, artificially lowering - * the interest rate, borrowing at variable, and switching to stable - **/ - require(stableRateEnabled, Errors.VL_STABLE_BORROWING_NOT_ENABLED); - - require( - !userConfig.isUsingAsCollateral(reserve.id) || - reserve.configuration.getLtv() == 0 || - stableDebt.add(variableDebt) > IERC20(reserve.aTokenAddress).balanceOf(msg.sender), - Errors.VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY - ); - } else { - revert(Errors.VL_INVALID_INTEREST_RATE_MODE_SELECTED); - } - } - - /** - * @dev Validates a stable borrow rate rebalance action - * @param reserve The reserve state on which the user is getting rebalanced - * @param reserveAddress The address of the reserve - * @param stableDebtToken The stable debt token instance - * @param variableDebtToken The variable debt token instance - * @param aTokenAddress The address of the aToken contract - */ - function validateRebalanceStableBorrowRate( - DataTypes.ReserveData storage reserve, - address reserveAddress, - IERC20 stableDebtToken, - IERC20 variableDebtToken, - address aTokenAddress - ) external view { - (bool isActive, , , ) = reserve.configuration.getFlags(); - - require(isActive, Errors.VL_NO_ACTIVE_RESERVE); - - //if the usage ratio is below 95%, no rebalances are needed - uint256 totalDebt = stableDebtToken - .totalSupply() - .add(variableDebtToken.totalSupply()) - .wadToRay(); - uint256 availableLiquidity = IERC20(reserveAddress).balanceOf(aTokenAddress).wadToRay(); - uint256 usageRatio = totalDebt == 0 ? 0 : totalDebt.rayDiv(availableLiquidity.add(totalDebt)); - - //if the liquidity rate is below REBALANCE_UP_THRESHOLD of the max variable APR at 95% usage, - //then we allow rebalancing of the stable rate positions. - - uint256 currentLiquidityRate = reserve.currentLiquidityRate; - uint256 maxVariableBorrowRate = IReserveInterestRateStrategy( - reserve.interestRateStrategyAddress - ).getMaxVariableBorrowRate(); - - require( - usageRatio >= REBALANCE_UP_USAGE_RATIO_THRESHOLD && - currentLiquidityRate <= - maxVariableBorrowRate.percentMul(REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD), - Errors.LP_INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET - ); - } - - /** - * @dev Validates the action of setting an asset as collateral - * @param reserve The state of the reserve that the user is enabling or disabling as collateral - * @param reserveAddress The address of the reserve - * @param reservesData The data of all the reserves - * @param userConfig The state of the user for the specific reserve - * @param reserves The addresses of all the active reserves - * @param oracle The price oracle - */ - function validateSetUseReserveAsCollateral( - DataTypes.ReserveData storage reserve, - address reserveAddress, - bool useAsCollateral, - mapping(address => DataTypes.ReserveData) storage reservesData, - DataTypes.UserConfigurationMap storage userConfig, - mapping(uint256 => address) storage reserves, - uint256 reservesCount, - address oracle - ) external view { - uint256 underlyingBalance = IERC20(reserve.aTokenAddress).balanceOf(msg.sender); - - require(underlyingBalance > 0, Errors.VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0); - - require( - useAsCollateral || - GenericLogic.balanceDecreaseAllowed( - reserveAddress, - msg.sender, - underlyingBalance, - reservesData, - userConfig, - reserves, - reservesCount, - oracle - ), - Errors.VL_DEPOSIT_ALREADY_IN_USE - ); - } - - /** - * @dev Validates a flashloan action - * @param assets The assets being flashborrowed - * @param amounts The amounts for each asset being borrowed - **/ - function validateFlashloan(address[] memory assets, uint256[] memory amounts) internal pure { - require(assets.length == amounts.length, Errors.VL_INCONSISTENT_FLASHLOAN_PARAMS); - } - - /** - * @dev Validates the liquidation action - * @param collateralReserve The reserve data of the collateral - * @param principalReserve The reserve data of the principal - * @param userConfig The user configuration - * @param userHealthFactor The user's health factor - * @param userStableDebt Total stable debt balance of the user - * @param userVariableDebt Total variable debt balance of the user - **/ - function validateLiquidationCall( - DataTypes.ReserveData storage collateralReserve, - DataTypes.ReserveData storage principalReserve, - DataTypes.UserConfigurationMap storage userConfig, - uint256 userHealthFactor, - uint256 userStableDebt, - uint256 userVariableDebt - ) internal view returns (uint256, string memory) { - if ( - !collateralReserve.configuration.getActive() || !principalReserve.configuration.getActive() - ) { - return ( - uint256(Errors.CollateralManagerErrors.NO_ACTIVE_RESERVE), - Errors.VL_NO_ACTIVE_RESERVE - ); - } - - if (userHealthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD) { - return ( - uint256(Errors.CollateralManagerErrors.HEALTH_FACTOR_ABOVE_THRESHOLD), - Errors.LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD - ); - } - - bool isCollateralEnabled = collateralReserve.configuration.getLiquidationThreshold() > 0 && - userConfig.isUsingAsCollateral(collateralReserve.id); - - //if collateral isn't enabled as collateral by user, it cannot be liquidated - if (!isCollateralEnabled) { - return ( - uint256(Errors.CollateralManagerErrors.COLLATERAL_CANNOT_BE_LIQUIDATED), - Errors.LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED - ); - } - - if (userStableDebt == 0 && userVariableDebt == 0) { - return ( - uint256(Errors.CollateralManagerErrors.CURRRENCY_NOT_BORROWED), - Errors.LPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER - ); - } - - return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.LPCM_NO_ERRORS); - } - - /** - * @dev Validates an aToken transfer - * @param from The user from which the aTokens are being transferred - * @param reservesData The state of all the reserves - * @param userConfig The state of the user for the specific reserve - * @param reserves The addresses of all the active reserves - * @param oracle The price oracle - */ - function validateTransfer( - address from, - mapping(address => DataTypes.ReserveData) storage reservesData, - DataTypes.UserConfigurationMap storage userConfig, - mapping(uint256 => address) storage reserves, - uint256 reservesCount, - address oracle - ) internal view { - (, , , , uint256 healthFactor) = GenericLogic.calculateUserAccountData( - from, - reservesData, - userConfig, - reserves, - reservesCount, - oracle - ); - - require( - healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, - Errors.VL_TRANSFER_NOT_ALLOWED - ); - } -} - -contract LendingPoolStorage { - using ReserveLogic for DataTypes.ReserveData; - using ReserveConfiguration for DataTypes.ReserveConfigurationMap; - using UserConfiguration for DataTypes.UserConfigurationMap; - - ILendingPoolAddressesProvider internal _addressesProvider; - - mapping(address => DataTypes.ReserveData) internal _reserves; - mapping(address => DataTypes.UserConfigurationMap) internal _usersConfig; - - // the list of the available reserves, structured as a mapping for gas savings reasons - mapping(uint256 => address) internal _reservesList; - - uint256 internal _reservesCount; - - bool internal _paused; - - uint256 internal _maxStableRateBorrowSizePercent; - - uint256 internal _flashLoanPremiumTotal; - - uint256 internal _maxNumberOfReserves; -} - -/** - * @title LendingPool contract - * @dev Main point of interaction with an Aave protocol's market - * - Users can: - * # Deposit - * # Withdraw - * # Borrow - * # Repay - * # Swap their loans between variable and stable rate - * # Enable/disable their deposits as collateral rebalance stable rate borrow positions - * # Liquidate positions - * # Execute Flash Loans - * - To be covered by a proxy contract, owned by the LendingPoolAddressesProvider of the specific market - * - All admin functions are callable by the LendingPoolConfigurator contract defined also in the - * LendingPoolAddressesProvider - * @author Aave - **/ -contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage { - using SafeMath for uint256; - using WadRayMath for uint256; - using PercentageMath for uint256; - using SafeERC20 for IERC20; - - uint256 public constant LENDINGPOOL_REVISION = 0x2; - - modifier whenNotPaused() { - _whenNotPaused(); - _; - } - - modifier onlyLendingPoolConfigurator() { - _onlyLendingPoolConfigurator(); - _; - } - - function _whenNotPaused() internal view { - require(!_paused, Errors.LP_IS_PAUSED); - } - - function _onlyLendingPoolConfigurator() internal view { - require( - _addressesProvider.getLendingPoolConfigurator() == msg.sender, - Errors.LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR - ); - } - - function getRevision() internal pure override returns (uint256) { - return LENDINGPOOL_REVISION; - } - - /** - * @dev Function is invoked by the proxy contract when the LendingPool contract is added to the - * LendingPoolAddressesProvider of the market. - * - Caching the address of the LendingPoolAddressesProvider in order to reduce gas consumption - * on subsequent operations - * @param provider The address of the LendingPoolAddressesProvider - **/ - function initialize(ILendingPoolAddressesProvider provider) public initializer { - _addressesProvider = provider; - _maxStableRateBorrowSizePercent = 2500; - _flashLoanPremiumTotal = 9; - _maxNumberOfReserves = 128; - } - - /** - * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. - * - E.g. User deposits 100 USDC and gets in return 100 aUSDC - * @param asset The address of the underlying asset to deposit - * @param amount The amount to be deposited - * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user - * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens - * is a different wallet - * @param referralCode Code used to register the integrator originating the operation, for potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - **/ - function deposit( - address asset, - uint256 amount, - address onBehalfOf, - uint16 referralCode - ) external override whenNotPaused { - DataTypes.ReserveData storage reserve = _reserves[asset]; - - ValidationLogic.validateDeposit(reserve, amount); - - address aToken = reserve.aTokenAddress; - - reserve.updateState(); - reserve.updateInterestRates(asset, aToken, amount, 0); - - IERC20(asset).safeTransferFrom(msg.sender, aToken, amount); - - bool isFirstDeposit = IAToken(aToken).mint(onBehalfOf, amount, reserve.liquidityIndex); - - if (isFirstDeposit) { - _usersConfig[onBehalfOf].setUsingAsCollateral(reserve.id, true); - emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf); - } - - emit Deposit(asset, msg.sender, onBehalfOf, amount, referralCode); - } - - /** - * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned - * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC - * @param asset The address of the underlying asset to withdraw - * @param amount The underlying amount to be withdrawn - * - Send the value type(uint256).max in order to withdraw the whole aToken balance - * @param to Address that will receive the underlying, same as msg.sender if the user - * wants to receive it on his own wallet, or a different address if the beneficiary is a - * different wallet - * @return The final amount withdrawn - **/ - function withdraw( - address asset, - uint256 amount, - address to - ) external override whenNotPaused returns (uint256) { - DataTypes.ReserveData storage reserve = _reserves[asset]; - - address aToken = reserve.aTokenAddress; - - uint256 userBalance = IAToken(aToken).balanceOf(msg.sender); - - uint256 amountToWithdraw = amount; - - if (amount == type(uint256).max) { - amountToWithdraw = userBalance; - } - - ValidationLogic.validateWithdraw( - asset, - amountToWithdraw, - userBalance, - _reserves, - _usersConfig[msg.sender], - _reservesList, - _reservesCount, - _addressesProvider.getPriceOracle() - ); - - reserve.updateState(); - - reserve.updateInterestRates(asset, aToken, 0, amountToWithdraw); - - if (amountToWithdraw == userBalance) { - _usersConfig[msg.sender].setUsingAsCollateral(reserve.id, false); - emit ReserveUsedAsCollateralDisabled(asset, msg.sender); - } - - IAToken(aToken).burn(msg.sender, to, amountToWithdraw, reserve.liquidityIndex); - - emit Withdraw(asset, msg.sender, to, amountToWithdraw); - - return amountToWithdraw; - } - - /** - * @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower - * already deposited enough collateral, or he was given enough allowance by a credit delegator on the - * corresponding debt token (StableDebtToken or VariableDebtToken) - * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet - * and 100 stable/variable debt tokens, depending on the `interestRateMode` - * @param asset The address of the underlying asset to borrow - * @param amount The amount to be borrowed - * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable - * @param referralCode Code used to register the integrator originating the operation, for potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - * @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself - * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator - * if he has been given credit delegation allowance - **/ - function borrow( - address asset, - uint256 amount, - uint256 interestRateMode, - uint16 referralCode, - address onBehalfOf - ) external override whenNotPaused { - DataTypes.ReserveData storage reserve = _reserves[asset]; - - _executeBorrow( - ExecuteBorrowParams( - asset, - msg.sender, - onBehalfOf, - amount, - interestRateMode, - reserve.aTokenAddress, - referralCode, - true - ) - ); - } - - /** - * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned - * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address - * @param asset The address of the borrowed underlying asset previously borrowed - * @param amount The amount to repay - * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` - * @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable - * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the - * user calling the function if he wants to reduce/remove his own debt, or the address of any other - * other borrower whose debt should be removed - * @return The final amount repaid - **/ - function repay( - address asset, - uint256 amount, - uint256 rateMode, - address onBehalfOf - ) external override whenNotPaused returns (uint256) { - DataTypes.ReserveData storage reserve = _reserves[asset]; - - (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve); - - DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode); - - ValidationLogic.validateRepay( - reserve, - amount, - interestRateMode, - onBehalfOf, - stableDebt, - variableDebt - ); - - uint256 paybackAmount = interestRateMode == DataTypes.InterestRateMode.STABLE - ? stableDebt - : variableDebt; - - if (amount < paybackAmount) { - paybackAmount = amount; - } - - reserve.updateState(); - - if (interestRateMode == DataTypes.InterestRateMode.STABLE) { - IStableDebtToken(reserve.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount); - } else { - IVariableDebtToken(reserve.variableDebtTokenAddress).burn( - onBehalfOf, - paybackAmount, - reserve.variableBorrowIndex - ); - } - - address aToken = reserve.aTokenAddress; - reserve.updateInterestRates(asset, aToken, paybackAmount, 0); - - if (stableDebt.add(variableDebt).sub(paybackAmount) == 0) { - _usersConfig[onBehalfOf].setBorrowing(reserve.id, false); - } - - IERC20(asset).safeTransferFrom(msg.sender, aToken, paybackAmount); - - IAToken(aToken).handleRepayment(msg.sender, paybackAmount); - - emit Repay(asset, onBehalfOf, msg.sender, paybackAmount); - - return paybackAmount; - } - - /** - * @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa - * @param asset The address of the underlying asset borrowed - * @param rateMode The rate mode that the user wants to swap to - **/ - function swapBorrowRateMode(address asset, uint256 rateMode) external override whenNotPaused { - DataTypes.ReserveData storage reserve = _reserves[asset]; - - (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve); - - DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode); - - ValidationLogic.validateSwapRateMode( - reserve, - _usersConfig[msg.sender], - stableDebt, - variableDebt, - interestRateMode - ); - - reserve.updateState(); - - if (interestRateMode == DataTypes.InterestRateMode.STABLE) { - IStableDebtToken(reserve.stableDebtTokenAddress).burn(msg.sender, stableDebt); - IVariableDebtToken(reserve.variableDebtTokenAddress).mint( - msg.sender, - msg.sender, - stableDebt, - reserve.variableBorrowIndex - ); - } else { - IVariableDebtToken(reserve.variableDebtTokenAddress).burn( - msg.sender, - variableDebt, - reserve.variableBorrowIndex - ); - IStableDebtToken(reserve.stableDebtTokenAddress).mint( - msg.sender, - msg.sender, - variableDebt, - reserve.currentStableBorrowRate - ); - } - - reserve.updateInterestRates(asset, reserve.aTokenAddress, 0, 0); - - emit Swap(asset, msg.sender, rateMode); - } - - /** - * @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve. - * - Users can be rebalanced if the following conditions are satisfied: - * 1. Usage ratio is above 95% - * 2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been - * borrowed at a stable rate and depositors are not earning enough - * @param asset The address of the underlying asset borrowed - * @param user The address of the user to be rebalanced - **/ - function rebalanceStableBorrowRate(address asset, address user) external override whenNotPaused { - DataTypes.ReserveData storage reserve = _reserves[asset]; - - IERC20 stableDebtToken = IERC20(reserve.stableDebtTokenAddress); - IERC20 variableDebtToken = IERC20(reserve.variableDebtTokenAddress); - address aTokenAddress = reserve.aTokenAddress; - - uint256 stableDebt = IERC20(stableDebtToken).balanceOf(user); - - ValidationLogic.validateRebalanceStableBorrowRate( - reserve, - asset, - stableDebtToken, - variableDebtToken, - aTokenAddress - ); - - reserve.updateState(); - - IStableDebtToken(address(stableDebtToken)).burn(user, stableDebt); - IStableDebtToken(address(stableDebtToken)).mint( - user, - user, - stableDebt, - reserve.currentStableBorrowRate - ); - - reserve.updateInterestRates(asset, aTokenAddress, 0, 0); - - emit RebalanceStableBorrowRate(asset, user); - } - - /** - * @dev Allows depositors to enable/disable a specific deposited asset as collateral - * @param asset The address of the underlying asset deposited - * @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise - **/ - function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) - external - override - whenNotPaused - { - DataTypes.ReserveData storage reserve = _reserves[asset]; - - ValidationLogic.validateSetUseReserveAsCollateral( - reserve, - asset, - useAsCollateral, - _reserves, - _usersConfig[msg.sender], - _reservesList, - _reservesCount, - _addressesProvider.getPriceOracle() - ); - - _usersConfig[msg.sender].setUsingAsCollateral(reserve.id, useAsCollateral); - - if (useAsCollateral) { - emit ReserveUsedAsCollateralEnabled(asset, msg.sender); - } else { - emit ReserveUsedAsCollateralDisabled(asset, msg.sender); - } - } - - /** - * @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1 - * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives - * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk - * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation - * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation - * @param user The address of the borrower getting liquidated - * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover - * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants - * to receive the underlying collateral asset directly - **/ - function liquidationCall( - address collateralAsset, - address debtAsset, - address user, - uint256 debtToCover, - bool receiveAToken - ) external override whenNotPaused { - address collateralManager = _addressesProvider.getLendingPoolCollateralManager(); - - //solium-disable-next-line - (bool success, bytes memory result) = collateralManager.delegatecall( - abi.encodeWithSignature( - 'liquidationCall(address,address,address,uint256,bool)', - collateralAsset, - debtAsset, - user, - debtToCover, - receiveAToken - ) - ); - - require(success, Errors.LP_LIQUIDATION_CALL_FAILED); - - (uint256 returnCode, string memory returnMessage) = abi.decode(result, (uint256, string)); - - require(returnCode == 0, string(abi.encodePacked(returnMessage))); - } - - struct FlashLoanLocalVars { - IFlashLoanReceiver receiver; - address oracle; - uint256 i; - address currentAsset; - address currentATokenAddress; - uint256 currentAmount; - uint256 currentPremium; - uint256 currentAmountPlusPremium; - address debtToken; - } - - /** - * @dev Allows smartcontracts to access the liquidity of the pool within one transaction, - * as long as the amount taken plus a fee is returned. - * IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration. - * For further details please visit https://developers.aave.com - * @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface - * @param assets The addresses of the assets being flash-borrowed - * @param amounts The amounts amounts being flash-borrowed - * @param modes Types of the debt to open if the flash loan is not returned: - * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver - * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address - * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address - * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2 - * @param params Variadic packed params to pass to the receiver as extra information - * @param referralCode Code used to register the integrator originating the operation, for potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - **/ - function flashLoan( - address receiverAddress, - address[] calldata assets, - uint256[] calldata amounts, - uint256[] calldata modes, - address onBehalfOf, - bytes calldata params, - uint16 referralCode - ) external override whenNotPaused { - FlashLoanLocalVars memory vars; - - ValidationLogic.validateFlashloan(assets, amounts); - - address[] memory aTokenAddresses = new address[](assets.length); - uint256[] memory premiums = new uint256[](assets.length); - - vars.receiver = IFlashLoanReceiver(receiverAddress); - - for (vars.i = 0; vars.i < assets.length; vars.i++) { - aTokenAddresses[vars.i] = _reserves[assets[vars.i]].aTokenAddress; - - premiums[vars.i] = amounts[vars.i].mul(_flashLoanPremiumTotal).div(10000); - - IAToken(aTokenAddresses[vars.i]).transferUnderlyingTo(receiverAddress, amounts[vars.i]); - } - - require( - vars.receiver.executeOperation(assets, amounts, premiums, msg.sender, params), - Errors.LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN - ); - - for (vars.i = 0; vars.i < assets.length; vars.i++) { - vars.currentAsset = assets[vars.i]; - vars.currentAmount = amounts[vars.i]; - vars.currentPremium = premiums[vars.i]; - vars.currentATokenAddress = aTokenAddresses[vars.i]; - vars.currentAmountPlusPremium = vars.currentAmount.add(vars.currentPremium); - - if (DataTypes.InterestRateMode(modes[vars.i]) == DataTypes.InterestRateMode.NONE) { - _reserves[vars.currentAsset].updateState(); - _reserves[vars.currentAsset].cumulateToLiquidityIndex( - IERC20(vars.currentATokenAddress).totalSupply(), - vars.currentPremium - ); - _reserves[vars.currentAsset].updateInterestRates( - vars.currentAsset, - vars.currentATokenAddress, - vars.currentAmountPlusPremium, - 0 - ); - - IERC20(vars.currentAsset).safeTransferFrom( - receiverAddress, - vars.currentATokenAddress, - vars.currentAmountPlusPremium - ); - } else { - // If the user chose to not return the funds, the system checks if there is enough collateral and - // eventually opens a debt position - _executeBorrow( - ExecuteBorrowParams( - vars.currentAsset, - msg.sender, - onBehalfOf, - vars.currentAmount, - modes[vars.i], - vars.currentATokenAddress, - referralCode, - false - ) - ); - } - emit FlashLoan( - receiverAddress, - msg.sender, - vars.currentAsset, - vars.currentAmount, - vars.currentPremium, - referralCode - ); - } - } - - /** - * @dev Returns the state and configuration of the reserve - * @param asset The address of the underlying asset of the reserve - * @return The state of the reserve - **/ - function getReserveData(address asset) - external - view - override - returns (DataTypes.ReserveData memory) - { - return _reserves[asset]; - } - - /** - * @dev Returns the user account data across all the reserves - * @param user The address of the user - * @return totalCollateralETH the total collateral in ETH of the user - * @return totalDebtETH the total debt in ETH of the user - * @return availableBorrowsETH the borrowing power left of the user - * @return currentLiquidationThreshold the liquidation threshold of the user - * @return ltv the loan to value of the user - * @return healthFactor the current health factor of the user - **/ - function getUserAccountData(address user) - external - view - override - returns ( - uint256 totalCollateralETH, - uint256 totalDebtETH, - uint256 availableBorrowsETH, - uint256 currentLiquidationThreshold, - uint256 ltv, - uint256 healthFactor - ) - { - ( - totalCollateralETH, - totalDebtETH, - ltv, - currentLiquidationThreshold, - healthFactor - ) = GenericLogic.calculateUserAccountData( - user, - _reserves, - _usersConfig[user], - _reservesList, - _reservesCount, - _addressesProvider.getPriceOracle() - ); - - availableBorrowsETH = GenericLogic.calculateAvailableBorrowsETH( - totalCollateralETH, - totalDebtETH, - ltv - ); - } - - /** - * @dev Returns the configuration of the reserve - * @param asset The address of the underlying asset of the reserve - * @return The configuration of the reserve - **/ - function getConfiguration(address asset) - external - view - override - returns (DataTypes.ReserveConfigurationMap memory) - { - return _reserves[asset].configuration; - } - - /** - * @dev Returns the configuration of the user across all the reserves - * @param user The user address - * @return The configuration of the user - **/ - function getUserConfiguration(address user) - external - view - override - returns (DataTypes.UserConfigurationMap memory) - { - return _usersConfig[user]; - } - - /** - * @dev Returns the normalized income per unit of asset - * @param asset The address of the underlying asset of the reserve - * @return The reserve's normalized income - */ - function getReserveNormalizedIncome(address asset) - external - view - virtual - override - returns (uint256) - { - return _reserves[asset].getNormalizedIncome(); - } - - /** - * @dev Returns the normalized variable debt per unit of asset - * @param asset The address of the underlying asset of the reserve - * @return The reserve normalized variable debt - */ - function getReserveNormalizedVariableDebt(address asset) - external - view - override - returns (uint256) - { - return _reserves[asset].getNormalizedDebt(); - } - - /** - * @dev Returns if the LendingPool is paused - */ - function paused() external view override returns (bool) { - return _paused; - } - - /** - * @dev Returns the list of the initialized reserves - **/ - function getReservesList() external view override returns (address[] memory) { - address[] memory _activeReserves = new address[](_reservesCount); - - for (uint256 i = 0; i < _reservesCount; i++) { - _activeReserves[i] = _reservesList[i]; - } - return _activeReserves; - } - - /** - * @dev Returns the cached LendingPoolAddressesProvider connected to this contract - **/ - function getAddressesProvider() external view override returns (ILendingPoolAddressesProvider) { - return _addressesProvider; - } - - /** - * @dev Returns the percentage of available liquidity that can be borrowed at once at stable rate - */ - function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() public view returns (uint256) { - return _maxStableRateBorrowSizePercent; - } - - /** - * @dev Returns the fee on flash loans - */ - function FLASHLOAN_PREMIUM_TOTAL() public view returns (uint256) { - return _flashLoanPremiumTotal; - } - - /** - * @dev Returns the maximum number of reserves supported to be listed in this LendingPool - */ - function MAX_NUMBER_RESERVES() public view returns (uint256) { - return _maxNumberOfReserves; - } - - /** - * @dev Validates and finalizes an aToken transfer - * - Only callable by the overlying aToken of the `asset` - * @param asset The address of the underlying asset of the aToken - * @param from The user from which the aTokens are transferred - * @param to The user receiving the aTokens - * @param amount The amount being transferred/withdrawn - * @param balanceFromBefore The aToken balance of the `from` user before the transfer - * @param balanceToBefore The aToken balance of the `to` user before the transfer - */ - function finalizeTransfer( - address asset, - address from, - address to, - uint256 amount, - uint256 balanceFromBefore, - uint256 balanceToBefore - ) external override whenNotPaused { - require(msg.sender == _reserves[asset].aTokenAddress, Errors.LP_CALLER_MUST_BE_AN_ATOKEN); - - ValidationLogic.validateTransfer( - from, - _reserves, - _usersConfig[from], - _reservesList, - _reservesCount, - _addressesProvider.getPriceOracle() - ); - - uint256 reserveId = _reserves[asset].id; - - if (from != to) { - if (balanceFromBefore.sub(amount) == 0) { - DataTypes.UserConfigurationMap storage fromConfig = _usersConfig[from]; - fromConfig.setUsingAsCollateral(reserveId, false); - emit ReserveUsedAsCollateralDisabled(asset, from); - } - - if (balanceToBefore == 0 && amount != 0) { - DataTypes.UserConfigurationMap storage toConfig = _usersConfig[to]; - toConfig.setUsingAsCollateral(reserveId, true); - emit ReserveUsedAsCollateralEnabled(asset, to); - } - } - } - - /** - * @dev Initializes a reserve, activating it, assigning an aToken and debt tokens and an - * interest rate strategy - * - Only callable by the LendingPoolConfigurator contract - * @param asset The address of the underlying asset of the reserve - * @param aTokenAddress The address of the aToken that will be assigned to the reserve - * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the reserve - * @param aTokenAddress The address of the VariableDebtToken that will be assigned to the reserve - * @param interestRateStrategyAddress The address of the interest rate strategy contract - **/ - function initReserve( - address asset, - address aTokenAddress, - address stableDebtAddress, - address variableDebtAddress, - address interestRateStrategyAddress - ) external override onlyLendingPoolConfigurator { - require(Address.isContract(asset), Errors.LP_NOT_CONTRACT); - _reserves[asset].init( - aTokenAddress, - stableDebtAddress, - variableDebtAddress, - interestRateStrategyAddress - ); - _addReserveToList(asset); - } - - /** - * @dev Updates the address of the interest rate strategy contract - * - Only callable by the LendingPoolConfigurator contract - * @param asset The address of the underlying asset of the reserve - * @param rateStrategyAddress The address of the interest rate strategy contract - **/ - function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress) - external - override - onlyLendingPoolConfigurator - { - _reserves[asset].interestRateStrategyAddress = rateStrategyAddress; - } - - /** - * @dev Sets the configuration bitmap of the reserve as a whole - * - Only callable by the LendingPoolConfigurator contract - * @param asset The address of the underlying asset of the reserve - * @param configuration The new configuration bitmap - **/ - function setConfiguration(address asset, uint256 configuration) - external - override - onlyLendingPoolConfigurator - { - _reserves[asset].configuration.data = configuration; - } - - /** - * @dev Set the _pause state of a reserve - * - Only callable by the LendingPoolConfigurator contract - * @param val `true` to pause the reserve, `false` to un-pause it - */ - function setPause(bool val) external override onlyLendingPoolConfigurator { - _paused = val; - if (_paused) { - emit Paused(); - } else { - emit Unpaused(); - } - } - - struct ExecuteBorrowParams { - address asset; - address user; - address onBehalfOf; - uint256 amount; - uint256 interestRateMode; - address aTokenAddress; - uint16 referralCode; - bool releaseUnderlying; - } - - function _executeBorrow(ExecuteBorrowParams memory vars) internal { - DataTypes.ReserveData storage reserve = _reserves[vars.asset]; - DataTypes.UserConfigurationMap storage userConfig = _usersConfig[vars.onBehalfOf]; - - address oracle = _addressesProvider.getPriceOracle(); - - uint256 amountInETH = IPriceOracleGetter(oracle).getAssetPrice(vars.asset).mul(vars.amount).div( - 10**reserve.configuration.getDecimals() - ); - - ValidationLogic.validateBorrow( - vars.asset, - reserve, - vars.onBehalfOf, - vars.amount, - amountInETH, - vars.interestRateMode, - _maxStableRateBorrowSizePercent, - _reserves, - userConfig, - _reservesList, - _reservesCount, - oracle - ); - - reserve.updateState(); - - uint256 currentStableRate = 0; - - bool isFirstBorrowing = false; - if (DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE) { - currentStableRate = reserve.currentStableBorrowRate; - - isFirstBorrowing = IStableDebtToken(reserve.stableDebtTokenAddress).mint( - vars.user, - vars.onBehalfOf, - vars.amount, - currentStableRate - ); - } else { - isFirstBorrowing = IVariableDebtToken(reserve.variableDebtTokenAddress).mint( - vars.user, - vars.onBehalfOf, - vars.amount, - reserve.variableBorrowIndex - ); - } - - if (isFirstBorrowing) { - userConfig.setBorrowing(reserve.id, true); - } - - reserve.updateInterestRates( - vars.asset, - vars.aTokenAddress, - 0, - vars.releaseUnderlying ? vars.amount : 0 - ); - - if (vars.releaseUnderlying) { - IAToken(vars.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount); - } - - emit Borrow( - vars.asset, - vars.user, - vars.onBehalfOf, - vars.amount, - vars.interestRateMode, - DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE - ? currentStableRate - : reserve.currentVariableBorrowRate, - vars.referralCode - ); - } - - function _addReserveToList(address asset) internal { - uint256 reservesCount = _reservesCount; - - require(reservesCount < _maxNumberOfReserves, Errors.LP_NO_MORE_RESERVES_ALLOWED); - - bool reserveAlreadyAdded = _reserves[asset].id != 0 || _reservesList[0] == asset; - - if (!reserveAlreadyAdded) { - _reserves[asset].id = uint8(reservesCount); - _reservesList[reservesCount] = asset; - - _reservesCount = reservesCount + 1; - } - } -} From 52c75bbf1f5721c48c0bbd0eea85f4e498687419 Mon Sep 17 00:00:00 2001 From: x-moola Date: Fri, 17 Jun 2022 13:57:58 -0700 Subject: [PATCH 07/11] Update cli --- cli.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli.js b/cli.js index 0d1a8205..d03ab0e9 100644 --- a/cli.js +++ b/cli.js @@ -246,7 +246,7 @@ async function execute(network, action, ...params) { let cREAL; let MOO; let UBE; - let WETH; + let GNT; let migrator; let privateKeyRequired = true; let liquiditySwapAdapter; @@ -267,7 +267,7 @@ async function execute(network, action, ...params) { cREAL = new kit.web3.eth.Contract(MToken, '0xE4D517785D091D3c54818832dB6094bcc2744545'); MOO = new kit.web3.eth.Contract(MToken, '0x17700282592D6917F6A73D0bF8AcCf4D578c131e'); UBE = new kit.web3.eth.Contract(MToken, '0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC'); - WETH = new kit.web3.eth.Contract(MToken, '0xDe37f36C9c045164CE89D3cEaeC67949EfACC398'); + GNT = new kit.web3.eth.Contract(MToken, '0xcd8148C6f63C1559a1f95962569a915AA7907Eb7'); CELO = new kit.web3.eth.Contract(MToken, '0xF194afDf50B03e69Bd7D057c1Aa9e10c9954E4C9'); dataProvider = new kit.web3.eth.Contract( DataProvider, @@ -304,7 +304,7 @@ async function execute(network, action, ...params) { cREAL = new kit.web3.eth.Contract(MToken, '0xe8537a3d056DA446677B9E9d6c5dB704EaAb4787'); MOO = new kit.web3.eth.Contract(MToken, '0x17700282592D6917F6A73D0bF8AcCf4D578c131e'); UBE = new kit.web3.eth.Contract(MToken, '0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC'); - WETH = new kit.web3.eth.Contract(MToken, '0x122013fd7dF1C6F636a5bb8f03108E876548b455'); + GNT = new kit.web3.eth.Contract(MToken, '0x16FDA7073b085e0231824499345c7334a68f7783'); CELO = new kit.web3.eth.Contract(MToken, '0x471EcE3750Da237f93B8E339c536989b8978a438'); dataProvider = new kit.web3.eth.Contract( DataProvider, @@ -392,7 +392,7 @@ async function execute(network, action, ...params) { creal: cREAL, moo: MOO, ube: UBE, - weth: WETH, + gnt: GNT, }; const reserves = { From 881a3113553dc60f4dab85fce22c1b5d3a70d99c Mon Sep 17 00:00:00 2001 From: x-moola Date: Fri, 17 Jun 2022 13:59:04 -0700 Subject: [PATCH 08/11] Remove pre-commit hook changes --- contracts/adapters/BaseUniswapAdapter.sol | 29 ++++--- contracts/adapters/LeverageBorrowAdapter.sol | 8 +- .../contracts/OptimizedSafeERC20.sol | 82 ++++++------------- helpers/contracts-helpers.ts | 8 +- .../uniswapAdapters.leverageBorrow.spec.ts | 17 +--- 5 files changed, 50 insertions(+), 94 deletions(-) diff --git a/contracts/adapters/BaseUniswapAdapter.sol b/contracts/adapters/BaseUniswapAdapter.sol index 99f7c0f0..823031b6 100644 --- a/contracts/adapters/BaseUniswapAdapter.sol +++ b/contracts/adapters/BaseUniswapAdapter.sol @@ -144,24 +144,23 @@ abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapt address swapTo ) internal returns (uint256) { { - uint256 expectedMinAmountOut = amountToSwap - .mul(_getPrice(assetToSwapFromPrice).mul(10**_getDecimals(assetToSwapToPrice))) - .div(_getPrice(assetToSwapToPrice).mul(10**_getDecimals(assetToSwapFromPrice))) - .percentMul(PercentageMath.PERCENTAGE_FACTOR.sub(MAX_SLIPPAGE_PERCENT)); + uint256 expectedMinAmountOut = amountToSwap + .mul(_getPrice(assetToSwapFromPrice).mul(10**_getDecimals(assetToSwapToPrice))) + .div(_getPrice(assetToSwapToPrice).mul(10**_getDecimals(assetToSwapFromPrice))) + .percentMul(PercentageMath.PERCENTAGE_FACTOR.sub(MAX_SLIPPAGE_PERCENT)); - require(expectedMinAmountOut < minAmountOut, 'minAmountOut exceed max slippage'); + require(expectedMinAmountOut < minAmountOut, 'minAmountOut exceed max slippage'); } - return - _swapExactTokensForTokensNoPriceCheck( - assetToSwapFrom, - assetToSwapTo, - amountToSwap, - minAmountOut, - useEthPath, - aTokenExist, - swapTo - ); + return _swapExactTokensForTokensNoPriceCheck( + assetToSwapFrom, + assetToSwapTo, + amountToSwap, + minAmountOut, + useEthPath, + aTokenExist, + swapTo + ); } function _swapExactTokensForTokensNoPriceCheck( diff --git a/contracts/adapters/LeverageBorrowAdapter.sol b/contracts/adapters/LeverageBorrowAdapter.sol index dba4e705..21678ace 100644 --- a/contracts/adapters/LeverageBorrowAdapter.sol +++ b/contracts/adapters/LeverageBorrowAdapter.sol @@ -50,9 +50,9 @@ contract LeverageBorrowAdapter is BaseUniswapAdapter { 'leverageParams length does not match to assets length' ); - for (uint256 i = 0; i < assets.length; i++) { + for (uint i = 0; i < assets.length; i++) { LeverageParams memory leverageParams = leverageParamsArr[i]; - uint256 amountIn = amounts[i]; + uint amountIn = amounts[i]; address asset = assets[i]; if (leverageParams.useATokenAsFrom) { _deposit(asset, amountIn, address(this)); @@ -62,9 +62,7 @@ contract LeverageBorrowAdapter is BaseUniswapAdapter { // reusing amountIn amountIn = _swapExactTokensForTokensNoPriceCheck( leverageParams.useATokenAsFrom ? _getReserveData(asset).aTokenAddress : asset, - leverageParams.useATokenAsTo - ? _getReserveData(leverageParams.toAsset).aTokenAddress - : leverageParams.toAsset, + leverageParams.useATokenAsTo ? _getReserveData(leverageParams.toAsset).aTokenAddress : leverageParams.toAsset, amountIn, leverageParams.minAmountOut, leverageParams.useEthPath, diff --git a/contracts/dependencies/openzeppelin/contracts/OptimizedSafeERC20.sol b/contracts/dependencies/openzeppelin/contracts/OptimizedSafeERC20.sol index 61c825e8..1397539c 100644 --- a/contracts/dependencies/openzeppelin/contracts/OptimizedSafeERC20.sol +++ b/contracts/dependencies/openzeppelin/contracts/OptimizedSafeERC20.sol @@ -16,65 +16,37 @@ import {IERC20} from './IERC20.sol'; * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library OptimizedSafeERC20 { - function safeTransfer( - IERC20 token, - address to, - uint256 value, - bytes memory errPrefix - ) internal { - require( - _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)), - string(abi.encodePacked(errPrefix, 'ERC20 transfer failed')) - ); - } - - function safeTransferFrom( - IERC20 token, - address from, - address to, - uint256 value, - bytes memory errPrefix - ) internal { - require( - _callOptionalReturn( - token, - abi.encodeWithSelector(token.transferFrom.selector, from, to, value) - ), - string(abi.encodePacked(errPrefix, 'ERC20 transferFrom failed')) - ); - } - - function safeApprove( - IERC20 token, - address spender, - uint256 value, - bytes memory errPrefix - ) internal { - if ( - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)) - ) { - return; + function safeTransfer(IERC20 token, address to, uint256 value, bytes memory errPrefix) internal { + require(_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)), + string(abi.encodePacked(errPrefix, 'ERC20 transfer failed'))); } - require( - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)) && - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)), - string(abi.encodePacked(errPrefix, 'ERC20 approve failed')) - ); - } - function _callOptionalReturn(IERC20 token, bytes memory data) private returns (bool) { - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory returndata) = address(token).call(data); - if (!success) { - return false; + function safeTransferFrom(IERC20 token, address from, address to, uint256 value, bytes memory errPrefix) internal { + require(_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)), + string(abi.encodePacked(errPrefix, 'ERC20 transferFrom failed'))); } - if (returndata.length >= 32) { - // Return data is optional - return abi.decode(returndata, (bool)); + function safeApprove(IERC20 token, address spender, uint256 value, bytes memory errPrefix) internal { + if (_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value))) { + return; + } + require(_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)) + && _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)), + string(abi.encodePacked(errPrefix, 'ERC20 approve failed'))); } - // In a wierd case when return data is 1-31 bytes long - return false. - return returndata.length == 0; - } + function _callOptionalReturn(IERC20 token, bytes memory data) private returns(bool) { + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = address(token).call(data); + if (!success) { + return false; + } + + if (returndata.length >= 32) { // Return data is optional + return abi.decode(returndata, (bool)); + } + + // In a wierd case when return data is 1-31 bytes long - return false. + return returndata.length == 0; + } } diff --git a/helpers/contracts-helpers.ts b/helpers/contracts-helpers.ts index cdfc3329..ad26ddc1 100644 --- a/helpers/contracts-helpers.ts +++ b/helpers/contracts-helpers.ts @@ -361,13 +361,9 @@ interface LeverageBorrowAdapter { minAmountOut: BigNumberish; } -export const buildLeverageBorrowAdapterParams = ( - leverageBorrowAdapterParamsArr: LeverageBorrowAdapter[] -) => { +export const buildLeverageBorrowAdapterParams = (leverageBorrowAdapterParamsArr: LeverageBorrowAdapter[]) => { return ethers.utils.defaultAbiCoder.encode( - [ - 'tuple(bool useATokenAsFrom, bool useATokenAsTo, bool useEthPath, address toAsset, uint256 minAmountOut)[]', - ], + ['tuple(bool useATokenAsFrom, bool useATokenAsTo, bool useEthPath, address toAsset, uint256 minAmountOut)[]'], [leverageBorrowAdapterParamsArr] ); }; diff --git a/test-suites/test-aave/uniswapAdapters.leverageBorrow.spec.ts b/test-suites/test-aave/uniswapAdapters.leverageBorrow.spec.ts index 8388e572..6a905acc 100644 --- a/test-suites/test-aave/uniswapAdapters.leverageBorrow.spec.ts +++ b/test-suites/test-aave/uniswapAdapters.leverageBorrow.spec.ts @@ -96,8 +96,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { const ten = ethers.BigNumber.from(10); it('should correctly swap token and deposit', async () => { - const { users, pool, weth, aWETH, dai, oracle, leverageBorrowAdapter, helpersContract } = - testEnv; + const { users, pool, weth, aWETH, dai, oracle, leverageBorrowAdapter, helpersContract } = testEnv; const user = users[0].signer; const userAddress = users[0].address; @@ -124,13 +123,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { await mockUniswapRouter.connect(user).setAmountToReturn(dai.address, liquidityToSwap); const params = buildLeverageBorrowAdapterParams([ - { - useATokenAsFrom: false, - useATokenAsTo: false, - useEthPath: false, - toAsset: weth.address, - minAmountOut: liquidityToSwap, - }, + { useATokenAsFrom: false, useATokenAsTo: false, useEthPath: false, toAsset: weth.address, minAmountOut: liquidityToSwap }, ]); await expect( @@ -163,8 +156,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { }); it('should correctly swap tokens(2 or more) and deposit', async () => { - const { users, pool, weth, aWETH, dai, oracle, leverageBorrowAdapter, helpersContract } = - testEnv; + const { users, pool, weth, aWETH, dai, oracle, leverageBorrowAdapter, helpersContract } = testEnv; const user = users[0].signer; const userAddress = users[0].address; @@ -233,8 +225,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { }); it('should correctly swap token and deposit with variable mode', async () => { - const { users, pool, weth, aWETH, dai, oracle, leverageBorrowAdapter, helpersContract } = - testEnv; + const { users, pool, weth, aWETH, dai, oracle, leverageBorrowAdapter, helpersContract } = testEnv; const user = users[0].signer; const userAddress = users[0].address; From bbde42df15c2ad8e350107252e1f97efa6871c9f Mon Sep 17 00:00:00 2001 From: x-moola Date: Mon, 20 Jun 2022 14:46:39 -0700 Subject: [PATCH 09/11] Add PACT --- cli.js | 7 ++ .../PACT/PACTConfiguratorAlfajores.sol | 94 +++++++++++++++++++ .../lendingpool/PACT/PACTConfiguratorCelo.sol | 94 +++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 contracts/protocol/lendingpool/PACT/PACTConfiguratorAlfajores.sol create mode 100644 contracts/protocol/lendingpool/PACT/PACTConfiguratorCelo.sol diff --git a/cli.js b/cli.js index d03ab0e9..464ad632 100644 --- a/cli.js +++ b/cli.js @@ -247,6 +247,7 @@ async function execute(network, action, ...params) { let MOO; let UBE; let GNT; + let PACT; let migrator; let privateKeyRequired = true; let liquiditySwapAdapter; @@ -268,6 +269,7 @@ async function execute(network, action, ...params) { MOO = new kit.web3.eth.Contract(MToken, '0x17700282592D6917F6A73D0bF8AcCf4D578c131e'); UBE = new kit.web3.eth.Contract(MToken, '0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC'); GNT = new kit.web3.eth.Contract(MToken, '0xcd8148C6f63C1559a1f95962569a915AA7907Eb7'); + PACT = new kit.web3.eth.Contract(MToken, '0x73A2De6A8370108D43c3C80430C84c30df323eD2'); CELO = new kit.web3.eth.Contract(MToken, '0xF194afDf50B03e69Bd7D057c1Aa9e10c9954E4C9'); dataProvider = new kit.web3.eth.Contract( DataProvider, @@ -305,6 +307,7 @@ async function execute(network, action, ...params) { MOO = new kit.web3.eth.Contract(MToken, '0x17700282592D6917F6A73D0bF8AcCf4D578c131e'); UBE = new kit.web3.eth.Contract(MToken, '0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC'); GNT = new kit.web3.eth.Contract(MToken, '0x16FDA7073b085e0231824499345c7334a68f7783'); + PACT = new kit.web3.eth.Contract(MToken, '0x46c9757C5497c5B1f2eb73aE79b6B67D119B0B58'); CELO = new kit.web3.eth.Contract(MToken, '0x471EcE3750Da237f93B8E339c536989b8978a438'); dataProvider = new kit.web3.eth.Contract( DataProvider, @@ -393,6 +396,7 @@ async function execute(network, action, ...params) { moo: MOO, ube: UBE, gnt: GNT, + pact: PACT, }; const reserves = { @@ -401,6 +405,9 @@ async function execute(network, action, ...params) { ceur: cEUR.options.address, creal: cREAL.options.address, moo: MOO.options.address, + gnt: GNT.options.address, + pact: PACT.options.address, + ube: UBE.options.address, }; const isValidAsset = (asset) => { diff --git a/contracts/protocol/lendingpool/PACT/PACTConfiguratorAlfajores.sol b/contracts/protocol/lendingpool/PACT/PACTConfiguratorAlfajores.sol new file mode 100644 index 00000000..995b5b4f --- /dev/null +++ b/contracts/protocol/lendingpool/PACT/PACTConfiguratorAlfajores.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {ERC20} from '../../../dependencies/openzeppelin/contracts/ERC20.sol'; +import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol'; +import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; +import '../../../interfaces/ILendingPoolConfigurator.sol'; + +contract PACTConfiguratorAlfajores is Ownable { + address constant lendingPoolConfiguratorAddress = 0x39fe2A4a4174bB5cAC5568ce0715a0b320bcB231; + + LendingPoolConfigurator public lendingPoolConfigurator = + LendingPoolConfigurator(lendingPoolConfiguratorAddress); + address constant assetAddress = 0x73A2De6A8370108D43c3C80430C84c30df323eD2; + + bytes constant params = '0x10'; + bool constant stableBorrowRateEnabled = true; + uint8 constant underlyingAssetDecimals = 18; + address constant aTokenImpl = 0xe8B286649713447D8d5fBeBC28c731830d19B6C9; + address constant stableDebtTokenImpl = 0xB6a5059A228a16Fa2827E28E52ceC96BBC63D639; + address constant variableDebtTokenImpl = 0xB65b6a6a6F78E4daABF259c756567ae346699687; + address constant interestRateStrategyAddress = 0x3C06Fb2f5Ab65b0e35F91073d88afE2b017D04b8; + address constant treasury = 0x643C574128c7C56A1835e021Ad0EcC2592E72624; + address constant incentivesController = 0x0000000000000000000000000000000000000000; + string constant underlyingAssetName = 'impactMarket'; + string constant aTokenName = 'Moola interest bearing PACT'; + string constant aTokenSymbol = 'mPACT'; + string constant variableDebtTokenName = 'Moola variable debt bearing mPACT'; + string constant variableDebtTokenSymbol = 'variableDebtmPACT'; + string constant stableDebtTokenName = 'Moola stable debt bearing mPACT'; + string constant stableDebtTokenSymbol = 'stableDebtmPACT'; + uint256 constant baseLTV = 5000; + uint256 constant liquidationThreshold = 6500; + uint256 constant liquidationBonus = 11000; + uint256 constant reserveFactor = 1000; + + function execute() external onlyOwner { + createReserve(); + enableCollateral(); + enableBorrowing(); + setReserveFactor(); + + selfdestruct(payable(treasury)); + } + + function destruct() external onlyOwner { + selfdestruct(payable(treasury)); + } + + function createReserve() internal { + ILendingPoolConfigurator.InitReserveInput[] + memory inputs = new ILendingPoolConfigurator.InitReserveInput[](1); + ILendingPoolConfigurator.InitReserveInput memory input = ILendingPoolConfigurator + .InitReserveInput({ + aTokenImpl: aTokenImpl, + stableDebtTokenImpl: stableDebtTokenImpl, + variableDebtTokenImpl: variableDebtTokenImpl, + underlyingAssetDecimals: underlyingAssetDecimals, + interestRateStrategyAddress: interestRateStrategyAddress, + underlyingAsset: assetAddress, + treasury: treasury, + incentivesController: incentivesController, + underlyingAssetName: underlyingAssetName, + aTokenName: aTokenName, + aTokenSymbol: aTokenSymbol, + variableDebtTokenName: variableDebtTokenName, + variableDebtTokenSymbol: variableDebtTokenSymbol, + stableDebtTokenName: stableDebtTokenName, + stableDebtTokenSymbol: stableDebtTokenSymbol, + params: params + }); + inputs[0] = input; + + lendingPoolConfigurator.batchInitReserve(inputs); + } + + function enableCollateral() internal { + lendingPoolConfigurator.configureReserveAsCollateral( + assetAddress, + baseLTV, + liquidationThreshold, + liquidationBonus + ); + } + + function enableBorrowing() internal { + lendingPoolConfigurator.enableBorrowingOnReserve(assetAddress, stableBorrowRateEnabled); + } + + function setReserveFactor() internal { + lendingPoolConfigurator.setReserveFactor(assetAddress, reserveFactor); + } +} diff --git a/contracts/protocol/lendingpool/PACT/PACTConfiguratorCelo.sol b/contracts/protocol/lendingpool/PACT/PACTConfiguratorCelo.sol new file mode 100644 index 00000000..cd52da68 --- /dev/null +++ b/contracts/protocol/lendingpool/PACT/PACTConfiguratorCelo.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {ERC20} from '../../../dependencies/openzeppelin/contracts/ERC20.sol'; +import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol'; +import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; +import '../../../interfaces/ILendingPoolConfigurator.sol'; + +contract PACTConfiguratorCelo is Ownable { + address constant lendingPoolConfiguratorAddress = 0x39fe2A4a4174bB5cAC5568ce0715a0b320bcB231; + + LendingPoolConfigurator public lendingPoolConfigurator = + LendingPoolConfigurator(lendingPoolConfiguratorAddress); + address constant assetAddress = 0x46c9757C5497c5B1f2eb73aE79b6B67D119B0B58; + + bytes constant params = '0x10'; + bool constant stableBorrowRateEnabled = true; + uint8 constant underlyingAssetDecimals = 18; + address constant aTokenImpl = 0x55bFCED2451b2154e06604D4269c9349F31141e6; + address constant stableDebtTokenImpl = 0xaCdb7B3e2b0a038F1f4eF04736728E0065b689DA; + address constant variableDebtTokenImpl = 0x0301Cf8F1FCD9255BD32FB7e0fE5B3494f445C2C; + address constant interestRateStrategyAddress = 0x801443470c119F2eac65F13886D9e293CdecE2DF; + address constant treasury = 0x313bc86D3D6e86ba164B2B451cB0D9CfA7943e5c; + address constant incentivesController = 0x0000000000000000000000000000000000000000; + string constant underlyingAssetName = 'impactMarket'; + string constant aTokenName = 'Moola interest bearing PACT'; + string constant aTokenSymbol = 'mPACT'; + string constant variableDebtTokenName = 'Moola variable debt bearing mPACT'; + string constant variableDebtTokenSymbol = 'variableDebtmPACT'; + string constant stableDebtTokenName = 'Moola stable debt bearing mPACT'; + string constant stableDebtTokenSymbol = 'stableDebtmPACT'; + uint256 constant baseLTV = 5000; // TODO-- wait for params + uint256 constant liquidationThreshold = 6500; + uint256 constant liquidationBonus = 11000; + uint256 constant reserveFactor = 1000; + + function execute() external onlyOwner { + createReserve(); + enableCollateral(); + enableBorrowing(); + setReserveFactor(); + + selfdestruct(payable(treasury)); + } + + function destruct() external onlyOwner { + selfdestruct(payable(treasury)); + } + + function createReserve() internal { + ILendingPoolConfigurator.InitReserveInput[] + memory inputs = new ILendingPoolConfigurator.InitReserveInput[](1); + ILendingPoolConfigurator.InitReserveInput memory input = ILendingPoolConfigurator + .InitReserveInput({ + aTokenImpl: aTokenImpl, + stableDebtTokenImpl: stableDebtTokenImpl, + variableDebtTokenImpl: variableDebtTokenImpl, + underlyingAssetDecimals: underlyingAssetDecimals, + interestRateStrategyAddress: interestRateStrategyAddress, + underlyingAsset: assetAddress, + treasury: treasury, + incentivesController: incentivesController, + underlyingAssetName: underlyingAssetName, + aTokenName: aTokenName, + aTokenSymbol: aTokenSymbol, + variableDebtTokenName: variableDebtTokenName, + variableDebtTokenSymbol: variableDebtTokenSymbol, + stableDebtTokenName: stableDebtTokenName, + stableDebtTokenSymbol: stableDebtTokenSymbol, + params: params + }); + inputs[0] = input; + + lendingPoolConfigurator.batchInitReserve(inputs); + } + + function enableCollateral() internal { + lendingPoolConfigurator.configureReserveAsCollateral( + assetAddress, + baseLTV, + liquidationThreshold, + liquidationBonus + ); + } + + function enableBorrowing() internal { + lendingPoolConfigurator.enableBorrowingOnReserve(assetAddress, stableBorrowRateEnabled); + } + + function setReserveFactor() internal { + lendingPoolConfigurator.setReserveFactor(assetAddress, reserveFactor); + } +} From c2c3ef1a84c11336f816eeadf6bd71494a3c1aac Mon Sep 17 00:00:00 2001 From: x-moola Date: Mon, 20 Jun 2022 14:48:49 -0700 Subject: [PATCH 10/11] Temporarily remove celo configurators --- .../lendingpool/GNT/GNTConfiguratorCelo.sol | 94 ------------------- .../lendingpool/PACT/PACTConfiguratorCelo.sol | 94 ------------------- .../lendingpool/UBE/UBEConfiguratorCelo.sol | 94 ------------------- 3 files changed, 282 deletions(-) delete mode 100644 contracts/protocol/lendingpool/GNT/GNTConfiguratorCelo.sol delete mode 100644 contracts/protocol/lendingpool/PACT/PACTConfiguratorCelo.sol delete mode 100644 contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol diff --git a/contracts/protocol/lendingpool/GNT/GNTConfiguratorCelo.sol b/contracts/protocol/lendingpool/GNT/GNTConfiguratorCelo.sol deleted file mode 100644 index b0271bc4..00000000 --- a/contracts/protocol/lendingpool/GNT/GNTConfiguratorCelo.sol +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.12; -pragma experimental ABIEncoderV2; - -import {ERC20} from '../../../dependencies/openzeppelin/contracts/ERC20.sol'; -import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol'; -import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; -import '../../../interfaces/ILendingPoolConfigurator.sol'; - -contract GNTConfiguratorCelo is Ownable { - address constant lendingPoolConfiguratorAddress = 0x928F63a83217e427A84504950206834CBDa4Aa65; - - LendingPoolConfigurator public lendingPoolConfigurator = - LendingPoolConfigurator(lendingPoolConfiguratorAddress); - address constant assetAddress = 0x16FDA7073b085e0231824499345c7334a68f7783; - - bytes constant params = '0x10'; - bool constant stableBorrowRateEnabled = true; - uint8 constant underlyingAssetDecimals = 18; - address constant aTokenImpl = 0x55bFCED2451b2154e06604D4269c9349F31141e6; - address constant stableDebtTokenImpl = 0xaCdb7B3e2b0a038F1f4eF04736728E0065b689DA; - address constant variableDebtTokenImpl = 0x0301Cf8F1FCD9255BD32FB7e0fE5B3494f445C2C; - address constant interestRateStrategyAddress = 0x801443470c119F2eac65F13886D9e293CdecE2DF; - address constant treasury = 0x313bc86D3D6e86ba164B2B451cB0D9CfA7943e5c; - address constant incentivesController = 0x0000000000000000000000000000000000000000; - string constant underlyingAssetName = 'CarbonCreditBundleToken'; - string constant aTokenName = 'Moola interest bearing GNT'; - string constant aTokenSymbol = 'mGNT'; - string constant variableDebtTokenName = 'Moola variable debt bearing mGNT'; - string constant variableDebtTokenSymbol = 'variableDebtmGNT'; - string constant stableDebtTokenName = 'Moola stable debt bearing mGNT'; - string constant stableDebtTokenSymbol = 'stableDebtmGNT'; - uint256 constant baseLTV = 5000; // TODO: update after mainnet params are confirmed - uint256 constant liquidationThreshold = 6500; - uint256 constant liquidationBonus = 11000; - uint256 constant reserveFactor = 1000; - - function execute() external onlyOwner { - createReserve(); - enableCollateral(); - enableBorrowing(); - setReserveFactor(); - - selfdestruct(payable(treasury)); - } - - function destruct() external onlyOwner { - selfdestruct(payable(treasury)); - } - - function createReserve() internal { - ILendingPoolConfigurator.InitReserveInput[] - memory inputs = new ILendingPoolConfigurator.InitReserveInput[](1); - ILendingPoolConfigurator.InitReserveInput memory input = ILendingPoolConfigurator - .InitReserveInput({ - aTokenImpl: aTokenImpl, - stableDebtTokenImpl: stableDebtTokenImpl, - variableDebtTokenImpl: variableDebtTokenImpl, - underlyingAssetDecimals: underlyingAssetDecimals, - interestRateStrategyAddress: interestRateStrategyAddress, - underlyingAsset: assetAddress, - treasury: treasury, - incentivesController: incentivesController, - underlyingAssetName: underlyingAssetName, - aTokenName: aTokenName, - aTokenSymbol: aTokenSymbol, - variableDebtTokenName: variableDebtTokenName, - variableDebtTokenSymbol: variableDebtTokenSymbol, - stableDebtTokenName: stableDebtTokenName, - stableDebtTokenSymbol: stableDebtTokenSymbol, - params: params - }); - inputs[0] = input; - - lendingPoolConfigurator.batchInitReserve(inputs); - } - - function enableCollateral() internal { - lendingPoolConfigurator.configureReserveAsCollateral( - assetAddress, - baseLTV, - liquidationThreshold, - liquidationBonus - ); - } - - function enableBorrowing() internal { - lendingPoolConfigurator.enableBorrowingOnReserve(assetAddress, stableBorrowRateEnabled); - } - - function setReserveFactor() internal { - lendingPoolConfigurator.setReserveFactor(assetAddress, reserveFactor); - } -} diff --git a/contracts/protocol/lendingpool/PACT/PACTConfiguratorCelo.sol b/contracts/protocol/lendingpool/PACT/PACTConfiguratorCelo.sol deleted file mode 100644 index cd52da68..00000000 --- a/contracts/protocol/lendingpool/PACT/PACTConfiguratorCelo.sol +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.12; -pragma experimental ABIEncoderV2; - -import {ERC20} from '../../../dependencies/openzeppelin/contracts/ERC20.sol'; -import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol'; -import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; -import '../../../interfaces/ILendingPoolConfigurator.sol'; - -contract PACTConfiguratorCelo is Ownable { - address constant lendingPoolConfiguratorAddress = 0x39fe2A4a4174bB5cAC5568ce0715a0b320bcB231; - - LendingPoolConfigurator public lendingPoolConfigurator = - LendingPoolConfigurator(lendingPoolConfiguratorAddress); - address constant assetAddress = 0x46c9757C5497c5B1f2eb73aE79b6B67D119B0B58; - - bytes constant params = '0x10'; - bool constant stableBorrowRateEnabled = true; - uint8 constant underlyingAssetDecimals = 18; - address constant aTokenImpl = 0x55bFCED2451b2154e06604D4269c9349F31141e6; - address constant stableDebtTokenImpl = 0xaCdb7B3e2b0a038F1f4eF04736728E0065b689DA; - address constant variableDebtTokenImpl = 0x0301Cf8F1FCD9255BD32FB7e0fE5B3494f445C2C; - address constant interestRateStrategyAddress = 0x801443470c119F2eac65F13886D9e293CdecE2DF; - address constant treasury = 0x313bc86D3D6e86ba164B2B451cB0D9CfA7943e5c; - address constant incentivesController = 0x0000000000000000000000000000000000000000; - string constant underlyingAssetName = 'impactMarket'; - string constant aTokenName = 'Moola interest bearing PACT'; - string constant aTokenSymbol = 'mPACT'; - string constant variableDebtTokenName = 'Moola variable debt bearing mPACT'; - string constant variableDebtTokenSymbol = 'variableDebtmPACT'; - string constant stableDebtTokenName = 'Moola stable debt bearing mPACT'; - string constant stableDebtTokenSymbol = 'stableDebtmPACT'; - uint256 constant baseLTV = 5000; // TODO-- wait for params - uint256 constant liquidationThreshold = 6500; - uint256 constant liquidationBonus = 11000; - uint256 constant reserveFactor = 1000; - - function execute() external onlyOwner { - createReserve(); - enableCollateral(); - enableBorrowing(); - setReserveFactor(); - - selfdestruct(payable(treasury)); - } - - function destruct() external onlyOwner { - selfdestruct(payable(treasury)); - } - - function createReserve() internal { - ILendingPoolConfigurator.InitReserveInput[] - memory inputs = new ILendingPoolConfigurator.InitReserveInput[](1); - ILendingPoolConfigurator.InitReserveInput memory input = ILendingPoolConfigurator - .InitReserveInput({ - aTokenImpl: aTokenImpl, - stableDebtTokenImpl: stableDebtTokenImpl, - variableDebtTokenImpl: variableDebtTokenImpl, - underlyingAssetDecimals: underlyingAssetDecimals, - interestRateStrategyAddress: interestRateStrategyAddress, - underlyingAsset: assetAddress, - treasury: treasury, - incentivesController: incentivesController, - underlyingAssetName: underlyingAssetName, - aTokenName: aTokenName, - aTokenSymbol: aTokenSymbol, - variableDebtTokenName: variableDebtTokenName, - variableDebtTokenSymbol: variableDebtTokenSymbol, - stableDebtTokenName: stableDebtTokenName, - stableDebtTokenSymbol: stableDebtTokenSymbol, - params: params - }); - inputs[0] = input; - - lendingPoolConfigurator.batchInitReserve(inputs); - } - - function enableCollateral() internal { - lendingPoolConfigurator.configureReserveAsCollateral( - assetAddress, - baseLTV, - liquidationThreshold, - liquidationBonus - ); - } - - function enableBorrowing() internal { - lendingPoolConfigurator.enableBorrowingOnReserve(assetAddress, stableBorrowRateEnabled); - } - - function setReserveFactor() internal { - lendingPoolConfigurator.setReserveFactor(assetAddress, reserveFactor); - } -} diff --git a/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol b/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol deleted file mode 100644 index a3f43f7a..00000000 --- a/contracts/protocol/lendingpool/UBE/UBEConfiguratorCelo.sol +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.12; -pragma experimental ABIEncoderV2; - -import {ERC20} from '../../../dependencies/openzeppelin/contracts/ERC20.sol'; -import {Ownable} from '../../../dependencies/openzeppelin/contracts/Ownable.sol'; -import '../../../protocol/lendingpool/LendingPoolConfigurator.sol'; -import '../../../interfaces/ILendingPoolConfigurator.sol'; - -contract UBEConfiguratorCelo is Ownable { - address constant lendingPoolConfiguratorAddress = 0x39fe2A4a4174bB5cAC5568ce0715a0b320bcB231; - - LendingPoolConfigurator public lendingPoolConfigurator = - LendingPoolConfigurator(lendingPoolConfiguratorAddress); - address constant assetAddress = 0x00Be915B9dCf56a3CBE739D9B9c202ca692409EC; - - bytes constant params = '0x10'; - bool constant stableBorrowRateEnabled = true; - uint8 constant underlyingAssetDecimals = 18; - address constant aTokenImpl = 0x55bFCED2451b2154e06604D4269c9349F31141e6; - address constant stableDebtTokenImpl = 0xaCdb7B3e2b0a038F1f4eF04736728E0065b689DA; - address constant variableDebtTokenImpl = 0x0301Cf8F1FCD9255BD32FB7e0fE5B3494f445C2C; - address constant interestRateStrategyAddress = 0x801443470c119F2eac65F13886D9e293CdecE2DF; - address constant treasury = 0x313bc86D3D6e86ba164B2B451cB0D9CfA7943e5c; - address constant incentivesController = 0x0000000000000000000000000000000000000000; - string constant underlyingAssetName = 'Ubeswap'; - string constant aTokenName = 'Moola interest bearing UBE'; - string constant aTokenSymbol = 'mUBE'; - string constant variableDebtTokenName = 'Moola variable debt bearing mUBE'; - string constant variableDebtTokenSymbol = 'variableDebtmUBE'; - string constant stableDebtTokenName = 'Moola stable debt bearing mUBE'; - string constant stableDebtTokenSymbol = 'stableDebtmUBE'; - uint256 constant baseLTV = 5000; // TODO-- wait for params - uint256 constant liquidationThreshold = 6500; - uint256 constant liquidationBonus = 11000; - uint256 constant reserveFactor = 1000; - - function execute() external onlyOwner { - createReserve(); - enableCollateral(); - enableBorrowing(); - setReserveFactor(); - - selfdestruct(payable(treasury)); - } - - function destruct() external onlyOwner { - selfdestruct(payable(treasury)); - } - - function createReserve() internal { - ILendingPoolConfigurator.InitReserveInput[] - memory inputs = new ILendingPoolConfigurator.InitReserveInput[](1); - ILendingPoolConfigurator.InitReserveInput memory input = ILendingPoolConfigurator - .InitReserveInput({ - aTokenImpl: aTokenImpl, - stableDebtTokenImpl: stableDebtTokenImpl, - variableDebtTokenImpl: variableDebtTokenImpl, - underlyingAssetDecimals: underlyingAssetDecimals, - interestRateStrategyAddress: interestRateStrategyAddress, - underlyingAsset: assetAddress, - treasury: treasury, - incentivesController: incentivesController, - underlyingAssetName: underlyingAssetName, - aTokenName: aTokenName, - aTokenSymbol: aTokenSymbol, - variableDebtTokenName: variableDebtTokenName, - variableDebtTokenSymbol: variableDebtTokenSymbol, - stableDebtTokenName: stableDebtTokenName, - stableDebtTokenSymbol: stableDebtTokenSymbol, - params: params - }); - inputs[0] = input; - - lendingPoolConfigurator.batchInitReserve(inputs); - } - - function enableCollateral() internal { - lendingPoolConfigurator.configureReserveAsCollateral( - assetAddress, - baseLTV, - liquidationThreshold, - liquidationBonus - ); - } - - function enableBorrowing() internal { - lendingPoolConfigurator.enableBorrowingOnReserve(assetAddress, stableBorrowRateEnabled); - } - - function setReserveFactor() internal { - lendingPoolConfigurator.setReserveFactor(assetAddress, reserveFactor); - } -} From 5120e34131c59e1d7fe72b444071eff19181d172 Mon Sep 17 00:00:00 2001 From: x-moola Date: Tue, 21 Jun 2022 13:52:19 -0700 Subject: [PATCH 11/11] Update alfajores params --- .../protocol/lendingpool/GNT/GNTConfiguratorAlfajores.sol | 4 ++-- .../protocol/lendingpool/PACT/PACTConfiguratorAlfajores.sol | 6 +++--- .../protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/contracts/protocol/lendingpool/GNT/GNTConfiguratorAlfajores.sol b/contracts/protocol/lendingpool/GNT/GNTConfiguratorAlfajores.sol index e2549b0f..7f4d7f55 100644 --- a/contracts/protocol/lendingpool/GNT/GNTConfiguratorAlfajores.sol +++ b/contracts/protocol/lendingpool/GNT/GNTConfiguratorAlfajores.sol @@ -30,8 +30,8 @@ contract GNTConfiguratorAlfajores is Ownable { string constant variableDebtTokenSymbol = 'variableDebtmGNT'; string constant stableDebtTokenName = 'Moola stable debt bearing mGNT'; string constant stableDebtTokenSymbol = 'stableDebtmGNT'; - uint256 constant baseLTV = 5000; - uint256 constant liquidationThreshold = 6500; + uint256 constant baseLTV = 4500; + uint256 constant liquidationThreshold = 6000; uint256 constant liquidationBonus = 11000; uint256 constant reserveFactor = 1000; diff --git a/contracts/protocol/lendingpool/PACT/PACTConfiguratorAlfajores.sol b/contracts/protocol/lendingpool/PACT/PACTConfiguratorAlfajores.sol index 995b5b4f..56945be5 100644 --- a/contracts/protocol/lendingpool/PACT/PACTConfiguratorAlfajores.sol +++ b/contracts/protocol/lendingpool/PACT/PACTConfiguratorAlfajores.sol @@ -30,9 +30,9 @@ contract PACTConfiguratorAlfajores is Ownable { string constant variableDebtTokenSymbol = 'variableDebtmPACT'; string constant stableDebtTokenName = 'Moola stable debt bearing mPACT'; string constant stableDebtTokenSymbol = 'stableDebtmPACT'; - uint256 constant baseLTV = 5000; - uint256 constant liquidationThreshold = 6500; - uint256 constant liquidationBonus = 11000; + uint256 constant baseLTV = 3000; + uint256 constant liquidationThreshold = 4500; + uint256 constant liquidationBonus = 11200; uint256 constant reserveFactor = 1000; function execute() external onlyOwner { diff --git a/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol b/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol index 808ed16d..517eb1a0 100644 --- a/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol +++ b/contracts/protocol/lendingpool/UBE/UBEConfiguratorAlfajores.sol @@ -30,8 +30,8 @@ contract UBEConfiguratorAlfajores is Ownable { string constant variableDebtTokenSymbol = 'variableDebtmUBE'; string constant stableDebtTokenName = 'Moola stable debt bearing mUBE'; string constant stableDebtTokenSymbol = 'stableDebtmUBE'; - uint256 constant baseLTV = 5000; - uint256 constant liquidationThreshold = 6500; + uint256 constant baseLTV = 4500; + uint256 constant liquidationThreshold = 6000; uint256 constant liquidationBonus = 11000; uint256 constant reserveFactor = 1000;