RustFund

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

Broken Contribution Tracking Causes Refund Failures

Summary

contribute function does not update the contribution.amount field when contributors add funds, leading to incorrect refund calculations if the funding goal isn't met. The refund process relies on contribution.amount to determine how much each contributor should get back, meaning contributors may receive nothing or incorrect amounts in case of a refund.

Vulnerability Details

  • Contributions are stored in the Contribution struct:

#[account]
#[derive(InitSpace)]
pub struct Contribution {
pub contributor: Pubkey,
pub fund: Pubkey,
pub amount: u64,
}
  • However, the contribute function never updates contribution.amount when additional funds are added:

pub fn contribute(ctx: Context<FundContribute>, amount: u64) -> Result<()> {
let fund = &mut ctx.accounts.fund;
let contribution = &mut ctx.accounts.contribution;
if fund.deadline != 0 && fund.deadline < Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
return Err(ErrorCode::DeadlineReached.into());
}
// Initialize or update contribution record
if contribution.contributor == Pubkey::default() {
contribution.contributor = ctx.accounts.contributor.key();
contribution.fund = fund.key();
contribution.amount = 0; // Only initialized, but never updated
}
// Transfer SOL from contributor to fund account
let cpi_context = CpiContext::new(
ctx.accounts.system_program.to_account_info(),
system_program::Transfer {
from: ctx.accounts.contributor.to_account_info(),
to: fund.to_account_info(),
},
);
system_program::transfer(cpi_context, amount)?;
fund.amount_raised += amount;
Ok(())
}

Impact

Since FundRefund processes refunds based on contribution.amount, this leads to:

  1. Funds incorrectly distributed during refunds → Some contributors may lose their money entirely.

  2. Loss of contributor trust → Crowdfunding is based on fairness; if refunds break, the contract is unusable.

  3. Potential legal consequences → A crowdfunding platform failing to properly refund users can face liability.

Tools Used

Anchor Framework for Testing

Proof of Concept

it("Fails to process refunds correctly due to incorrect contribution tracking", async () => {
// First contribution: 100
await program.methods
.contribute(new anchor.BN(100))
.accounts({ fund: fundPDA, contributor: contributor.publicKey, contribution: contributionPDA })
.signers([contributor])
.rpc();
let contribution = await program.account.contribution.fetch(contributionPDA);
expect(contribution.amount.toString()).to.equal("100"); // Expected: 100
// Second contribution of 50 (should total 150)
await program.methods
.contribute(new anchor.BN(50))
.accounts({ fund: fundPDA, contributor: contributor.publicKey, contribution: contributionPDA })
.signers([contributor])
.rpc();
contribution = await program.account.contribution.fetch(contributionPDA);
expect(contribution.amount.toString()).to.equal("100"); // ❌ Bug: Should be 150 but remains 100
// Now simulate a refund process
await program.methods
.refund()
.accounts({ fund: fundPDA, contributor: contributor.publicKey, contribution: contributionPDA })
.signers([contributor])
.rpc();
const refundedBalance = await getContributorBalance(contributor.publicKey);
expect(refundedBalance).to.be.lessThan(originalBalance); // ❌ Bug: Contributor lost money
});

Recommendations

Modify contribute to update contribution.amount before completing the transaction:

pub fn contribute(ctx: Context<FundContribute>, amount: u64) -> Result<()> {
let fund = &mut ctx.accounts.fund;
let contribution = &mut ctx.accounts.contribution;
// Ensure contributions are tracked properly
if contribution.contributor == Pubkey::default() {
contribution.contributor = ctx.accounts.contributor.key();
contribution.fund = fund.key();
contribution.amount = 0;
}
// ✅ Fix: Update contribution amount correctly
contribution.amount = contribution
.amount
.checked_add(amount)
.ok_or(ErrorCode::CalculationOverflow)?;
// Rest of function logic...
}
Updates

Appeal created

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

Contribution amount is not updated

Support

FAQs

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