Rust Fund

AI First Flight #9
Beginner FriendlyRust
EXP
View results
Submission Details
Impact: low
Likelihood: high
Invalid

Missing Event Emissions for Critical State Changes

Root + Impact

Description

  • The contract does not emit any events for critical state changes such as campaign creation, contributions, refunds, withdrawals, or deadline updates. Events are essential for off-chain monitoring, indexing, analytics, and building user interfaces. Without events, tracking protocol activity requires inefficient on-chain account polling.

pub fn contribute(ctx: Context<FundContribute>, amount: u64) -> Result<()> {
// ... performs contribution ...
// ❌ No event emitted
Ok(())
}
pub fn withdraw(ctx: Context<FundWithdraw>) -> Result<()> {
// ... transfers funds ...
// ❌ No event emitted
Ok(())
}

Risk

Likelihood:

  • 100% of state changes occur without events

  • Any off-chain system (indexers, UIs, analytics) immediately affected

  • Not a "might happen" - it's currently happening to all users

Impact:

  • Off-chain indexers cannot efficiently track campaign state

  • UIs must poll accounts frequently (higher RPC costs)

  • No audit trail for historical actions

  • Difficult to debug issues or investigate suspicious activity

  • Analytics and dashboards are harder to build

Proof of Concept

N/A

Recommended Mitigation


FIX: Define event structs

#[event]
pub struct FundCreated {
pub fund: Pubkey,
pub creator: Pubkey,
pub name: String,
pub goal: u64,
pub timestamp: i64,
}
#[event]
pub struct ContributionMade {
pub fund: Pubkey,
pub contributor: Pubkey,
pub amount: u64,
pub total_raised: u64,
pub timestamp: i64,
}
#[event]
pub struct DeadlineSet {
pub fund: Pubkey,
pub deadline: u64,
pub timestamp: i64,
}
#[event]
pub struct RefundProcessed {
pub fund: Pubkey,
pub contributor: Pubkey,
pub amount: u64,
pub timestamp: i64,
}
#[event]
pub struct FundsWithdrawn {
pub fund: Pubkey,
pub creator: Pubkey,
pub amount: u64,
pub timestamp: i64,
}
// ✅ FIX: Emit events in functions
pub fn fund_create(ctx: Context<FundCreate>, name: String, description: String, goal: u64) -> Result<()> {
let fund = &mut ctx.accounts.fund;
fund.name = name.clone();
fund.description = description;
fund.goal = goal;
fund.deadline = 0;
fund.creator = ctx.accounts.creator.key();
fund.amount_raised = 0;
fund.deadline_set = false;
emit!(FundCreated {
fund: fund.key(),
creator: fund.creator,
name: name,
goal: goal,
timestamp: Clock::get()?.unix_timestamp,
});
Ok(())
}
pub fn contribute(ctx: Context<FundContribute>, amount: u64) -> Result<()> {
// ... perform contribution ...
emit!(ContributionMade {
fund: ctx.accounts.fund.key(),
contributor: ctx.accounts.contributor.key(),
amount: amount,
total_raised: ctx.accounts.fund.amount_raised,
timestamp: Clock::get()?.unix_timestamp,
});
Ok(())
}
pub fn set_deadline(ctx: Context<FundSetDeadline>, deadline: u64) -> Result<()> {
// ... set deadline ...
emit!(DeadlineSet {
fund: ctx.accounts.fund.key(),
deadline: deadline,
timestamp: Clock::get()?.unix_timestamp,
});
Ok(())
}
pub fn refund(ctx: Context<FundRefund>) -> Result<()> {
let amount = ctx.accounts.contribution.amount;
// ... process refund ...
emit!(RefundProcessed {
fund: ctx.accounts.fund.key(),
contributor: ctx.accounts.contributor.key(),
amount: amount,
timestamp: Clock::get()?.unix_timestamp,
});
Ok(())
}
pub fn withdraw(ctx: Context<FundWithdraw>) -> Result<()> {
let amount = ctx.accounts.fund.amount_raised;
// ... process withdrawal ...
emit!(FundsWithdrawn {
fund: ctx.accounts.fund.key(),
creator: ctx.accounts.creator.key(),
amount: amount,
timestamp: Clock::get()?.unix_timestamp,
});
Ok(())
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 2 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!