mirror of
				https://github.com/Instadapp/aave-protocol-v2.git
				synced 2024-07-29 21:47:30 +00:00 
			
		
		
		
	Fixes #99
This commit is contained in:
		
							parent
							
								
									251bd591f5
								
							
						
					
					
						commit
						9e55ea12b6
					
				| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -628,4 +628,4 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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());
 | 
			
		||||
  });    
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user