Skip to content
Merged
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
34 changes: 31 additions & 3 deletions contract/contract/src/base/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,32 @@ pub enum EventStatus {
#[contracttype]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EventDetails {
pub id: u64,
pub id: BytesN<32>,
pub title: String,
pub creator: Address,
pub ticket_price: i128,
pub max_attendees: u32,
pub deadline: u64,
pub token: Address,
}

#[contracttype]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EventMetrics {
pub tickets_sold: u32,
}

impl Default for EventMetrics {
fn default() -> Self {
Self::new()
}
}

impl EventMetrics {
/// Creates zero-initialized metrics for a new event.
pub fn new() -> Self {
Self { tickets_sold: 0 }
}
}

/// Represents the type of a ticket.
Expand Down Expand Up @@ -290,6 +310,10 @@ pub enum StorageKey {
EventPlatformFees(u64),
// Track if someone bought a ticket
UserTicket(u64, Address),
// Event details keyed by event id
Event(BytesN<32>),
// Per-event metrics (tickets sold, etc.)
EventMetrics(BytesN<32>),
}

#[cfg(test)]
Expand Down Expand Up @@ -462,18 +486,22 @@ mod tests {
use soroban_sdk::testutils::Address as _;
let env = Env::default();
let creator = soroban_sdk::Address::generate(&env);
let token = soroban_sdk::Address::generate(&env);
let id = soroban_sdk::BytesN::from_array(&env, &[1u8; 32]);
let event = EventDetails {
id: 1,
id: id.clone(),
title: String::from_str(&env, "Nevo Launch"),
creator: creator.clone(),
ticket_price: 500,
max_attendees: 100,
deadline: 1_700_000_000,
token: token.clone(),
};
assert_eq!(event.id, 1);
assert_eq!(event.id, id);
assert_eq!(event.ticket_price, 500);
assert_eq!(event.max_attendees, 100);
assert_eq!(event.deadline, 1_700_000_000);
assert_eq!(event.creator, creator);
assert_eq!(event.token, token);
}
}
38 changes: 28 additions & 10 deletions contract/contract/src/crowdfunding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use crate::base::{
},
types::{
CampaignDetails, CampaignLifecycleStatus, CampaignMetrics, Contribution,
EmergencyWithdrawal, MultiSigConfig, PoolConfig, PoolContribution, PoolMetadata,
PoolMetrics, PoolState, StorageKey, MAX_DESCRIPTION_LENGTH, MAX_HASH_LENGTH,
MAX_STRING_LENGTH, MAX_URL_LENGTH,
EmergencyWithdrawal, EventDetails, EventMetrics, MultiSigConfig, PoolConfig,
PoolContribution, PoolMetadata, PoolMetrics, PoolState, StorageKey,
MAX_DESCRIPTION_LENGTH, MAX_HASH_LENGTH, MAX_STRING_LENGTH, MAX_URL_LENGTH,
},
};
use crate::interfaces::crowdfunding::CrowdfundingTrait;
Expand Down Expand Up @@ -1922,16 +1922,34 @@ impl SecondCrowdfundingTrait for CrowdfundingContract {

fn create_event(
env: Env,
_id: BytesN<32>,
id: BytesN<32>,
title: String,
_creator: Address,
_ticket_price: i128,
_max_attendees: u32,
_deadline: u64,
_token: Address,
creator: Address,
ticket_price: i128,
max_attendees: u32,
deadline: u64,
token: Address,
) -> Result<(), SecondCrowdfundingError> {
Self::validate_string_length(&title)?;
let _ = env;

let details = EventDetails {
id: id.clone(),
title,
creator,
ticket_price,
max_attendees,
deadline,
token,
};

env.storage()
.instance()
.set(&StorageKey::Event(id.clone()), &details);

env.storage()
.instance()
.set(&StorageKey::EventMetrics(id), &EventMetrics::new());

Ok(())
}
}
82 changes: 71 additions & 11 deletions contract/contract/test/create_event_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
use soroban_sdk::{testutils::Address as _, Address, BytesN, Env, String};

use crate::{
base::errors::SecondCrowdfundingError, crowdfunding::CrowdfundingContract,
base::{
errors::SecondCrowdfundingError,
types::{EventDetails, EventMetrics, StorageKey},
},
crowdfunding::CrowdfundingContract,
interfaces::second_crowdfunding::SecondCrowdfundingTrait,
};

Expand All @@ -14,6 +18,7 @@ fn string_of_len(env: &Env, len: usize) -> String {
#[test]
fn test_create_event_success_path_returns_ok_for_valid_titles() {
let env = Env::default();
let contract_id = env.register(CrowdfundingContract, ());

let creator = Address::generate(&env);
let token = Address::generate(&env);
Expand All @@ -25,16 +30,18 @@ fn test_create_event_success_path_returns_ok_for_valid_titles() {
let id = BytesN::from_array(&env, &[(index + 1) as u8; 32]);
let title = string_of_len(&env, title_len);

let result = <CrowdfundingContract as SecondCrowdfundingTrait>::create_event(
env.clone(),
id,
title,
creator.clone(),
100,
500,
base_deadline + index as u64,
token.clone(),
);
let result = env.as_contract(&contract_id, || {
<CrowdfundingContract as SecondCrowdfundingTrait>::create_event(
env.clone(),
id,
title,
creator.clone(),
100,
500,
base_deadline + index as u64,
token.clone(),
)
});

assert_eq!(
result,
Expand All @@ -43,3 +50,56 @@ fn test_create_event_success_path_returns_ok_for_valid_titles() {
);
}
}

#[test]
fn test_create_event_stores_event_details_and_initializes_metrics() {
let env = Env::default();
let contract_id = env.register(CrowdfundingContract, ());

let creator = Address::generate(&env);
let token = Address::generate(&env);
let id = BytesN::from_array(&env, &[42u8; 32]);
let title = String::from_str(&env, "Soroban Hackathon");
let ticket_price: i128 = 250;
let max_attendees: u32 = 100;
let deadline: u64 = env.ledger().timestamp() + 7 * 86_400;

env.as_contract(&contract_id, || {
let result = <CrowdfundingContract as SecondCrowdfundingTrait>::create_event(
env.clone(),
id.clone(),
title.clone(),
creator.clone(),
ticket_price,
max_attendees,
deadline,
token.clone(),
);

assert_eq!(result, Ok(()), "create_event should return Ok");

// Verify EventDetails stored correctly
let stored_details: EventDetails = env
.storage()
.instance()
.get(&StorageKey::Event(id.clone()))
.expect("EventDetails should be stored");

assert_eq!(stored_details.id, id, "id mismatch");
assert_eq!(stored_details.title, title, "title mismatch");
assert_eq!(stored_details.creator, creator, "creator mismatch");
assert_eq!(stored_details.ticket_price, ticket_price, "ticket_price mismatch");
assert_eq!(stored_details.max_attendees, max_attendees, "max_attendees mismatch");
assert_eq!(stored_details.deadline, deadline, "deadline mismatch");
assert_eq!(stored_details.token, token, "token mismatch");

// Verify EventMetrics initialized with 0 tickets sold
let stored_metrics: EventMetrics = env
.storage()
.instance()
.get(&StorageKey::EventMetrics(id.clone()))
.expect("EventMetrics should be stored");

assert_eq!(stored_metrics.tickets_sold, 0, "tickets_sold should be initialized to 0");
});
}
Loading