From c9fa861e055106e5b789a0b350a31df8343d38df Mon Sep 17 00:00:00 2001 From: xqcxx Date: Wed, 25 Mar 2026 20:04:50 +0100 Subject: [PATCH] Add maximum participant cap to campaign contract - Add CapacityReached error variant (Error code 102) - Add MAX_CAP and PARTICIPANT_COUNT storage keys - Implement set_max_cap admin function to set capacity limit - Update register function to check and enforce capacity - Track participant count automatically on registration - Add get_participant_count and get_max_cap query functions - Cap value of 0 means unlimited participants (default behavior) Closes #4 --- contracts/campaign/src/lib.rs | 72 +++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 7 deletions(-) diff --git a/contracts/campaign/src/lib.rs b/contracts/campaign/src/lib.rs index 88837f38..84594035 100644 --- a/contracts/campaign/src/lib.rs +++ b/contracts/campaign/src/lib.rs @@ -5,7 +5,7 @@ #![no_std] -use soroban_sdk::{contract, contractimpl, contractmeta, contracterror, symbol_short, Env, Symbol}; +use soroban_sdk::{contract, contracterror, contractimpl, contractmeta, symbol_short, Env, Symbol}; #[contracterror] #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] @@ -13,18 +13,18 @@ use soroban_sdk::{contract, contractimpl, contractmeta, contracterror, symbol_sh pub enum Error { Unauthorized = 100, OutsideTimeWindow = 101, + CapacityReached = 102, } -contractmeta!( - key = "Description", - val = "Trivela campaign configuration" -); +contractmeta!(key = "Description", val = "Trivela campaign configuration"); const ADMIN: Symbol = symbol_short!("admin"); const CAMPAIGN_ACTIVE: Symbol = symbol_short!("active"); const PARTICIPANT: Symbol = symbol_short!("partic"); const START_TIME: Symbol = symbol_short!("start"); const END_TIME: Symbol = symbol_short!("end"); +const MAX_CAP: Symbol = symbol_short!("maxcap"); +const PARTICIPANT_COUNT: Symbol = symbol_short!("count"); #[contract] pub struct CampaignContract; @@ -37,6 +37,7 @@ impl CampaignContract { env.storage().instance().set(&CAMPAIGN_ACTIVE, &true); env.storage().instance().set(&START_TIME, &0u64); env.storage().instance().set(&END_TIME, &u64::MAX); + env.storage().instance().set(&PARTICIPANT_COUNT, &0u64); Ok(()) } @@ -68,6 +69,17 @@ impl CampaignContract { Ok(()) } + /// Set maximum participant cap (admin only). Set to 0 for unlimited. + pub fn set_max_cap(env: Env, admin: soroban_sdk::Address, max_cap: u64) -> Result<(), Error> { + admin.require_auth(); + let stored: soroban_sdk::Address = env.storage().instance().get(&ADMIN).unwrap(); + if stored != admin { + return Err(Error::Unauthorized); + } + env.storage().instance().set(&MAX_CAP, &max_cap); + Ok(()) + } + /// Register a participant (authorized caller). pub fn register(env: Env, participant: soroban_sdk::Address) -> Result { participant.require_auth(); @@ -81,10 +93,40 @@ impl CampaignContract { } let key = (PARTICIPANT, participant.clone()); - if env.storage().instance().get::<_, bool>(&key).unwrap_or(false) { + if env + .storage() + .instance() + .get::<_, bool>(&key) + .unwrap_or(false) + { return Ok(false); } + + // Check capacity if max_cap is set + let max_cap: u64 = env.storage().instance().get(&MAX_CAP).unwrap_or(0); + if max_cap > 0 { + let count: u64 = env + .storage() + .instance() + .get(&PARTICIPANT_COUNT) + .unwrap_or(0); + if count >= max_cap { + return Err(Error::CapacityReached); + } + } + env.storage().instance().set(&key, &true); + + // Increment participant count + let count: u64 = env + .storage() + .instance() + .get(&PARTICIPANT_COUNT) + .unwrap_or(0); + env.storage() + .instance() + .set(&PARTICIPANT_COUNT, &(count + 1)); + env.storage().instance().extend_ttl(50, 100); Ok(true) } @@ -99,7 +141,23 @@ impl CampaignContract { /// Check if campaign is active. pub fn is_active(env: Env) -> bool { - env.storage().instance().get(&CAMPAIGN_ACTIVE).unwrap_or(false) + env.storage() + .instance() + .get(&CAMPAIGN_ACTIVE) + .unwrap_or(false) + } + + /// Get current participant count. + pub fn get_participant_count(env: Env) -> u64 { + env.storage() + .instance() + .get(&PARTICIPANT_COUNT) + .unwrap_or(0) + } + + /// Get maximum participant cap (0 means unlimited). + pub fn get_max_cap(env: Env) -> u64 { + env.storage().instance().get(&MAX_CAP).unwrap_or(0) } }