Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions soroban-contract/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
[workspace]
resolver = "2"
members = [
"contracts/pausable",
"contracts/upgradeable",
"contracts/tba_account",
"contracts/tba_registry",
"contracts/ticket_nft",
"contracts/ticket_factory",
"contracts/event_manager",
"contracts/marketplace",
"contracts/user_profile",
"tests/integration",
]
exclude = ["contracts/hello-world"]
Expand Down
30 changes: 15 additions & 15 deletions soroban-contract/contracts/event_manager/src/fuzz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
//! panics that could lead to a Denial of Service (DoS).

use super::*;
use soroban_sdk::{testutils::Address as _, Address, Env, String, Vec};
use proptest::prelude::*;
use soroban_sdk::{testutils::Address as _, testutils::Ledger, Address, Env, String, Vec};

// Mock implementation for cross-contract calls
#[contract]
Expand All @@ -33,15 +33,15 @@ fn setup(env: &Env) -> (EventManagerClient<'_>, Address) {
let contract_id = env.register(EventManager, ());
let client = EventManagerClient::new(env, &contract_id);
let mock_addr = env.register(MockContract, ());
let admin = Address::generate(env);
env.mock_all_auths();
// We try to initialize, if it fails it's already initialized (though in tests it should be fresh)
let _ = client.try_initialize(&env.current_contract_address(), &mock_addr);
let _ = client.try_initialize(&admin, &mock_addr);
(client, mock_addr)
}

proptest! {
#![proptest_config(ProptestConfig::with_cases(50))]

/// Fuzz test for event creation.
/// Validates that various inputs for event creation do not cause panics
/// and that basic constraints hold.
Expand All @@ -57,10 +57,10 @@ proptest! {
let env = Env::default();
let (client, mock_addr) = setup(&env);
let organizer = Address::generate(&env);

// Mock current ledger time to be 1000000
env.ledger().set_timestamp(1000000);

let params = CreateEventParams {
organizer: organizer.clone(),
theme: String::from_str(&env, &theme),
Expand All @@ -75,8 +75,8 @@ proptest! {

// Try to create event. We expect it to either succeed or return an Error.
// It MUST NOT panic.
let result = client.try_create_event(&params);
let result = client.try_create_event_v2(&params);

if let Ok(Ok(event_id)) = result {
let event = client.get_event(&event_id);
assert_eq!(event.organizer, organizer);
Expand All @@ -99,9 +99,9 @@ proptest! {
let (client, mock_addr) = setup(&env);
let organizer = Address::generate(&env);
let buyer = Address::generate(&env);

env.ledger().set_timestamp(1000000);

// Setup a valid event first
let params = CreateEventParams {
organizer: organizer.clone(),
Expand All @@ -114,21 +114,21 @@ proptest! {
payment_token: mock_addr.clone(),
tiers: Vec::new(&env),
};
if let Ok(Ok(event_id)) = client.try_create_event(&params) {

if let Ok(Ok(event_id)) = client.try_create_event_v2(&params) {
// Test purchase
let purchase_res = client.try_purchase_tickets(&buyer, &event_id, &tier_index, &quantity);

if purchase_res.is_ok() {
let event = client.get_event(&event_id);
// Total supply consistency
assert!(event.tickets_sold <= event.total_tickets);
}

// Test cancel and refund
client.cancel_event(&event_id);
let _ = client.try_claim_refund(&buyer, &event_id);

// Test withdraw (should fail for canceled event)
env.ledger().set_timestamp(4000000);
let withdraw_res = client.try_withdraw_funds(&event_id);
Expand Down
79 changes: 47 additions & 32 deletions soroban-contract/contracts/event_manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,9 @@ impl EventManager {
}

fn validate_ticket_price(price: i128) -> Result<(), Error> {
if price < 0 {
return Err(Error::NegativeTicketPrice);
}
if price > Self::MAX_TICKET_PRICE {
return Err(Error::TicketPriceOutOfRange);
}
Expand Down Expand Up @@ -896,45 +899,57 @@ impl EventManager {
Ok(())
}

fn validate_bounded_string(s: &String, max_bytes: u32) -> Result<(), Error> {
if s.len() > max_bytes {
return Err(Error::InvalidTierConfig); // Or some appropriate error
}
Ok(())
}
fn commit_organizer_create(env: &Env, organizer: &Address) {
let count_key = DataKey::OrganizerOpenEventCount(organizer.clone());
let open_count: u32 = env.storage().persistent().get(&count_key).unwrap_or(0);
env.storage()
.persistent()
.set(&count_key, &open_count.saturating_add(1));
Self::extend_persistent_ttl(env, &count_key);

fn validate_ticket_price(price: i128) -> Result<(), Error> {
if price < 0 {
return Err(Error::NegativeTicketPrice);
}
Ok(())
let ts_key = DataKey::OrganizerLastCreateTs(organizer.clone());
env.storage()
.instance()
.set(&ts_key, &env.ledger().timestamp());
upg::extend_instance_ttl(env);
}

fn enforce_organizer_limits_and_rate(_env: &Env, _organizer: &Address) -> Result<(), Error> {
// Placeholder for real logic
Ok(())
fn decrement_organizer_open_events(env: &Env, organizer: &Address) {
let count_key = DataKey::OrganizerOpenEventCount(organizer.clone());
let open_count: u32 = env.storage().persistent().get(&count_key).unwrap_or(0);
env.storage()
.persistent()
.set(&count_key, &open_count.saturating_sub(1));
Self::extend_persistent_ttl(env, &count_key);
}

fn validate_event_span(start: u64, end: u64) -> Result<(), Error> {
if end <= start {
return Err(Error::InvalidEndDate);
fn try_promote_from_waitlist(env: &Env, event_id: u32) {
let waitlist_key = DataKey::Waitlist(event_id);
let waitlist: Vec<Address> = env
.storage()
.persistent()
.get(&waitlist_key)
.unwrap_or_else(|| Vec::new(env));

if waitlist.is_empty() {
return;
}
Ok(())
}

fn validate_start_not_too_far(_start: u64, _current: u64) -> Result<(), Error> {
Ok(())
}
let promoted = waitlist.get(0).unwrap();

fn commit_organizer_create(env: &Env, organizer: &Address) {
let ts_key = DataKey::EventCounter; // Dummy key for timestamp if not defined
env.storage()
.instance()
.set(&ts_key, &env.ledger().timestamp());
upg::extend_instance_ttl(env);
}
let mut remaining = Vec::new(env);
for (i, addr) in waitlist.iter().enumerate() {
if i > 0 {
remaining.push_back(addr);
}
}
env.storage().persistent().set(&waitlist_key, &remaining);
Self::extend_persistent_ttl(env, &waitlist_key);

fn decrement_organizer_open_events(_env: &Env, _organizer: &Address) {
env.events().publish(
(Symbol::new(env, "waitlist_promoted"),),
(event_id, promoted),
);
}

fn get_and_increment_counter(env: &Env) -> Result<u32, Error> {
Expand Down Expand Up @@ -1043,7 +1058,7 @@ impl EventManager {
}
}

#[cfg(test)]
mod test;
#[cfg(test)]
mod fuzz;
#[cfg(test)]
mod test;
Loading