RustFund

First Flight #36
Beginner FriendlyRust
100 EXP
View results
Submission Details
Severity: medium
Valid

Inconsistent Fund State After Withdrawal

Summary

After a successful withdrawal by the campaign creator, the amount_raised field in the fund account is not reset or updated. This oversight leads to an inconsistent state, potentially causing misrepresentation of the campaign’s funds and creating opportunities for logical errors or unintended behavior in subsequent transactions.

Vulnerability Details

Flaw Description:
Upon a withdrawal operation, the contract transfers the funds from the campaign account to the creator’s account. However, the amount_raised field, which tracks the total contributions received, remains unchanged after the withdrawal. This means that the internal state of the fund still reflects the original raised amount, even though the actual funds have been moved.

  • Code Analysis:

  • The withdraw function currently performs the fund transfer as follows:

pub fn withdraw(ctx: Context<FundWithdraw>) -> Result<()> {
let amount = ctx.accounts.fund.amount_raised;
**ctx.accounts.fund.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.fund.to_account_info().lamports()
.checked_sub(amount)
.ok_or(ProgramError::InsufficientFunds)?;
**ctx.accounts.creator.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.creator.to_account_info().lamports()
.checked_add(amount)
.ok_or(ErrorCode::CalculationOverflow)?;
Ok(())
}

The function deducts the funds from the campaign account and credits the creator’s account, but does not update the amount_raised field. As a result, the contract state continues to indicate that the campaign has raised funds even after they have been withdrawn.

Impact

  • Operational Risks:
    The state inconsistency may lead to operational issues, such as repeated or erroneous calls to the withdrawal function, affecting the overall reliability of the contract.

  • User Trust:
    Contributors and campaign creators rely on accurate state representation to make informed decisions. An incorrect amount_raised can erode trust in the platform’s transparency and reliability.

  • Downstream Effects:
    Future contract logic or integrations (e.g., automated refund processes, success criteria evaluations) that depend on amount_raised could behave unpredictably, leading to further financial or reputational damage.

Tools Used

Manual Review

Recommendations

Reset or Update amount_raised:
Modify the withdraw function to reset amount_raised to zero or adjust it appropriately to reflect the current funds in the campaign account after a withdrawal. For example:

pub fn withdraw(ctx: Context<FundWithdraw>) -> Result<()> {
let amount = ctx.accounts.fund.amount_raised;
**ctx.accounts.fund.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.fund.to_account_info().lamports()
.checked_sub(amount)
.ok_or(ProgramError::InsufficientFunds)?;
**ctx.accounts.creator.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.creator.to_account_info().lamports()
.checked_add(amount)
.ok_or(ErrorCode::CalculationOverflow)?;
// Reset the amount_raised field to zero after withdrawal
let fund = &mut ctx.accounts.fund;
fund.amount_raised = 0;
Ok(())
}
Updates

Appeal created

bube Lead Judge 5 months ago
Submission Judgement Published
Validated
Assigned finding tags:

`amount_raised` is not reset to 0 in `withdraw` function

Support

FAQs

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