Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: high
Invalid

Fund Drainage During Withdraw Phase Breaks Protocol Operations

Summary

The BuyerAgent contract's withdrawal mechanism allows complete drainage of funds during the Withdraw phase by bypassing minimum fund requirements. This creates a vulnerability where the contract can be left with insufficient funds for oracle operations and purchases in subsequent rounds.

The withdraw function only enforces minimum fund requirements during non-Withdraw phases:

function withdraw(uint96 _amount) public onlyAuthorized {
(, Phase phase,) = getRoundPhase();
// @Issue - Minimum fund check bypassed during Withdraw phase
// Allows complete drainage of contract funds
if (phase != Phase.Withdraw) {
if (treasury() < minFundAmount() + _amount) {
revert MinFundSubceeded(_amount);
}
}
// @Issue - Direct transfer without minimum balance validation
swan.token().transfer(owner(), _amount);
}

The minFundAmount is critical as it covers:

  • Required funds for next round purchases (amountPerRound)

  • Oracle fees for LLM operations

  • Operational costs for the buying cycle

Vulnerability Details

The withdraw function conditionally checks the minimum fund requirement only for non-Withdraw phases. This creates a loophole where users can drain the contract below the required minimum during Withdraw phase: #L267-L271: https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/swan/BuyerAgent.sol#L267-L271

// @Issue - Conditional check creates bypass opportunity
if (phase != Phase.Withdraw) {
if (treasury() < minFundAmount() + _amount) {
revert MinFundSubceeded(_amount);
}
}

Withdraw#L262-L271: https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/swan/BuyerAgent.sol#L262-L271

function withdraw(uint96 _amount) public onlyAuthorized {
(, Phase phase,) = getRoundPhase();
// @Issue - Missing minimum fund check during Withdraw phase
// This allows complete drainage of funds
// leaving insufficient balance for next Buy phase operations
if (phase != Phase.Withdraw) {
if (treasury() < minFundAmount() + _amount) {
revert MinFundSubceeded(_amount);
}
}
swan.token().transfer(owner(), _amount);
}
  1. During Withdraw phase, the function allows withdrawing funds below minFundAmount

  2. minFundAmount is critical as it covers:

    • amountPerRound for purchases

    • oracle fees for next round operations

  3. When next Buy phase starts, the contract will be unable to:

    • Pay for oracle requests

    • Execute purchases

    • Maintain normal buying cycle

  4. This breaks the core autonomous buying functionality

The vulnerability creates a systemic risk where a single withdrawal during Withdraw phase can disrupt the entire buying cycle for subsequent rounds.

POC

// Initial state
treasury = 100 tokens
minFundAmount = 50 tokens
// During Withdraw phase
withdraw(90 tokens) // Succeeds
// Remaining balance: 10 tokens
// Next Buy phase
// Contract cannot pay oracle fees or execute purchases
// Protocol functionality breaks

Impact

  1. Protocol Operation Failure

    • Oracle requests fail due to insufficient fees

    • Purchase transactions revert from lack of funds

    • Buying cycle breaks in subsequent rounds

  2. Economic Impact

    • Disrupts market participation

    • Breaks autonomous buying functionality

    • Affects protocol reliability

Recommendations

Enforce minimum fund requirements across all phases to maintain protocol functionality and prevent operational disruption. Consider adding additional safety checks:

  • Maximum withdrawal limits per round

  • Time-based withdrawal restrictions

  • Emergency pause mechanism for large withdrawals

Updates

Lead Judging Commences

inallhonesty Lead Judge
12 months ago
inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.