RustFund

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

[L-1] Deadline setting flag missing allowing users to withdraw fund and refund fund at anytime

Summary

There is no flag for setting deadline allowing contributor to request for refund at any time and fund creator to withdraw the fund at any time.

pub fn set_deadline(ctx: Context<FundSetDeadline>, deadline: u64) -> Result<()> {
let fund = &mut ctx.accounts.fund;
if fund.dealine_set {
return Err(ErrorCode::DeadlineAlreadySet.into());
}
fund.deadline = deadline;
Ok(())
}

Vulnerability Details

The function does not set a flag (deadline_set = true) after setting the deadline. This will cause override of the deadline multiple times. There are also no explicit checks that if deadline set in withdraw and refund functions as well which allow fund creator to withdraw fund at any time and contributor to refund their amount at any time. For example if deadline is not set in refund function then it will see deadline == 0 means that the condition effectively skips the check, allowing refunds immediately and in withdraw function there is no explicit check that if deadline passed or not so here fund creator can withdraw fund anytime causing issue to contributors.

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(())
}
}
pub fn refund(ctx: Context<FundRefund>) -> Result<()> {
let amount = ctx.accounts.contribution.amount;
if ctx.accounts.fund.deadline != 0 && ctx.accounts.fund.deadline > Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
return Err(ErrorCode::DeadlineNotReached.into());
}
**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(())
}

Impact

If the deadline is not set then this will create impact on withdraw function and refund function as there is no deadline set for withdrawing the funds by fund creator and contributors can ask for refund any time.

Tools Used

Manual Review

Recommendations

We have added deadline set field in fund struct and added flag in the set_deadline function. We have also added checks in the withdraw function and refund function so that until deadline is not set then fund owner and contributers cannot refund and withdraw their respective funds.

pub fn refund(ctx: Context<FundRefund>) -> Result<()> {
let fund = &ctx.accounts.fund;
if !fund.deadline_set {
return Err(ErrorCode::DeadlineNotSet.into()); // ✅ Prevent refunds if no deadline exists
}
let current_time = Clock::get()?.unix_timestamp as u64;
if current_time < fund.deadline {
return Err(ErrorCode::DeadlineNotReached.into()); // ✅ Refunds only after deadline passed
}
let contribution = &mut ctx.accounts.contribution;
let refund_amount = contribution.amount;
**ctx.accounts.fund.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.fund.to_account_info().lamports()
.checked_sub(refund_amount)
.ok_or(ProgramError::InsufficientFunds)?;
**ctx.accounts.contributor.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.contributor.to_account_info().lamports()
.checked_add(refund_amount)
.ok_or(ErrorCode::CalculationOverflow)?;
Ok(())
}
pub fn withdraw(ctx: Context<FundWithdraw>) -> Result<()> {
let fund = &ctx.accounts.fund;
if !fund.deadline_set {
return Err(ErrorCode::DeadlineNotSet.into()); // ✅ Prevent withdrawals if no deadline exists
}
let current_time = Clock::get()?.unix_timestamp as u64;
if current_time < fund.deadline {
return Err(ErrorCode::DeadlineNotReached.into()); // ✅ Creator can only withdraw after deadline reached
}
let amount = 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(())
}
pub fn set_deadline(ctx: Context<FundSetDeadline>, deadline: u64) -> Result<()> {
let fund = &mut ctx.accounts.fund;
if fund.deadline_set {
return Err(ErrorCode::DeadlineAlreadySet.into());
}
fund.deadline = deadline;
fund.deadline_set = true; // ✅ Update the flag
Ok(())
}
#[account]
#[derive(InitSpace)]
pub struct Fund {
#[max_len(200)]
pub name: String,
#[max_len(5000)]
pub description: String,
pub goal: u64,
pub deadline: u64,
pub creator: Pubkey,
pub amount_raised: u64,
pub deadline_set: bool, // ✅ Add this flag
}
Updates

Appeal created

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

Deadline set flag is not updated in `set_deadline` function

Support

FAQs

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