diff --git a/campaign/src/lib.rs b/campaign/src/lib.rs index ab93865..ef4453a 100644 --- a/campaign/src/lib.rs +++ b/campaign/src/lib.rs @@ -3,8 +3,8 @@ pub mod storage; pub mod types; -use soroban_sdk::{contract, contractimpl, Env, Vec}; -use types::{CampaignData, CampaignStatus, Error, MilestoneData, MilestoneStatus, StellarAsset, CampaignEvent}; +use soroban_sdk::{contract, contractimpl, Address, Env, Vec}; +use types::{CampaignData, CampaignStatus, Error, MilestoneData, MilestoneStatus, StellarAsset, CampaignEvent, AssetInfo}; use storage::{get_campaign, set_campaign, set_milestone}; pub const VERSION: u32 = 1; @@ -39,6 +39,7 @@ impl CampaignContract { end_time: u64, accepted_assets: Vec, milestones: Vec, + min_donation_amount: i128, ) -> Result<(), Error> { // Authorization check: creator must authorize this call creator.require_auth(); @@ -85,6 +86,7 @@ impl CampaignContract { status: CampaignStatus::Active, accepted_assets: accepted_assets.clone(), milestone_count, + min_donation_amount, }; set_campaign(&env, &campaign); @@ -107,6 +109,27 @@ impl CampaignContract { Ok(()) } + /// Issue #192 – Donate to the campaign, enforcing the minimum donation amount. + /// + /// Panics with `Error::DonationTooSmall` if `amount < min_donation_amount` (when min > 0). + /// Set `min_donation_amount` to 0 during `initialize` to disable enforcement. + pub fn donate(env: Env, donor: Address, amount: i128, _asset: AssetInfo) { + donor.require_auth(); + + let mut campaign: CampaignData = get_campaign(&env) + .unwrap_or_else(|| panic_with_error(&env, Error::AlreadyInitialized)); + + // Issue #192 – enforce minimum donation amount + if campaign.min_donation_amount > 0 && amount < campaign.min_donation_amount { + panic_with_error(&env, Error::DonationTooSmall); + } + + campaign.raised_amount += amount; + set_campaign(&env, &campaign); + + env.events().publish(("campaign", "donation_received"), (donor, amount)); + } + pub fn hello(env: Env) -> soroban_sdk::Symbol { soroban_sdk::Symbol::new(&env, "campaign") } @@ -173,6 +196,7 @@ fn panic_with_error(env: &Env, error: Error) -> ! { Error::CampaignNotActive => "CampaignNotActive", Error::CampaignEnded => "CampaignEnded", Error::GoalNotReached => "GoalNotReached", + Error::DonationTooSmall => "DonationTooSmall", }; env.panic_with_error(soroban_sdk::Symbol::new(env, error_name)) } diff --git a/campaign/src/types.rs b/campaign/src/types.rs index 52c3c80..646b3e3 100644 --- a/campaign/src/types.rs +++ b/campaign/src/types.rs @@ -23,6 +23,8 @@ pub enum Error { CampaignNotActive, // campaign must be Active to accept donations CampaignEnded, // campaign end_time has passed GoalNotReached, // cannot transition to GoalReached before reaching goal + /// Issue #192 – donation amount is below the campaign minimum + DonationTooSmall, } // ── Supporting enums ───────────────────────────────────────────────────────── @@ -123,6 +125,8 @@ pub struct CampaignData { pub status: CampaignStatus, pub accepted_assets: Vec, pub milestone_count: u32, + /// Issue #192 – minimum donation amount; set to 0 to disable enforcement + pub min_donation_amount: i128, } // ── Issue #168 – MilestoneData struct ────────────────────────────────────────