Skip to content

FLO-22: maxWithdraw() View Function Incorrectly Caps Credit Position Withdrawals #231

Closed

Description

@liobrasil

Severity: Low

Files Affected

  • cadence/contracts/FlowALPv1.cdc

Description

The maxWithdraw() pure math helper calculates the maximum amount of a token a user can withdraw while maintaining a specific target health factor. For users holding a credit balance in the requested token, the function correctly computes the risk-adjusted deltaTokens but artificially caps the return value at the token's current trueBalance. This fails to account for the protocol's ability to seamlessly flip a credit balance into a debit balance, a behavior explicitly supported by the core accounting logic. Because Pool.availableBalance() relies directly on this helper when pullFromTopUpSource is false, external integrations and frontends will query artificially suppressed liquidity limits. The actual state-mutating withdrawal logic correctly handles flipping the balance via the internal computeAvailableWithdrawal() function, meaning this is strictly a view-layer discrepancy that impacts UI/UX but not protocol solvency. Exploit Scenario:

  • A user holds a massively overcollateralized position backed by 100,000 USDC.
  • The user also has a small credit balance of 1 FLOW in the exact same position.
  • A frontend queries Pool.availableBalance() to display to the user how much FLOW they can safely borrow against their USDC.
  • The maxWithdraw() helper evaluates the FLOW credit balance, sets maxPossible to 1 FLOW, and artificially caps the returned available balance to 1 FLOW.
  • The frontend erroneously informs the user that their borrowing power is exhausted, misleading the user and severely degrading the application's usability, even though submitting a manual transaction to borrow 1,000 FLOW would mathematically succeed.

Recommendation

Refactor the maxWithdraw() function to align with the core accounting logic found in computeAvailableWithdrawal(). When evaluating a credit balance, the function should return the sum of the entire trueBalance (which brings the balance to zero) plus the newly allowed debt capacity (which flips the balance to a debit) that the remaining effective collateral can support at the target health factor.


Parent Issue: #209

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions