Skip to content

Comments

Feat/analytics and insight functions and tests#106

Merged
Utilitycoder merged 11 commits intoFundable-Protocol:mainfrom
FrankiePower:feat/analytics_and_insight_functions
Jul 22, 2025
Merged

Feat/analytics and insight functions and tests#106
Utilitycoder merged 11 commits intoFundable-Protocol:mainfrom
FrankiePower:feat/analytics_and_insight_functions

Conversation

@FrankiePower
Copy link
Contributor

@FrankiePower FrankiePower commented Jun 2, 2025

Pull Request: Implement Analytics Functions for CampaignDonation Contract


🧠 Summary

This PR implements the get_campaign_progress and get_campaign_donor_count functions in the CampaignDonation contract, providing analytics for campaign performance. It enhances get_campaign_progress with capping, validation, rounding, and documentation, and adds get_campaign_donor_count with gas-optimized unique donor tracking. Comprehensive tests cover all edge cases, ensuring accuracy and robustness.


📌 Type of Change

  • Documentation (updates to docs or comments)
  • Bug fix (non-breaking change fixing issues)
  • Enhancement (adds new functionality)
  • Breaking change

Context

This PR completes the analytics functions for the CampaignDonation contract, enabling campaign owners and donors to track progress and donor engagement. get_campaign_progress calculates the percentage of funds raised, and get_campaign_donor_count counts unique donors. Fixes address gaps in get_campaign_progress (capping, validation, rounding) and implement get_campaign_donor_count with a gas-efficient storage-based approach using unique_donors mapping.


📝 Changes Description

  1. get_campaign_progress:

    • Added campaign ID validation (campaign_id <= campaign_counts).
    • Implemented rounding ((balance * 1000) / target / 10, round up if ≥ 0.5).
    • Capped progress at 100% for overfunded campaigns.
  2. get_campaign_donor_count:

    • Counts unique donors using unique_donors mapping, updated in donate_to_campaign.
    • Validates campaign ID, returns 0_u32 for invalid IDs.
  3. Tests:

    • Expanded test_get_campaign_progress for empty, partially funded, fully funded, overfunded.
    • Added test_get_campaign_donor_count for no donors, single donor, multiple donors, repeated donors.

Design Considerations

  1. Capping Progress:
    • Capped at 100% for overfunded campaigns to meet u8 (0-100) requirement, tested with 1500/1000.
  2. Gas Optimization:
    • Used unique_donors mapping for get_campaign_donor_count to avoid iterating donations, reducing gas for large lists.
  3. Rounding:
    • Implemented rounding up at ≥ 0.5 for get_campaign_progress to ensure precision.
  4. Edge Cases:
    • Handled invalid IDs, zero target, and empty campaigns; documented normal calculation for cancelled campaigns (no is_cancelled field).
  5. Tests:
    • Comprehensive coverage for all scenarios, ensuring robustness.

Acceptance Criteria

  1. Accurate Metrics:
    • ✅ Progress and donor counts are correct (e.g., 750/1000 = 75, 3 unique donors).
  2. View/Read-Only:
    • ✅ Both functions use @ContractState, no state changes.
  3. Gas-Efficient:
    • ✅ Minimal storage reads; unique_donors mapping optimizes donor count.
  4. Edge Cases:
    • ✅ Empty, overfunded, invalid ID, and zero-target campaigns handled.
    • ✅ Cancelled campaigns documented (progress/donors calculated normally).
  5. Unit Tests:
    • ✅ Cover empty, partially funded, fully funded, overfunded, single/multiple donors, invalid IDs.
  6. Documentation:
    • ✅ Usage examples in docstrings.

📸 Evidence

On Tests:
Screenshot 2025-06-02 at 08 24 21


⏰ Time Spent Breakdown

Total: ~8 hours

Day Focus Area Tasks
Day 1 🧠 Analysis & Design Analyzed requirements, identified gaps, designed fixes for both functions (~2 hours).
Day 1 🔨 Implementation Updated get_campaign_progress, implemented get_campaign_donor_count, added tests (~4 hours).
Day 1 ✅ Testing & Review Ran tests, verified edge cases, finalized documentation (~2 hours).

