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
70 changes: 59 additions & 11 deletions contracts/raffle/src/instance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,11 @@ pub struct Contract;
#[derive(Clone, PartialEq, Eq, Debug)]
#[contracttype]
pub enum RaffleStatus {
Open = 0,
Active = 1,
Drawing = 2,
Finalized = 3,
Claimed = 4,
Cancelled = 5,
Failed = 6, // min_tickets threshold not met at draw time
Active = 0,
Drawing = 1,
Finalized = 2,
Cancelled = 3,
Failed = 4, // min_tickets threshold not met at draw time
}

#[derive(Clone, PartialEq, Eq, Debug)]
Expand Down Expand Up @@ -473,7 +471,7 @@ impl Contract {
prize_amount: config.prize_amount,
prizes: config.prizes.clone(),
tickets_sold: 0,
status: RaffleStatus::Open,
status: RaffleStatus::Active,
prize_deposited: false,
winners: Vec::new(&env),
claimed_winners: Vec::new(&env),
Expand Down Expand Up @@ -510,6 +508,12 @@ impl Contract {
}


if raffle.status != RaffleStatus::Active {
return Err(Error::InvalidStateTransition);
}
if raffle.prize_deposited {
return Err(Error::PrizeAlreadyDeposited);
}

// Effects: update state BEFORE external call (CEI pattern)
raffle.prize_deposited = true;
Expand Down Expand Up @@ -549,9 +553,12 @@ impl Contract {


// --- 1. CHECKS ---
if raffle.status != RaffleStatus::Open {
if raffle.status != RaffleStatus::Active {
return Err(Error::RaffleInactive);
}
if !raffle.prize_deposited {
return Err(Error::InvalidStateTransition);
}
if raffle.end_time != 0 && env.ledger().timestamp() > raffle.end_time {
return Err(Error::RaffleExpired);
}
Expand Down Expand Up @@ -596,7 +603,7 @@ impl Contract {
&env,
"status_changed",
RaffleStatusChanged {
old_status,
old_status: RaffleStatus::Active,
new_status: RaffleStatus::Drawing,
timestamp,
},
Expand Down Expand Up @@ -650,6 +657,47 @@ impl Contract {
);


if raffle.status == RaffleStatus::Active {
if (raffle.end_time != 0 && env.ledger().timestamp() >= raffle.end_time)
|| raffle.tickets_sold >= raffle.max_tickets
{
raffle.status = RaffleStatus::Drawing;
publish_event(
&env,
"status_changed",
RaffleStatusChanged {
old_status: RaffleStatus::Active,
new_status: RaffleStatus::Drawing,
timestamp: env.ledger().timestamp(),
},
);
}
}

if raffle.status != RaffleStatus::Drawing {
return Err(Error::InvalidStateTransition);
}

if raffle.tickets_sold == 0 {
return Err(Error::NoTicketsSold);
}

// If a minimum ticket threshold was set and not met, mark as Failed
// so the creator can reclaim the prize via refund_prize.
if raffle.min_tickets > 0 && raffle.tickets_sold < raffle.min_tickets {
raffle.status = RaffleStatus::Failed;
write_raffle(&env, &raffle);
publish_event(
&env,
"status_changed",
RaffleStatusChanged {
old_status: RaffleStatus::Drawing,
new_status: RaffleStatus::Failed,
timestamp: env.ledger().timestamp(),
},
);
return Ok(());
}

publish_event(
&env,
Expand Down Expand Up @@ -815,7 +863,7 @@ impl Contract {
&env,
"status_changed",
RaffleStatusChanged {
old_status,
old_status: RaffleStatus::Active,
new_status: RaffleStatus::Drawing,
timestamp: now,
},
Expand Down
4 changes: 2 additions & 2 deletions contracts/raffle/src/instance/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ fn test_creator_can_deposit_prize() {

// Should succeed — creator auth is mocked
client.deposit_prize();
assert_eq!(client.get_raffle().status, RaffleStatus::Open);
assert_eq!(client.get_raffle().status, RaffleStatus::Active);
}

/// require_creator: creator can finalize raffle
Expand Down Expand Up @@ -1092,7 +1092,7 @@ fn test_deposit_prize_cei_state_active_after_call() {
client.deposit_prize();

let raffle = client.get_raffle();
assert!(raffle.status == RaffleStatus::Open);
assert!(raffle.status == RaffleStatus::Active);
assert!(raffle.prize_deposited);
}

Expand Down
Loading