External lending can exceed the threshold
Due to an incorrect calculation of the max lending amount, external lending can exceed the external withdrawal threshold. If this restriction/threshold is not adhered to, users or various core functionalities within the protocol will have issues redeeming or withdrawing their prime cash.\\nThe following is the extract from the Audit Scope Documentation provided by the protocol team on the contest page that describes the external withdraw threshold:\\n● External Withdraw Threshold: ensures that Notional has sufficient liquidity to withdraw from an external lending market. If Notional has 1000 units of underlying lent out on Aave, it requires 1000 * externalWithdrawThreshold units of underlying to be available on Aave for withdraw. This ensures there is sufficient buffer to process the redemption of Notional funds. If available liquidity on Aave begins to drop due to increased utilization, Notional will automatically begin to withdraw its funds from Aave to ensure that they are available for withdrawal on Notional itself.\\nTo ensure the redeemability of Notional's funds on external lending markets, Notional requires there to be redeemable funds on the external lending market that are a multiple of the funds that Notional has lent on that market itself.\\nAssume that the `externalWithdrawThreshold` is 200% and the underlying is USDC. Therefore, `PERCENTAGE_DECIMALS/externalWithdrawThreshold = 100/200 = 0.5` (Line 83-84 below). This means that the number of USDC to be available on AAVE for withdrawal must be two (2) times the number of USDC Notional lent out on AAVE (A multiple of 2).\\nThe `externalUnderlyingAvailableForWithdraw` stores the number of liquidity in USDC on the AAVE pool available to be withdrawn.\\nIf `externalUnderlyingAvailableForWithdraw` is 1000 USDC and `currentExternalUnderlyingLend` is 400 USDC, this means that the remaining 600 USDC liquidity on the AAVE pool is not owned by Notional.\\nThe `maxExternalUnderlyingLend` will be `600 * 0.5 = 300`. Thus, the maximum amount that Notional can lend externally at this point is 300 USDC.\\nAssume that after Notional has lent 300 USDC externally to the AAVE pool.\\nThe `currentExternalUnderlyingLend` will become `400+300=700`, and the `externalUnderlyingAvailableForWithdraw` will become `1000+300=1300`\\nFollowing is the percentage of USDC in AAVE that belong to Notional\\n```\\n700/1300 = 0.5384615385 (53%).\\n```\\n\\nAt this point, the invariant is broken as the number of USDC to be available on AAVE for withdrawal is less than two (2) times the number of USDC lent out on AAVE after the lending.\\n```\\nFile: ExternalLending.sol\\n    function getTargetExternalLendingAmount(\\n..SNIP..\\n        uint256 maxExternalUnderlyingLend;\\n        if (oracleData.currentExternalUnderlyingLend < oracleData.externalUnderlyingAvailableForWithdraw) {\\n            maxExternalUnderlyingLend =\\n                (oracleData.externalUnderlyingAvailableForWithdraw - oracleData.currentExternalUnderlyingLend)\\n                .mul(uint256(Constants.PERCENTAGE_DECIMALS))\\n                .div(rebalancingTargetData.externalWithdrawThreshold);\\n        } else {\\n            maxExternalUnderlyingLend = 0;\\n        }\\n```\\n\\nThe root cause is that when USDC is deposited to AAVE to get aUSDC, the total USDC in the pool increases. Therefore, using the current amount of USDC in the pool to determine the maximum deposit amount is not an accurate measure of liquidity risk.
To ensure that a deposit does not exceed the threshold, the following formula should be used to determine the maximum deposit amount:\\nLet's denote:\\n$T$ as the externalWithdrawThreshold $L$ as the currentExternalUnderlyingLend $W$ as the externalUnderlyingAvailableForWithdraw $D$ as the Deposit (the variable we want to solve for)\\n$$ T = \\frac{L + D}{W + D} $$\\nSolving $D$, the formula for calculating the maximum deposit ($D$) is\\n$$ D = \\frac{TW-L}{1-T} $$\\nUsing back the same example in the "Vulnerability Detail" section.\\nThe maximum deposit amount is as follows:\\n```\\nD = (TW - L) / (1 - T)\\nD = (0.5 * 1000 - 400) / (1 - 0.5)\\nD = (500 - 400) / 0.5 = 200\\n```\\n\\nIf 200 USDC is lent out, it will still not exceed the threshold of 200%, which demonstrates that the formula is working as intended in keeping the multiple of two (200%) constant before and after the deposit.\\n```\\n(400 + 200) / (1000 + 200) = 0.5\\n```\\n
To ensure the redeemability of Notional's funds on external lending markets, Notional requires there to be redeemable funds on the external lending market that are a multiple of the funds that Notional has lent on that market itself.\\nIf this restriction is not adhered to, users or various core functionalities within the protocol will have issues redeeming or withdrawing their prime cash. For instance, users might not be able to withdraw their assets from the protocol due to insufficient liquidity, or liquidation cannot be carried out due to lack of liquidity, resulting in bad debt accumulating within the protocol and negatively affecting the protocol's solvency.
```\\n700/1300 = 0.5384615385 (53%).\\n```\\n