RustFund

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

The refund instructions don’t check whether the fundraising goal has been reached

[M-01] The refund instructions don’t check whether the fundraising goal has been reached

Summary

Contributors can refund their contributions even when the fundraising goal has been reached, despite the documentation stating otherwise:

Can request refunds if the campaign **fails to meet the goal** and the deadline is reached.

Vulnerability Details

Below is the implementation of the refund function. As seen in the code, there is no check on whether the fundraising goal (fund.goal) has been met.

pub fn refund(ctx: Context<FundRefund>) -> Result<()> {
let amount = ctx.accounts.contribution.amount;
// Check if the deadline has been reached
if ctx.accounts.fund.deadline != 0 && ctx.accounts.fund.deadline > Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
return Err(ErrorCode::DeadlineNotReached.into());
}
// Perform the refund operation
**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.contributor.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.contributor.to_account_info().lamports()
.checked_add(amount)
.ok_or(ErrorCode::CalculationOverflow)?;
// Reset contribution amount after refund
ctx.accounts.contribution.amount = 0;
Ok(())
}

Currently, the refund function only checks if the campaign’s deadline has passed but does not check if the fundraising goal has been met. This means that even if a campaign reaches its goal, contributors can still refund their contributions, effectively withdrawing funds that should have been locked for the project.

Impact

Contributors can refund their contributions at any time, even after the campaign has successfully reached its goal. This could allow contributors to withdraw their funds post-success, potentially draining the fund and leading to unintended consequences. This violates the expected behavior of the contract, where funds should remain locked once the goal is achieved.

Tools Used

Manual Review

Recommendations

Modify the refund function to include a check that ensures refunds are only allowed if the campaign has failed (i.e., fund.goal <= fund.raised_amount). This will prevent contributors from withdrawing their funds once the goal has been met.

pub fn refund(ctx: Context<FundRefund>) -> Result<()> {
let amount = ctx.accounts.contribution.amount;
// Check if the deadline has been reached
if ctx.accounts.fund.deadline != 0 && ctx.accounts.fund.deadline > Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
return Err(ErrorCode::DeadlineNotReached.into());
}
+ if ctx.accounts.fund.goal <= ctx.accounts.fund.raised_amount {
+ return Err(ErrorCode::GoalHasBeenReached.into())
+ }
// Perform the refund operation
**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.contributor.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.contributor.to_account_info().lamports()
.checked_add(amount)
.ok_or(ErrorCode::CalculationOverflow)?;
// Reset contribution amount after refund
ctx.accounts.contribution.amount = 0;
Ok(())
}
Updates

Appeal created

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

There is no check for goal achievement in `refund` function

Support

FAQs

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