Checklist

  • Implement get_campaign_progress and get_campaign_donor_count.
  • Handle edge cases.
  • Optimize gas with unique_donors mapping.
  • Write comprehensive tests.
  • Add documentation with examples.
  • Ensure read-only behavior.
  • Verify with tests.
  • Run formatting.
  • Evidence provided.
  • Commented code (docstrings).
  • Closes Implement Analytics & Insights Functions in ICampaignDonation #100

Conclusion

The PR fully implements get_campaign_progress and get_campaign_donor_count, addressing all task requirements, technical considerations, and acceptance criteria. Both functions are accurate, read-only, and gas-efficient, with comprehensive tests and clear documentation. The unique_donors mapping optimizes donor counting, and all edge cases (including invalid IDs and cancellation assumptions) are handled.

Summary by CodeRabbit

  • New Features

    • Added the ability to view the funding progress of a campaign as a percentage.
    • Introduced a way to see the unique donor count for each campaign.
    • Unique donor counts are now updated automatically when new donors contribute.
  • Tests

    • Added tests to verify campaign progress calculation and unique donor tracking, including precision and multi-campaign scenarios.

@coderabbitai
Copy link

coderabbitai bot commented Jun 2, 2025

Walkthrough

Two analytics functions, get_campaign_progress and get_campaign_donor_count, were implemented in the campaign donation contract and exposed via the interface. Storage mappings for tracking unique donors per campaign were added, and the donation logic was updated to increment donor counts. Comprehensive tests were introduced to validate the new analytics features.

Changes

File(s) Change Summary
src/campaign_donation.cairo Added storage mappings for unique donors; implemented get_campaign_progress and get_campaign_donor_count; updated donation logic to track unique donors.
src/interfaces/ICampaignDonation.cairo Uncommented and included analytics function signatures in the interface; improved spacing/formatting.
tests/test_campaign_donation.cairo Added five tests covering campaign progress, donor count accuracy, repeat donors, and multi-campaign scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CampaignDonationContract

    User->>CampaignDonationContract: donate(campaign_id, amount)
    alt First-time donor to campaign
        CampaignDonationContract->>CampaignDonationContract: Mark donor as contributed
        CampaignDonationContract->>CampaignDonationContract: Increment unique_donors_count
    end
    CampaignDonationContract->>CampaignDonationContract: Update campaign balance

    User->>CampaignDonationContract: get_campaign_progress(campaign_id)
    CampaignDonationContract->>CampaignDonationContract: Calculate (balance * 100 / target), cap at 100
    CampaignDonationContract-->>User: progress_percentage

    User->>CampaignDonationContract: get_campaign_donor_count(campaign_id)
    CampaignDonationContract-->>User: unique_donors_count
Loading

Estimated code review effort

2 (~18 minutes)

Suggested reviewers

  • mubarak23

Poem

A hop and a skip, new insights appear,
Donor counts tracked, campaign progress clear!
With every new gift, the numbers grow bright,
Analytics in place, all coded just right.
🥕 The bunnies rejoice, for data is king—
Let’s see what these clever new functions will bring!


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@FrankiePower
Copy link
Contributor Author

@mubarak23 this pr is up for review and is ready to be merged.

@mubarak23
Copy link
Contributor

@FrankiePower , fix the merge conflict above

@mubarak23 mubarak23 self-requested a review June 10, 2025 11:59
Copy link
Contributor

@mubarak23 mubarak23 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGFM,

let fix the merge conflict

@mubarak23
Copy link
Contributor

@FrankiePower are you still working on fixing this merge conflict

@FrankiePower
Copy link
Contributor Author

yes i am sorry about the delay. i will get back to you by end of day

@mubarak23
Copy link
Contributor

@FrankiePower are you still working on fixing this merge conflict

@mubarak23 mubarak23 closed this Jun 19, 2025
@FrankiePower
Copy link
Contributor Author

@mubarak23 chief sorry i wasn't able to attend to this since, but i am free now and would like to resolve it

@Utilitycoder Utilitycoder reopened this Jul 12, 2025
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Campaign Functions Lack Validation, Risk Overflow

