I am trying to call the getReserveData function of a library ILendingPool interface:

interface ILendingPool {
  function addressesProvider () external view returns ( address );
  function deposit ( address _reserve, uint256 _amount, uint16 _referralCode ) external payable;
  function redeemUnderlying ( address _reserve, address _user, uint256 _amount ) external;
  function borrow ( address _reserve, uint256 _amount, uint256 _interestRateMode, uint16 _referralCode ) external;
  function repay ( address _reserve, uint256 _amount, address _onBehalfOf ) external payable;
  function swapBorrowRateMode ( address _reserve ) external;
  function rebalanceFixedBorrowRate ( address _reserve, address _user ) external;
  function setUserUseReserveAsCollateral ( address _reserve, bool _useAsCollateral ) external;
  function liquidationCall ( address _collateral, address _reserve, address _user, uint256 _purchaseAmount, bool _receiveAToken ) external payable;
  function flashLoan ( address _receiver, address _reserve, uint256 _amount, bytes calldata _params ) external;
  function getReserveConfigurationData ( address _reserve ) external view returns ( uint256 ltv, uint256 liquidationThreshold, uint256 liquidationDiscount, address interestRateStrategyAddress, bool usageAsCollateralEnabled, bool borrowingEnabled, bool fixedBorrowRateEnabled, bool isActive );
  function getReserveData ( address _reserve ) external view returns ( uint256 totalLiquidity, uint256 availableLiquidity, uint256 totalBorrowsFixed, uint256 totalBorrowsVariable, uint256 liquidityRate, uint256 variableBorrowRate, uint256 fixedBorrowRate, uint256 averageFixedBorrowRate, uint256 utilizationRate, uint256 liquidityIndex, uint256 variableBorrowIndex, address aTokenAddress, uint40 lastUpdateTimestamp );
  function getUserAccountData ( address _user ) external view returns ( uint256 totalLiquidityETH, uint256 totalCollateralETH, uint256 totalBorrowsETH, uint256 availableBorrowsETH, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor );
  function getUserReserveData ( address _reserve, address _user ) external view returns ( uint256 currentATokenBalance, uint256 currentUnderlyingBalance, uint256 currentBorrowBalance, uint256 principalBorrowBalance, uint256 borrowRateMode, uint256 borrowRate, uint256 liquidityRate, uint256 originationFee, uint256 variableBorrowIndex, uint256 lastUpdateTimestamp, bool usageAsCollateralEnabled );
  function getReserves () external view;

Unfortunately the getReserveData function returns a tuple that has 13 fields.

I need only one of the fields and you can see me call it below:

   function getAvailableLiquidity(ILendingPool _lendingPool) internal view returns (uint256){
    uint256 _availableLiquidity;
    (,_availableLiquidity,,,,,,,,,,,) = _lendingPool.getReserveData(RAW_ETH_ASSET);// in ether
    return _availableLiquidity;

..Solidity keeps complaining:

YulException: Stack too deep when compiling inline assembly: Variable dataEnd is 1 slot(s) too deep inside the stack.

This is the interface definition so of course I can't do anything about it. Please what trick can I use to wangle the available liquidity out of the getReserveData function?


You can do something like this:

bytes4 private constant FUNC_SELECTOR = bytes4(keccak256("getReserveData(address)"));

function getAvailableLiquidity(ILendingPool _lendingPool) internal view returns (uint256) {
    uint256[2] memory ret;
    bytes memory data = abi.encodeWithSelector(FUNC_SELECTOR, RAW_ETH_ASSET);

    assembly {
        let success := staticcall(
            gas,           // gas remaining
            _lendingPool,  // destination address
            add(data, 32), // input buffer (starts after the first 32 bytes in the `data` array)
            mload(data),   // input length (loaded from the first 32 bytes in the `data` array)
            ret,           // output buffer
            64             // output length
        if iszero(success) {
            revert(0, 0)

    return ret[1];
  • Hmm,looks good at least it compiled after I set some value to the gas. Can you explain a bit though how this works, so I will be able to replicate the solution for other similar issues I might have later? – gbenroscience Jun 28 '20 at 12:38
  • Not sure if you saw my comment, but please explain what it does when you do.I will now accept your answer. Thanks a lot. – gbenroscience Jun 28 '20 at 12:55
  • @gbenroscience: Check out the comments next to each parameter. – goodvibration Jun 28 '20 at 13:56
  • Thanks @goodvibration You do give off good vibes... and good answers, lol. Have a great day! – gbenroscience Jun 28 '20 at 14:30
  • 1
    @gbenroscience: hahaha, you're welcome. – goodvibration Jun 28 '20 at 14:32

The available liquidity is also provided by the Lending Pool Core:

interface ILendingPoolCore {
    function getReserveAvailableLiquidity(address _reserve) external view returns (uint256 _availableLiquidity);

Naturally, one would have to provide the address of the lending pool core instead of the address for lending pool:

function getAvailableLiquidity(ILendingPoolCore _lendingPoolCore) internal view returns (uint256 _availableLiquidity)
    return _lendingPoolCore.getReserveAvailableLiquidity(RAW_ETH_ASSET);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.