Skip to content

Commit 09ed87d

Browse files
committed
Merge branch 'master' into fix/387-emode-pricefeed-liquidations
2 parents f14540b + 17d7b9d commit 09ed87d

File tree

202 files changed

+11696
-4221
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

202 files changed

+11696
-4221
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ coverage
1818
.coverage_cache
1919
.coverage_contracts
2020
coverage.json
21+
deployments/

CHANGELOG.md

Lines changed: 209 additions & 0 deletions
Large diffs are not rendered by default.

Certora/certora/Verification_Report.md

Lines changed: 442 additions & 0 deletions
Large diffs are not rendered by default.
112 KB
Binary file not shown.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// SPDX-License-Identifier: agpl-3.0
2+
pragma solidity 0.8.10;
3+
4+
import {Pool} from '../../contracts/protocol/pool/Pool.sol';
5+
import {AToken} from '../../contracts/protocol/tokenization/AToken.sol';
6+
7+
/**
8+
* @title Certora harness for Aave ERC20 AToken
9+
*
10+
* @dev Certora's harness contract for the verification of Aave ERC20 AToken.
11+
*/
12+
contract ATokenHarness is AToken {
13+
14+
constructor(
15+
Pool pool
16+
) public AToken(pool) {}
17+
18+
/**
19+
* @dev Calls burn with index == 1 RAY
20+
* @param amount the amount being burned
21+
**/
22+
function burn(
23+
address user,
24+
address receiverOfUnderlying,
25+
uint256 amount,
26+
uint256 index
27+
) public override onlyPool {
28+
29+
// changes for pool
30+
// require(index == 1e27, 'index is assumed to be 1 RAY');
31+
// super.burn(user, receiverOfUnderlying, amount, index);
32+
33+
super.burn(user, receiverOfUnderlying, amount, 1e27);
34+
//POOL.setATokenFlag(!POOL.getATokenFlag());
35+
}
36+
37+
/**
38+
* @dev Calls mint with index == 1 RAY
39+
* @param amount the amount of tokens to mint
40+
**/
41+
function mint(
42+
address user,
43+
address onBehalfOf,
44+
uint256 amount,
45+
uint256 index
46+
) public virtual override onlyPool returns (bool) {
47+
48+
// changes for pool
49+
// require(index == 1e27, 'index is assumed to be 1 RAY');
50+
// return super.mint(user, amount, index);
51+
return super.mint(user, onBehalfOf, amount, 1e27);
52+
}
53+
54+
function scaledTotalSupply() public view override returns (uint256) {
55+
uint256 val = super.scaledTotalSupply();
56+
// POOL.setATokenFlag(!POOL.getATokenFlag());
57+
return val;
58+
}
59+
60+
function additionalData(address user) public view returns (uint128) {
61+
return _userState[user].additionalData;
62+
}
63+
}

Certora/certora/harness/DataTypesInitializer.sol

Whitespace-only changes.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {EModeLogic} from '../../contracts/protocol/libraries/logic/EModeLogic.sol';
2+
import {DataTypes} from '../../contracts/protocol/libraries/types/DataTypes.sol';
3+
4+
contract EModeLogicHarness {
5+
mapping(address => DataTypes.ReserveData) reserves;
6+
mapping(uint256 => address) reservesList;
7+
mapping(uint8 => DataTypes.EModeCategory) eModeCategories;
8+
mapping(address => uint8) usersEModeCategory;
9+
DataTypes.UserConfigurationMap userConfig;
10+
DataTypes.ExecuteSetUserEModeParams params;
11+
12+
function test() public {
13+
EModeLogic.executeSetUserEMode(
14+
reserves,
15+
reservesList,
16+
eModeCategories,
17+
usersEModeCategory,
18+
userConfig,
19+
params
20+
);
21+
}
22+
}
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
// SPDX-License-Identifier: agpl-3.0
2+
pragma solidity 0.8.10;
3+
4+
import {IERC20} from '../../contracts/dependencies/openzeppelin/contracts/IERC20.sol';
5+
import {IScaledBalanceToken} from '../../contracts/interfaces/IScaledBalanceToken.sol';
6+
import {IPriceOracleGetter} from '../../contracts/interfaces/IPriceOracleGetter.sol';
7+
import {ReserveConfiguration} from '../../contracts/protocol/libraries/configuration/ReserveConfiguration.sol';
8+
import {UserConfiguration} from '../../contracts/protocol/libraries/configuration/UserConfiguration.sol';
9+
import {PercentageMath} from '../../contracts/protocol/libraries/math/PercentageMath.sol';
10+
import {WadRayMath} from '../../contracts/protocol/libraries/math/WadRayMath.sol';
11+
import {DataTypes} from '../../contracts/protocol/libraries/types/DataTypes.sol';
12+
import {ReserveLogic} from '../../contracts/protocol/libraries/logic/ReserveLogic.sol';
13+
14+
/**
15+
* @title GenericLogic library
16+
* @author Aave
17+
* @notice Implements protocol-level logic to calculate and validate the state of a user
18+
*/
19+
contract GenericLogic {
20+
using ReserveLogic for DataTypes.ReserveData;
21+
using WadRayMath for uint256;
22+
using PercentageMath for uint256;
23+
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
24+
using UserConfiguration for DataTypes.UserConfigurationMap;
25+
26+
mapping(address => DataTypes.ReserveData) public reservesData;
27+
mapping(uint256 => address) public reserves;
28+
mapping(uint8 => DataTypes.EModeCategory) public eModeCategories;
29+
//DataTypes.CalculateUserAccountDataParams public params;
30+
DataTypes.UserConfigurationMap public userConfig;
31+
uint256 public reservesCount;
32+
address public user;
33+
address public oracle;
34+
uint8 public userEModeCategory;
35+
36+
struct CalculateUserAccountDataVars {
37+
uint256 assetPrice;
38+
uint256 assetUnit;
39+
uint256 userBalance;
40+
uint256 userBalanceInBaseCurrency;
41+
uint256 userDebt;
42+
uint256 userStableDebt;
43+
uint256 userDebtInBaseCurrency;
44+
uint256 decimals;
45+
uint256 ltv;
46+
uint256 liquidationThreshold;
47+
uint256 i;
48+
uint256 healthFactor;
49+
uint256 totalCollateralInBaseCurrency;
50+
uint256 totalDebtInBaseCurrency;
51+
uint256 avgLtv;
52+
uint256 avgLiquidationThreshold;
53+
uint256 normalizedIncome;
54+
uint256 normalizedDebt;
55+
uint256 eModeAssetPrice;
56+
uint256 eModeLtv;
57+
uint256 eModeLiqThreshold;
58+
uint256 eModeAssetCategory;
59+
address eModePriceSource;
60+
address currentReserveAddress;
61+
bool hasZeroLtvCollateral;
62+
}
63+
64+
/**
65+
* @notice Calculates the user data across the reserves.
66+
* @dev It includes the total liquidity/collateral/borrow balances in the base currency used by the price feed,
67+
* the average Loan To Value, the average Liquidation Ratio, and the Health factor.
68+
* @return The total collateral of the user in the base currency used by the price feed
69+
* @return The total debt of the user in the base currency used by the price feed
70+
* @return The average ltv of the user
71+
* @return The average liquidation threshold of the user
72+
* @return The health factor of the user
73+
* @return True if the ltv is zero, false otherwise
74+
**/
75+
function calculateUserAccountData()
76+
public
77+
returns (
78+
uint256,
79+
uint256,
80+
uint256,
81+
uint256,
82+
uint256,
83+
bool
84+
)
85+
{
86+
if (userConfig.isEmpty()) {
87+
return (0, 0, 0, 0, type(uint256).max, false);
88+
}
89+
90+
CalculateUserAccountDataVars memory vars;
91+
92+
if (userEModeCategory != 0) {
93+
vars.eModePriceSource = eModeCategories[userEModeCategory].priceSource;
94+
vars.eModeLtv = eModeCategories[userEModeCategory].ltv;
95+
vars.eModeLiqThreshold = eModeCategories[userEModeCategory].liquidationThreshold;
96+
97+
if (vars.eModePriceSource != address(0)) {
98+
vars.eModeAssetPrice = IPriceOracleGetter(oracle).getAssetPrice(
99+
vars.eModePriceSource
100+
);
101+
}
102+
}
103+
104+
while (vars.i < reservesCount) {
105+
if (!userConfig.isUsingAsCollateralOrBorrowing(vars.i)) {
106+
unchecked {
107+
++vars.i;
108+
}
109+
continue;
110+
}
111+
112+
vars.currentReserveAddress = reserves[vars.i];
113+
114+
if (vars.currentReserveAddress == address(0)) {
115+
unchecked {
116+
++vars.i;
117+
}
118+
continue;
119+
}
120+
121+
DataTypes.ReserveData storage currentReserve = reservesData[vars.currentReserveAddress];
122+
123+
(
124+
vars.ltv,
125+
vars.liquidationThreshold,
126+
,
127+
vars.decimals,
128+
,
129+
vars.eModeAssetCategory
130+
) = currentReserve.configuration.getParams();
131+
132+
unchecked {
133+
vars.assetUnit = 10**vars.decimals;
134+
}
135+
vars.assetPrice = vars.eModeAssetPrice > 0
136+
? vars.eModeAssetPrice
137+
: IPriceOracleGetter(oracle).getAssetPrice(vars.currentReserveAddress);
138+
139+
if (vars.liquidationThreshold != 0 && userConfig.isUsingAsCollateral(vars.i)) {
140+
vars.normalizedIncome = currentReserve.getNormalizedIncome();
141+
vars.userBalance = IScaledBalanceToken(currentReserve.aTokenAddress).scaledBalanceOf(
142+
user
143+
);
144+
vars.userBalance = vars.userBalance.rayMul(vars.normalizedIncome);
145+
146+
vars.userBalanceInBaseCurrency = (vars.assetPrice * vars.userBalance);
147+
unchecked {
148+
vars.userBalanceInBaseCurrency /= vars.assetUnit;
149+
}
150+
vars.totalCollateralInBaseCurrency =
151+
vars.totalCollateralInBaseCurrency +
152+
vars.userBalanceInBaseCurrency;
153+
154+
vars.hasZeroLtvCollateral = vars.hasZeroLtvCollateral || vars.ltv == 0;
155+
156+
vars.avgLtv = vars.ltv > 0
157+
? vars.avgLtv +
158+
vars.userBalanceInBaseCurrency *
159+
(
160+
(userEModeCategory == 0 || vars.eModeAssetCategory != userEModeCategory)
161+
? vars.ltv
162+
: vars.eModeLtv
163+
)
164+
: vars.avgLtv;
165+
166+
vars.avgLiquidationThreshold =
167+
vars.avgLiquidationThreshold +
168+
vars.userBalanceInBaseCurrency *
169+
(
170+
(userEModeCategory == 0 || vars.eModeAssetCategory != userEModeCategory)
171+
? vars.liquidationThreshold
172+
: vars.eModeLiqThreshold
173+
);
174+
}
175+
176+
if (userConfig.isBorrowing(vars.i)) {
177+
vars.userStableDebt = IERC20(currentReserve.stableDebtTokenAddress).balanceOf(user);
178+
vars.userDebt = IScaledBalanceToken(currentReserve.variableDebtTokenAddress)
179+
.scaledBalanceOf(user);
180+
181+
if (vars.userDebt > 0) {
182+
vars.normalizedDebt = currentReserve.getNormalizedDebt();
183+
vars.userDebt = vars.userDebt.rayMul(vars.normalizedDebt);
184+
}
185+
vars.userDebt = vars.userDebt + vars.userStableDebt;
186+
vars.userDebtInBaseCurrency = (vars.assetPrice * vars.userDebt);
187+
unchecked {
188+
vars.userDebtInBaseCurrency /= vars.assetUnit;
189+
}
190+
vars.totalDebtInBaseCurrency = vars.totalDebtInBaseCurrency + vars.userDebtInBaseCurrency;
191+
}
192+
193+
unchecked {
194+
++vars.i;
195+
}
196+
}
197+
198+
unchecked {
199+
vars.avgLtv = vars.totalCollateralInBaseCurrency > 0
200+
? vars.avgLtv / vars.totalCollateralInBaseCurrency
201+
: 0;
202+
vars.avgLiquidationThreshold = vars.totalCollateralInBaseCurrency > 0
203+
? vars.avgLiquidationThreshold / vars.totalCollateralInBaseCurrency
204+
: 0;
205+
}
206+
207+
vars.healthFactor = (vars.totalDebtInBaseCurrency == 0)
208+
? type(uint256).max
209+
: (vars.totalCollateralInBaseCurrency.percentMul(vars.avgLiquidationThreshold)).wadDiv(
210+
vars.totalDebtInBaseCurrency
211+
);
212+
return (
213+
vars.totalCollateralInBaseCurrency,
214+
vars.totalDebtInBaseCurrency,
215+
vars.avgLtv,
216+
vars.avgLiquidationThreshold,
217+
vars.healthFactor,
218+
vars.hasZeroLtvCollateral
219+
);
220+
}
221+
222+
/**
223+
* @notice Calculates the maximum amount that can be borrowed depending on the available collateral, the total debt and the
224+
* average Loan To Value
225+
* @param totalCollateralInBaseCurrency The total collateral in the base currency used by the price feed
226+
* @param totalDebtInBaseCurrency The total borrow balance in the base currency used by the price feed
227+
* @param ltv The average loan to value
228+
* @return The amount available to borrow in the base currency of the used by the price feed
229+
**/
230+
function calculateAvailableBorrows(
231+
uint256 totalCollateralInBaseCurrency,
232+
uint256 totalDebtInBaseCurrency,
233+
uint256 ltv
234+
) public pure returns (uint256) {
235+
uint256 availableBorrowsInBaseCurrency = totalCollateralInBaseCurrency.percentMul(ltv);
236+
237+
if (availableBorrowsInBaseCurrency < totalDebtInBaseCurrency) {
238+
return 0;
239+
}
240+
241+
availableBorrowsInBaseCurrency = availableBorrowsInBaseCurrency - totalDebtInBaseCurrency;
242+
return availableBorrowsInBaseCurrency;
243+
}
244+
}

0 commit comments

Comments
 (0)