Skip to content

Implement Batch Donate Functionality #102

@Utilitycoder

Description

@Utilitycoder

Description

Implement a batch donation feature that allows donors to contribute to multiple campaigns in a single transaction. This enhancement significantly improves user experience by reducing transaction costs and time for donors who want to support multiple campaigns.

Code Reference

/// Batch donations to multiple campaigns
fn batch_donate(
    ref self: TContractState,
    campaign_amounts: Array<(u256, u256)> // Array of (campaign_id, amount)
);

Functional Requirements

The batch_donate function should:

  • Accept an array of (campaign_id, amount) tuples
  • Process multiple donations in a single transaction
  • Validate each donation individually
  • Handle partial failures gracefully
  • Emit events for each successful donation

Tasks

  • Add function signature to ICampaignDonation interface
  • Implement batch_donate function
    • Validate input array is not empty
    • Calculate total donation amount
    • Single approval check for total amount
    • Iterate through campaign_amounts array
    • For each campaign:
      • Validate campaign exists
      • Check campaign is active (not closed/cancelled)
      • Validate donation amount > 0
      • Process donation (reuse donate_to_campaign logic)
      • Track successful donations
    • Handle failures appropriately
    • Emit batch donation event

Technical Considerations

1. Token Approval Optimization

// Calculate total amount needed
let total_amount = calculate_total_amount(campaign_amounts);

// Single transfer for all donations
token.transfer_from(donor, contract, total_amount);

// Then distribute to individual campaigns

2. Error Handling Strategies

All-or-Nothing

  • If any donation fails, revert entire transaction
  • Pros: Simple, atomic
  • Cons: One invalid campaign blocks all donations

3. Gas Optimization

  • Limit maximum campaigns per batch (e.g., 10-20)
  • Consider gas refunds for unused donations
  • Optimize storage access patterns

4. Event Structure

#[derive(Drop, starknet::Event)]
struct BatchDonationProcessed {
    donor: ContractAddress,
    total_campaigns: u32,
    successful_donations: u32,
    total_amount: u256,
    results: Array<DonationResult>,
}

#[derive(Drop, starknet::Event)]
struct DonationResult {
    campaign_id: u256,
    amount: u256,
    success: bool,
    donation_id: u256,
}

Acceptance Criteria

  • Function accepts array of (campaign_id, amount) tuples
  • Single token approval covers all donations
  • Each donation is validated individually
  • Failed donations revert all operations
  • Appropriate events are emitted
  • Gas usage is optimized for typical batch sizes (5-10 campaigns)
  • Comprehensive tests cover:
    • Single campaign batch
    • Multiple valid campaigns
    • Mix of valid and invalid campaigns
    • Empty array rejection
    • Insufficient token balance
    • Campaigns reaching goal mid-batch

Security Considerations

  • Reentrancy protection
  • Integer overflow in the total calculation
  • Denial of Service via large arrays

Metadata

Metadata

Assignees

Labels

onlydust-waveContribute to awesome OSS repos during OnlyDust's open source week

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions