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
No fields configured for Feature.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions