# `ExternalLending`

ExternalLending redemption check compares expectedUnderlying to actual balance change, which always reverts for fee-on-transfer tokens, blocking AaveV3 withdrawals and prime cash redemptions.

- Payout: Contest reward
- Severity: medium
- Program: Notional Update 5
- Credited: eol
- Disclosed: 2023-12-20
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-12-notional-update-5-judging/issues/65
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-12-notional-update-5%3AM-15
- Tags: domain:web3 impact:dos kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic

**Target:** AaveV3HoldingsOracle / ExternalLending redemption flow
**Root cause:** expectedUnderlying is set to withdrawAmount (currentAmount - targetAmount) without accounting for transfer fees, so the require(expectedUnderlying <= underlyingBalanceChange) check fails for fee-on-transfer tokens.
**Steps:**
1. Treasury rebalances and encodes AaveV3 withdraw calldata via `AaveV3HoldingsOracle._getRedemptionCalldata()` with `withdrawAmount` as expectedUnderlying
2. `TreasuryAction` sets `redeemAmounts[0] = currentAmount - targetAmount` ignoring transfer fee
3. `ExternalLending.executeMoneyMarketRedemptions()` executes the withdraw and computes `underlyingBalanceChange`
4. `require(data.expectedUnderlying <= underlyingBalanceChange)` reverts because balance change is reduced by the fee
**How found:** Code reading of the redemption calldata construction and the balance-change require check, noticing expectedUnderlying equals withdrawAmount with no fee adjustment.
**Insight:** When a redemption/withdrawal path asserts an exact expected balance delta, check whether the underlying token can be fee-on-transfer or rebasing; the assertion becomes an unconditional revert that bricks the exit path.