The get_campaign_progress function has a potential u256 overflow: the multiplication (campaign.current_balance * 100) can panic if current_balance is very large. Additionally, both get_campaign_progress and get_campaign_donor_count functions lack campaign ID validation. They return misleading default values (0) for non-existent campaign IDs, contradicting the PR description's claim of adding validation.

src/campaign_donation.cairo#L311-L337

}
fn get_campaign_progress(self: @ContractState, campaign_id: u256) -> u8 {
let campaign: Campaigns = self.campaigns.read(campaign_id);
if campaign.target_amount == 0 {
return 0_u8;
}
let progress = (campaign.current_balance * 100) / campaign.target_amount;
// // Cap at 100% for overfunded campaigns
if progress > 100_u256 {
return 100_u8;
}
// Convert the calculated progress to u8 using try_into().
// This is a fallible conversion. unwrap() will panic if the value > 255.
let progress_u8: u8 = progress.try_into().unwrap();
// Return the u8 value.
progress_u8
}
fn get_campaign_donor_count(self: @ContractState, campaign_id: u256) -> u32 {
// Simply return the stored count of unique donors
self.unique_donors_count.read(campaign_id)
}

Fix in CursorFix in Web


Bug: Campaign ID Validation Missing

The get_campaign_donor_count function lacks validation for the campaign_id parameter. For non-existent campaign IDs, it misleadingly returns 0, implying a valid campaign with no donors rather than indicating an invalid ID. This contradicts the PR description's stated intent to include campaign ID validation.

src/campaign_donation.cairo#L333-L337

fn get_campaign_donor_count(self: @ContractState, campaign_id: u256) -> u32 {
// Simply return the stored count of unique donors
self.unique_donors_count.read(campaign_id)
}

Fix in CursorFix in Web


BugBot free trial expires on July 22, 2025
You have used $0.00 of your $50.00 spend limit so far. Manage your spend limit in the Cursor dashboard.

Was this report helpful? Give feedback by reacting with 👍 or 👎

@FrankiePower
Copy link
Contributor Author

@mubarak23 chief i am done with this issue. The PR is ready to be reviewed and merged.

@FrankiePower FrankiePower requested a review from mubarak23 July 18, 2025 01:07
@Utilitycoder
Copy link
Contributor

Please fix your test and formatting. And it will be merged asap.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
tests/test_campaign_donation.cairo (1)

806-806: Remove stray formatting marker.

There's a stray ~ marker on this line that appears to be a leftover from the diff formatting.

Apply this diff to clean up the formatting:

-    stop_cheat_caller_address(campaign_donation.contract_address);~
+    stop_cheat_caller_address(campaign_donation.contract_address);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dbc14ac and b97d754.

📒 Files selected for processing (2)
  • src/campaign_donation.cairo (3 hunks)
  • tests/test_campaign_donation.cairo (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/campaign_donation.cairo
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: tests
🔇 Additional comments (5)
tests/test_campaign_donation.cairo (5)

596-639: LGTM! Comprehensive test coverage for campaign progress calculation.

The test effectively validates the get_campaign_progress function across multiple scenarios with clear percentage calculations. The strategic donation amounts (300/1000=30%, 500/1000=50%, 1000/1000=100%) make the test easy to understand and verify.


641-694: Excellent precision testing for edge cases.

This test thoroughly validates the rounding behavior of the progress calculation, including the critical edge case where 99.9% should round down to 99%. The incremental donation approach effectively tests various precision scenarios.


810-867: Well-structured test for unique donor counting.

The test effectively validates the donor count functionality by systematically testing donations from different users and verifying the count increments correctly at each step. The setup properly handles multiple users with appropriate token approvals.


869-903: Critical test for unique donor logic.

This test validates the essential requirement that multiple donations from the same donor should only count as one unique donor. This is crucial for the integrity of the donor counting feature.


905-960: Excellent validation of campaign-isolated donor counting.

This test ensures that unique donor counts are properly tracked independently across different campaigns, validating that the same donor can contribute to multiple campaigns and be counted separately in each. The cross-campaign donation logic is well-tested.

@Utilitycoder Utilitycoder merged commit b65ff3d into Fundable-Protocol:main Jul 22, 2025
3 checks passed
@Utilitycoder
Copy link
Contributor

Thanks for the good work, Frank!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Analytics & Insights Functions in ICampaignDonation

3 participants