From 6be8b1c5fdbe37d641453c27a61864d029753f23 Mon Sep 17 00:00:00 2001 From: eboado Date: Wed, 28 Oct 2020 10:54:09 +0100 Subject: [PATCH 1/5] - Added validations on ReserveConfiguration's numeric setters. --- .../configuration/ReserveConfiguration.sol | 21 ++++++- contracts/libraries/helpers/Errors.sol | 9 +++ helpers/types.ts | 6 ++ test/configurator.spec.ts | 58 ++++++++++++++++++- 4 files changed, 91 insertions(+), 3 deletions(-) diff --git a/contracts/libraries/configuration/ReserveConfiguration.sol b/contracts/libraries/configuration/ReserveConfiguration.sol index 553cec66..ccef1e00 100644 --- a/contracts/libraries/configuration/ReserveConfiguration.sol +++ b/contracts/libraries/configuration/ReserveConfiguration.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: agpl-3.0 pragma solidity ^0.6.8; +import {Errors} from '../helpers/Errors.sol'; + /** * @title ReserveConfiguration library * @author Aave @@ -27,6 +29,12 @@ library ReserveConfiguration { 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; + struct Map { //bit 0-15: LTV //bit 16-31: Liq. threshold @@ -47,6 +55,8 @@ library ReserveConfiguration { * @param ltv the new ltv **/ function setLtv(ReserveConfiguration.Map memory self, uint256 ltv) internal pure { + require(ltv <= MAX_VALID_LTV, Errors.INVALID_LTV); + self.data = (self.data & LTV_MASK) | ltv; } @@ -68,6 +78,8 @@ library ReserveConfiguration { internal pure { + require(threshold <= MAX_VALID_LIQUIDATION_THRESHOLD, Errors.INVALID_LIQ_THRESHOLD); + self.data = (self.data & LIQUIDATION_THRESHOLD_MASK) | (threshold << LIQUIDATION_THRESHOLD_START_BIT_POSITION); @@ -92,6 +104,8 @@ library ReserveConfiguration { * @param bonus the new liquidation bonus **/ function setLiquidationBonus(ReserveConfiguration.Map memory self, uint256 bonus) internal pure { + require(bonus <= MAX_VALID_LIQUIDATION_BONUS, Errors.INVALID_LIQ_BONUS); + self.data = (self.data & LIQUIDATION_BONUS_MASK) | (bonus << LIQUIDATION_BONUS_START_BIT_POSITION); @@ -116,6 +130,8 @@ library ReserveConfiguration { * @param decimals the decimals **/ function setDecimals(ReserveConfiguration.Map memory self, uint256 decimals) internal pure { + require(decimals <= MAX_VALID_DECIMALS, Errors.INVALID_DECIMALS); + self.data = (self.data & DECIMALS_MASK) | (decimals << RESERVE_DECIMALS_START_BIT_POSITION); } @@ -225,6 +241,8 @@ library ReserveConfiguration { internal pure { + require(reserveFactor <= MAX_VALID_RESERVE_FACTOR, Errors.INVALID_RESERVE_FACTOR); + self.data = (self.data & RESERVE_FACTOR_MASK) | (reserveFactor << RESERVE_FACTOR_START_BIT_POSITION); @@ -316,8 +334,7 @@ library ReserveConfiguration { ); } - - /** + /** * @dev gets the configuration flags of the reserve from a memory object * @param self the reserve configuration * @return the state flags representing active, freezed, borrowing enabled, stableRateBorrowing enabled diff --git a/contracts/libraries/helpers/Errors.sol b/contracts/libraries/helpers/Errors.sol index 91dd385f..9ed7b07e 100644 --- a/contracts/libraries/helpers/Errors.sol +++ b/contracts/libraries/helpers/Errors.sol @@ -89,6 +89,15 @@ library Errors { // pausable error message string public constant IS_PAUSED = '58'; // 'Pool is paused' + + // Reserve configuration + string public constant INVALID_LTV = '70'; + string public constant INVALID_LIQ_THRESHOLD = '71'; + string public constant INVALID_LIQ_BONUS = '72'; + string public constant INVALID_DECIMALS = '73'; + string public constant INVALID_RESERVE_FACTOR = '74'; + + enum CollateralManagerErrors { NO_ERROR, NO_COLLATERAL_AVAILABLE, diff --git a/helpers/types.ts b/helpers/types.ts index 305ec335..944c2be0 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -117,6 +117,12 @@ export enum ProtocolErrors { IS_PAUSED = '58', // Pool is paused + INVALID_LTV = '70', + INVALID_LIQ_THRESHOLD = '71', + INVALID_LIQ_BONUS = '72', + INVALID_DECIMALS = '73', + INVALID_RESERVE_FACTOR = '74', + // old INVALID_FROM_BALANCE_AFTER_TRANSFER = 'Invalid from balance after transfer', diff --git a/test/configurator.spec.ts b/test/configurator.spec.ts index 891c88dc..788add5c 100644 --- a/test/configurator.spec.ts +++ b/test/configurator.spec.ts @@ -10,7 +10,63 @@ const APPROVAL_AMOUNT_LENDING_POOL = const {expect} = require('chai'); makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { - const {CALLER_NOT_AAVE_ADMIN, RESERVE_LIQUIDITY_NOT_0} = ProtocolErrors; + const { + CALLER_NOT_AAVE_ADMIN, + RESERVE_LIQUIDITY_NOT_0, + INVALID_LTV, + INVALID_LIQ_THRESHOLD, + INVALID_LIQ_BONUS, + INVALID_DECIMALS, + INVALID_RESERVE_FACTOR, + } = ProtocolErrors; + + it('Reverts trying to set an invalid LTV', async () => { + const {configurator, weth} = testEnv; + + const invalidLtv = 65536; + + await expect(configurator.setLtv(weth.address, invalidLtv)).to.be.revertedWith(INVALID_LTV); + }); + + it('Reverts trying to set an invalid liquidation threshold', async () => { + const {configurator, weth} = testEnv; + + const invalidLiqThreshold = 65536; + + await expect( + configurator.setLiquidationThreshold(weth.address, invalidLiqThreshold) + ).to.be.revertedWith(INVALID_LIQ_THRESHOLD); + }); + + it('Reverts trying to set an invalid liquidation bonus', async () => { + const {configurator, weth} = testEnv; + + const invalidLiqBonus = 65536; + + await expect( + configurator.setLiquidationBonus(weth.address, invalidLiqBonus) + ).to.be.revertedWith(INVALID_LIQ_BONUS); + }); + + it('Reverts trying to set an invalid reserve decimals', async () => { + const {configurator, weth} = testEnv; + + const invalidDecimals = 256; + + await expect(configurator.setReserveDecimals(weth.address, invalidDecimals)).to.be.revertedWith( + INVALID_DECIMALS + ); + }); + + it('Reverts trying to set an invalid reserve factor', async () => { + const {configurator, weth} = testEnv; + + const invalidReserveFactor = 65536; + + await expect( + configurator.setReserveFactor(weth.address, invalidReserveFactor) + ).to.be.revertedWith(INVALID_RESERVE_FACTOR); + }); it('Deactivates the ETH reserve', async () => { const {configurator, weth, helpersContract} = testEnv; From 9e55ea12b67f20b7e762e027e8048cbb5f38e147 Mon Sep 17 00:00:00 2001 From: emilio Date: Thu, 29 Oct 2020 11:57:43 +0100 Subject: [PATCH 2/5] Fixes #99 --- contracts/interfaces/ILendingPool.sol | 13 +++-- contracts/lendingpool/LendingPool.sol | 54 ++++++++++++------- contracts/libraries/logic/ValidationLogic.sol | 40 ++++++++++++++ contracts/tokenization/AToken.sol | 28 +++++----- contracts/tokenization/interfaces/IAToken.sol | 2 - deployed-contracts.json | 2 +- test/atoken-transfer.spec.ts | 47 ++++++++-------- 7 files changed, 123 insertions(+), 63 deletions(-) diff --git a/contracts/interfaces/ILendingPool.sol b/contracts/interfaces/ILendingPool.sol index f44a458a..b893c16b 100644 --- a/contracts/interfaces/ILendingPool.sol +++ b/contracts/interfaces/ILendingPool.sol @@ -349,11 +349,14 @@ interface ILendingPool { function getReserveData(address asset) external view returns (ReserveLogic.ReserveData memory); - function balanceDecreaseAllowed( - address reserve, - address user, - uint256 amount - ) external view returns (bool); + function finalizeTransfer( + address asset, + address from, + address to, + uint256 amount, + uint256 balanceFromAfter, + uint256 balanceToBefore + ) external; function getReservesList() external view returns (address[] memory); diff --git a/contracts/lendingpool/LendingPool.sol b/contracts/lendingpool/LendingPool.sol index 3f490365..fde9d760 100644 --- a/contracts/lendingpool/LendingPool.sol +++ b/contracts/lendingpool/LendingPool.sol @@ -724,29 +724,46 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage } /** - * @dev validate if a balance decrease for an asset is allowed + * @dev validates and finalizes an aToken transfer * @param asset the address of the reserve - * @param user the user related to the balance decrease + * @param from the user from which the aTokens are transferred + * @param to the user receiving the aTokens * @param amount the amount being transferred/redeemed - * @return true if the balance decrease can be allowed, false otherwise + * @param balanceFromBefore the balance of the from user before the transfer + * @param balanceToBefore the balance of the to user before the transfer */ - function balanceDecreaseAllowed( + function finalizeTransfer( address asset, - address user, - uint256 amount - ) external override view returns (bool) { + address from, + address to, + uint256 amount, + uint256 balanceFromBefore, + uint256 balanceToBefore + ) external override { _whenNotPaused(); - return - GenericLogic.balanceDecreaseAllowed( - asset, - user, - amount, - _reserves, - _usersConfig[user], - _reservesList, - _reservesCount, - _addressesProvider.getPriceOracle() - ); + + ValidationLogic.validateTransfer( + from, + _reserves, + _usersConfig[from], + _reservesList, + _reservesCount, + _addressesProvider.getPriceOracle() + ); + + uint256 reserveId = _reserves[asset].id; + + if (from != to) { + if (balanceFromBefore.sub(amount) == 0) { + UserConfiguration.Map storage fromConfig = _usersConfig[from]; + fromConfig.setUsingAsCollateral(reserveId, false); + } + + if (balanceToBefore == 0) { + UserConfiguration.Map storage toConfig = _usersConfig[to]; + toConfig.setUsingAsCollateral(reserveId, true); + } + } } /** @@ -913,7 +930,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage * @dev adds a reserve to the array of the _reserves address **/ function _addReserveToList(address asset) internal { - uint256 reservesCount = _reservesCount; require(reservesCount < MAX_NUMBER_RESERVES, Errors.NO_MORE_RESERVES_ALLOWED); diff --git a/contracts/libraries/logic/ValidationLogic.sol b/contracts/libraries/logic/ValidationLogic.sol index 947d84ea..c772e307 100644 --- a/contracts/libraries/logic/ValidationLogic.sol +++ b/contracts/libraries/logic/ValidationLogic.sol @@ -13,6 +13,8 @@ import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol'; import {UserConfiguration} from '../configuration/UserConfiguration.sol'; import {Errors} from '../helpers/Errors.sol'; import {Helpers} from '../helpers/Helpers.sol'; +import "@nomiclabs/buidler/console.sol"; + /** * @title ReserveLogic library @@ -46,6 +48,11 @@ library ValidationLogic { * @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, @@ -389,4 +396,37 @@ library ValidationLogic { return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.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 => ReserveLogic.ReserveData) storage reservesData, + UserConfiguration.Map storage userConfig, + mapping(uint256 => address) storage reserves, + uint256 reservesCount, + address oracle + ) internal view { + (, , , , uint256 healthFactor) = GenericLogic.calculateUserAccountData( + from, + reservesData, + userConfig, + reserves, + reservesCount, + oracle + ); + + console.log("Health factor after transfer %s", healthFactor); + + require( + healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, + Errors.TRANSFER_NOT_ALLOWED + ); + } } diff --git a/contracts/tokenization/AToken.sol b/contracts/tokenization/AToken.sol index 5641ebf8..adc1771b 100644 --- a/contracts/tokenization/AToken.sol +++ b/contracts/tokenization/AToken.sol @@ -241,16 +241,6 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken { return super.totalSupply(); } - /** - * @dev Used to validate transfers before actually executing them. - * @param user address of the user to check - * @param amount the amount to check - * @return true if the user can transfer amount, false otherwise - **/ - function isTransferAllowed(address user, uint256 amount) public override view returns (bool) { - return POOL.balanceDecreaseAllowed(UNDERLYING_ASSET_ADDRESS, user, amount); - } - /** * @dev transfers the underlying asset to the target. Used by the lendingpool to transfer * assets in borrow(), redeem() and flashLoan() @@ -317,14 +307,24 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken { uint256 amount, bool validate ) internal { - if (validate) { - require(isTransferAllowed(from, amount), Errors.TRANSFER_NOT_ALLOWED); - } - uint256 index = POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS); + uint256 fromBalanceBefore = super.balanceOf(from).rayMul(index); + uint256 toBalanceBefore = super.balanceOf(to).rayMul(index); + super._transfer(from, to, amount.rayDiv(index)); + if (validate) { + POOL.finalizeTransfer( + UNDERLYING_ASSET_ADDRESS, + from, + to, + amount, + fromBalanceBefore, + toBalanceBefore + ); + } + emit BalanceTransfer(from, to, amount, index); } diff --git a/contracts/tokenization/interfaces/IAToken.sol b/contracts/tokenization/interfaces/IAToken.sol index 00f63b20..055e3f5d 100644 --- a/contracts/tokenization/interfaces/IAToken.sol +++ b/contracts/tokenization/interfaces/IAToken.sol @@ -54,8 +54,6 @@ interface IAToken is IERC20, IScaledBalanceToken { uint256 value ) external; - function isTransferAllowed(address user, uint256 amount) external view returns (bool); - /** * @dev transfer the amount of the underlying asset to the user * @param user address of the user diff --git a/deployed-contracts.json b/deployed-contracts.json index d7001b2a..4b961b6c 100644 --- a/deployed-contracts.json +++ b/deployed-contracts.json @@ -628,4 +628,4 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } } -} +} \ No newline at end of file diff --git a/test/atoken-transfer.spec.ts b/test/atoken-transfer.spec.ts index 0e207e17..89ed584f 100644 --- a/test/atoken-transfer.spec.ts +++ b/test/atoken-transfer.spec.ts @@ -46,8 +46,8 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => { ); }); - it('User 0 deposits 1 WETH and user 1 tries to borrow, but the aTokens received as a transfer are not available as collateral (revert expected)', async () => { - const {users, pool, weth} = testEnv; + it('User 0 deposits 1 WETH and user 1 tries to borrow the WETH with the received DAI as collateral', async () => { + const {users, pool, weth, helpersContract} = testEnv; const userAddress = await pool.signer.getAddress(); await weth.connect(users[0].signer).mint(await convertToCurrencyDecimals(weth.address, '1')); @@ -57,26 +57,6 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => { await pool .connect(users[0].signer) .deposit(weth.address, ethers.utils.parseEther('1.0'), userAddress, '0'); - await expect( - pool - .connect(users[1].signer) - .borrow( - weth.address, - ethers.utils.parseEther('0.1'), - RateMode.Stable, - AAVE_REFERRAL, - users[1].address - ), - COLLATERAL_BALANCE_IS_0 - ).to.be.revertedWith(COLLATERAL_BALANCE_IS_0); - }); - - it('User 1 sets the DAI as collateral and borrows, tries to transfer everything back to user 0 (revert expected)', async () => { - const {users, pool, aDai, dai, weth} = testEnv; - await pool.connect(users[1].signer).setUserUseReserveAsCollateral(dai.address, true); - - const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '1000'); - await pool .connect(users[1].signer) .borrow( @@ -87,9 +67,32 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => { users[1].address ); + const userReserveData = await helpersContract.getUserReserveData(weth.address, users[1].address); + + expect(userReserveData.currentStableDebt.toString()).to.be.eq(ethers.utils.parseEther('0.1')); + }); + + it('User 1 tries to transfer all the DAI used as collateral back to user 0 (revert expected)', async () => { + const {users, pool, aDai, dai, weth} = testEnv; + + const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '1000'); + await expect( aDai.connect(users[1].signer).transfer(users[0].address, aDAItoTransfer), TRANSFER_NOT_ALLOWED ).to.be.revertedWith(TRANSFER_NOT_ALLOWED); }); + + it('User 1 tries to transfer a small amount of DAI used as collateral back to user 0', async () => { + + const {users, pool, aDai, dai, weth} = testEnv; + + const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '100'); + + await aDai.connect(users[1].signer).transfer(users[0].address, aDAItoTransfer); + + const user0Balance = await aDai.balanceOf(users[0].address); + + expect(user0Balance.toString()).to.be.eq(aDAItoTransfer.toString()); + }); }); From 2cf84f19ce43626b3ff854bf8269ddf39018fe2c Mon Sep 17 00:00:00 2001 From: emilio Date: Thu, 29 Oct 2020 12:03:26 +0100 Subject: [PATCH 3/5] removed console import --- contracts/libraries/logic/ValidationLogic.sol | 4 ---- 1 file changed, 4 deletions(-) diff --git a/contracts/libraries/logic/ValidationLogic.sol b/contracts/libraries/logic/ValidationLogic.sol index c772e307..78f74154 100644 --- a/contracts/libraries/logic/ValidationLogic.sol +++ b/contracts/libraries/logic/ValidationLogic.sol @@ -13,8 +13,6 @@ import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol'; import {UserConfiguration} from '../configuration/UserConfiguration.sol'; import {Errors} from '../helpers/Errors.sol'; import {Helpers} from '../helpers/Helpers.sol'; -import "@nomiclabs/buidler/console.sol"; - /** * @title ReserveLogic library @@ -422,8 +420,6 @@ library ValidationLogic { oracle ); - console.log("Health factor after transfer %s", healthFactor); - require( healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, Errors.TRANSFER_NOT_ALLOWED From 6cd18c4320dd072e9ac77bfb4528ef48bd345df1 Mon Sep 17 00:00:00 2001 From: eboado Date: Thu, 29 Oct 2020 12:09:07 +0100 Subject: [PATCH 4/5] - Simplified getter of boolean fields on ReserveConfiguration. - Added all 256 bits to masks on ReserveConfiguration for clarity. --- .../configuration/ReserveConfiguration.sol | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/contracts/libraries/configuration/ReserveConfiguration.sol b/contracts/libraries/configuration/ReserveConfiguration.sol index ccef1e00..ce4f722a 100644 --- a/contracts/libraries/configuration/ReserveConfiguration.sol +++ b/contracts/libraries/configuration/ReserveConfiguration.sol @@ -9,15 +9,15 @@ import {Errors} from '../helpers/Errors.sol'; * @notice Implements the bitmap logic to handle the reserve configuration */ library ReserveConfiguration { - uint256 constant LTV_MASK = 0xFFFFFFFFFFFFFFFF0000; - uint256 constant LIQUIDATION_THRESHOLD_MASK = 0xFFFFFFFFFFFF0000FFFF; - uint256 constant LIQUIDATION_BONUS_MASK = 0xFFFFFFFF0000FFFFFFFF; - uint256 constant DECIMALS_MASK = 0xFFFFFF00FFFFFFFFFFFF; - uint256 constant ACTIVE_MASK = 0xFFFFFEFFFFFFFFFFFFFF; - uint256 constant FROZEN_MASK = 0xFFFFFDFFFFFFFFFFFFFF; - uint256 constant BORROWING_MASK = 0xFFFFFBFFFFFFFFFFFFFF; - uint256 constant STABLE_BORROWING_MASK = 0xFFFFF7FFFFFFFFFFFFFF; - uint256 constant RESERVE_FACTOR_MASK = 0xFFFFFFFFFFFFFFFF; + 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), but we don't declare it as for 0 no bit movement is needed uint256 constant LIQUIDATION_THRESHOLD_START_BIT_POSITION = 16; @@ -161,7 +161,7 @@ library ReserveConfiguration { * @return the active state **/ function getActive(ReserveConfiguration.Map storage self) internal view returns (bool) { - return ((self.data & ~ACTIVE_MASK) >> IS_ACTIVE_START_BIT_POSITION) != 0; + return (self.data & ~ACTIVE_MASK) != 0; } /** @@ -181,7 +181,7 @@ library ReserveConfiguration { * @return the frozen state **/ function getFrozen(ReserveConfiguration.Map storage self) internal view returns (bool) { - return ((self.data & ~FROZEN_MASK) >> IS_FROZEN_START_BIT_POSITION) != 0; + return (self.data & ~FROZEN_MASK) != 0; } /** @@ -201,7 +201,7 @@ library ReserveConfiguration { * @return the borrowing state **/ function getBorrowingEnabled(ReserveConfiguration.Map storage self) internal view returns (bool) { - return ((self.data & ~BORROWING_MASK) >> BORROWING_ENABLED_START_BIT_POSITION) != 0; + return (self.data & ~BORROWING_MASK) != 0; } /** @@ -228,8 +228,7 @@ library ReserveConfiguration { view returns (bool) { - return - ((self.data & ~STABLE_BORROWING_MASK) >> STABLE_BORROWING_ENABLED_START_BIT_POSITION) != 0; + return (self.data & ~STABLE_BORROWING_MASK) != 0; } /** @@ -275,10 +274,10 @@ library ReserveConfiguration { uint256 dataLocal = self.data; return ( - (dataLocal & ~ACTIVE_MASK) >> IS_ACTIVE_START_BIT_POSITION != 0, - (dataLocal & ~FROZEN_MASK) >> IS_FROZEN_START_BIT_POSITION != 0, - (dataLocal & ~BORROWING_MASK) >> BORROWING_ENABLED_START_BIT_POSITION != 0, - (dataLocal & ~STABLE_BORROWING_MASK) >> STABLE_BORROWING_ENABLED_START_BIT_POSITION != 0 + (dataLocal & ~ACTIVE_MASK) != 0, + (dataLocal & ~FROZEN_MASK) != 0, + (dataLocal & ~BORROWING_MASK) != 0, + (dataLocal & ~STABLE_BORROWING_MASK) != 0 ); } @@ -350,10 +349,10 @@ library ReserveConfiguration { ) { return ( - (self.data & ~ACTIVE_MASK) >> IS_ACTIVE_START_BIT_POSITION != 0, - (self.data & ~FROZEN_MASK) >> IS_FROZEN_START_BIT_POSITION != 0, - (self.data & ~BORROWING_MASK) >> BORROWING_ENABLED_START_BIT_POSITION != 0, - (self.data & ~STABLE_BORROWING_MASK) >> STABLE_BORROWING_ENABLED_START_BIT_POSITION != 0 + (self.data & ~ACTIVE_MASK) != 0, + (self.data & ~FROZEN_MASK) != 0, + (self.data & ~BORROWING_MASK) != 0, + (self.data & ~STABLE_BORROWING_MASK) != 0 ); } } From 3f7d913fd43020328c827db4f5e045c9ce59c6b4 Mon Sep 17 00:00:00 2001 From: emilio Date: Thu, 29 Oct 2020 13:43:24 +0100 Subject: [PATCH 5/5] Fixed issue on 0 transfer, added check that the caller must be an aToken --- contracts/lendingpool/LendingPool.sol | 4 +++- contracts/libraries/helpers/Errors.sol | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/lendingpool/LendingPool.sol b/contracts/lendingpool/LendingPool.sol index fde9d760..1684247e 100644 --- a/contracts/lendingpool/LendingPool.sol +++ b/contracts/lendingpool/LendingPool.sol @@ -742,6 +742,8 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage ) external override { _whenNotPaused(); + require(msg.sender == _reserves[asset].aTokenAddress, Errors.CALLER_MUST_BE_AN_ATOKEN); + ValidationLogic.validateTransfer( from, _reserves, @@ -759,7 +761,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage fromConfig.setUsingAsCollateral(reserveId, false); } - if (balanceToBefore == 0) { + if (balanceToBefore == 0 && amount != 0) { UserConfiguration.Map storage toConfig = _usersConfig[to]; toConfig.setUsingAsCollateral(reserveId, true); } diff --git a/contracts/libraries/helpers/Errors.sol b/contracts/libraries/helpers/Errors.sol index 9ed7b07e..b515603f 100644 --- a/contracts/libraries/helpers/Errors.sol +++ b/contracts/libraries/helpers/Errors.sol @@ -46,6 +46,7 @@ library Errors { string public constant NO_MORE_RESERVES_ALLOWED = '59'; string public constant INVALID_FLASH_LOAN_EXECUTOR_RETURN = '60'; string public constant INCONSISTENT_FLASHLOAN_PARAMS = '69'; + string public constant CALLER_MUST_BE_AN_ATOKEN = '76'; // require error messages - aToken - DebtTokens string public constant CALLER_MUST_BE_LENDING_POOL = '28'; // 'The caller of this function must be a lending pool'