@@ -56,9 +56,9 @@ fn get_or_init_non_owner_total(env: &Env, event_id: u64) -> Result<i128, Error>
5656
5757pub fn create_event ( env : & Env , params : CreateEventParams , op_id : BytesN < 32 > ) -> Result < u64 , Error > {
5858 admin:: require_not_paused ( env) ?;
59- idempotency:: require_unseen ( env, & op_id) ?;
6059
6160 params. owner . require_auth ( ) ;
61+ idempotency:: require_unseen ( env, & params. owner , & op_id) ?;
6262
6363 token_whitelist:: require_supported ( env, & params. token ) ?;
6464
@@ -182,7 +182,7 @@ pub fn create_event(env: &Env, params: CreateEventParams, op_id: BytesN<32>) ->
182182 . publish ( env) ;
183183 }
184184
185- idempotency:: mark_seen ( env, & op_id) ;
185+ idempotency:: mark_seen ( env, & params . owner , & op_id) ;
186186 Ok ( id)
187187}
188188
@@ -273,7 +273,6 @@ pub fn add_funds(
273273 op_id : BytesN < 32 > ,
274274) -> Result < ( ) , Error > {
275275 admin:: require_not_paused ( env) ?;
276- idempotency:: require_unseen ( env, & op_id) ?;
277276
278277 if amount <= 0 {
279278 return Err ( Error :: InvalidContributionAmount ) ;
@@ -288,6 +287,7 @@ pub fn add_funds(
288287 }
289288
290289 from. require_auth ( ) ;
290+ idempotency:: require_unseen ( env, & from, & op_id) ?;
291291
292292 let is_non_owner = from != event. owner ;
293293 let prior_contribution = if is_non_owner {
@@ -330,13 +330,13 @@ pub fn add_funds(
330330
331331 evt:: FundsAdded {
332332 event_id,
333- contributor : from,
333+ contributor : from. clone ( ) ,
334334 amount : credited,
335335 new_remaining : event. remaining_escrow ,
336336 }
337337 . publish ( env) ;
338338
339- idempotency:: mark_seen ( env, & op_id) ;
339+ idempotency:: mark_seen ( env, & from , & op_id) ;
340340 Ok ( ( ) )
341341}
342342
@@ -345,7 +345,6 @@ pub fn add_funds(
345345// ============================================================
346346pub fn start_cancel ( env : & Env , event_id : u64 , op_id : BytesN < 32 > ) -> Result < ( ) , Error > {
347347 admin:: require_not_paused ( env) ?;
348- idempotency:: require_unseen ( env, & op_id) ?;
349348
350349 let mut event = storage:: get_event ( env, event_id) . ok_or ( Error :: EventNotFound ) ?;
351350 if !matches ! ( event. status, EventStatus :: Active ) {
@@ -366,7 +365,9 @@ pub fn start_cancel(env: &Env, event_id: u64, op_id: BytesN<32>) -> Result<(), E
366365 }
367366 }
368367
369- resolve_manager ( env, event_id, & event. owner ) . require_auth ( ) ;
368+ let manager = resolve_manager ( env, event_id, & event. owner ) ;
369+ manager. require_auth ( ) ;
370+ idempotency:: require_unseen ( env, & manager, & op_id) ?;
370371
371372 let remaining = event. remaining_escrow ;
372373 let count = storage:: contributor_count ( env, event_id) ;
@@ -395,7 +396,7 @@ pub fn start_cancel(env: &Env, event_id: u64, op_id: BytesN<32>) -> Result<(), E
395396 storage:: set_event ( env, event_id, & event) ;
396397 storage:: set_non_owner_contribution_total ( env, event_id, 0 ) ;
397398 evt:: EventCancelled { id : event_id } . publish ( env) ;
398- idempotency:: mark_seen ( env, & op_id) ;
399+ idempotency:: mark_seen ( env, & manager , & op_id) ;
399400 return Ok ( ( ) ) ;
400401 }
401402
@@ -410,7 +411,7 @@ pub fn start_cancel(env: &Env, event_id: u64, op_id: BytesN<32>) -> Result<(), E
410411 event. status = EventStatus :: Cancelling ;
411412 storage:: set_event ( env, event_id, & event) ;
412413
413- idempotency:: mark_seen ( env, & op_id) ;
414+ idempotency:: mark_seen ( env, & manager , & op_id) ;
414415 Ok ( ( ) )
415416}
416417
@@ -421,7 +422,10 @@ pub fn process_cancel_batch(
421422 op_id : BytesN < 32 > ,
422423) -> Result < u32 , Error > {
423424 admin:: require_not_paused ( env) ?;
424- idempotency:: require_unseen ( env, & op_id) ?;
425+ // Permissionless crank: no caller to authorize, so namespace under the
426+ // contract's own address — isolated from every user/privileged domain.
427+ let domain = env. current_contract_address ( ) ;
428+ idempotency:: require_unseen ( env, & domain, & op_id) ?;
425429
426430 let event = storage:: get_event ( env, event_id) . ok_or ( Error :: EventNotFound ) ?;
427431 if !matches ! ( event. status, EventStatus :: Cancelling ) {
@@ -475,13 +479,14 @@ pub fn process_cancel_batch(
475479 storage:: set_cancellation_state ( env, event_id, & state) ;
476480 let remaining_to_process = state. count_at_start . saturating_sub ( state. next_idx ) ;
477481
478- idempotency:: mark_seen ( env, & op_id) ;
482+ idempotency:: mark_seen ( env, & domain , & op_id) ;
479483 Ok ( remaining_to_process)
480484}
481485
482486pub fn finalize_cancel ( env : & Env , event_id : u64 , op_id : BytesN < 32 > ) -> Result < ( ) , Error > {
483487 admin:: require_not_paused ( env) ?;
484- idempotency:: require_unseen ( env, & op_id) ?;
488+ let domain = env. current_contract_address ( ) ;
489+ idempotency:: require_unseen ( env, & domain, & op_id) ?;
485490
486491 let mut event = storage:: get_event ( env, event_id) . ok_or ( Error :: EventNotFound ) ?;
487492 if !matches ! ( event. status, EventStatus :: Cancelling ) {
@@ -516,7 +521,7 @@ pub fn finalize_cancel(env: &Env, event_id: u64, op_id: BytesN<32>) -> Result<()
516521
517522 evt:: EventCancelled { id : event_id } . publish ( env) ;
518523
519- idempotency:: mark_seen ( env, & op_id) ;
524+ idempotency:: mark_seen ( env, & domain , & op_id) ;
520525 Ok ( ( ) )
521526}
522527
@@ -531,7 +536,6 @@ pub fn submit(
531536 op_id : BytesN < 32 > ,
532537) -> Result < ( ) , Error > {
533538 admin:: require_not_paused ( env) ?;
534- idempotency:: require_unseen ( env, & op_id) ?;
535539
536540 let event = storage:: get_event ( env, event_id) . ok_or ( Error :: EventNotFound ) ?;
537541 if !matches ! ( event. status, EventStatus :: Active ) {
@@ -547,6 +551,7 @@ pub fn submit(
547551 }
548552
549553 applicant. require_auth ( ) ;
554+ idempotency:: require_unseen ( env, & applicant, & op_id) ?;
550555
551556 // Reused rather than adding a new variant — stays inside the
552557 // contracterror 50-variant cap (see BACKLOG.md L7 for precedent).
@@ -583,12 +588,12 @@ pub fn submit(
583588
584589 evt:: Submitted {
585590 event_id,
586- applicant,
591+ applicant : applicant . clone ( ) ,
587592 content_uri,
588593 }
589594 . publish ( env) ;
590595
591- idempotency:: mark_seen ( env, & op_id) ;
596+ idempotency:: mark_seen ( env, & applicant , & op_id) ;
592597 Ok ( ( ) )
593598}
594599
@@ -602,7 +607,6 @@ pub fn withdraw_submission(
602607 op_id : BytesN < 32 > ,
603608) -> Result < ( ) , Error > {
604609 admin:: require_not_paused ( env) ?;
605- idempotency:: require_unseen ( env, & op_id) ?;
606610
607611 let event = storage:: get_event ( env, event_id) . ok_or ( Error :: EventNotFound ) ?;
608612 if !matches ! ( event. status, EventStatus :: Active ) {
@@ -615,6 +619,7 @@ pub fn withdraw_submission(
615619 }
616620
617621 applicant. require_auth ( ) ;
622+ idempotency:: require_unseen ( env, & applicant, & op_id) ?;
618623
619624 if storage:: get_submission ( env, event_id, & applicant) . is_none ( ) {
620625 return Err ( Error :: SubmissionNotFound ) ;
@@ -624,11 +629,11 @@ pub fn withdraw_submission(
624629
625630 evt:: SubmissionWithdrawn {
626631 event_id,
627- applicant,
632+ applicant : applicant . clone ( ) ,
628633 }
629634 . publish ( env) ;
630635
631- idempotency:: mark_seen ( env, & op_id) ;
636+ idempotency:: mark_seen ( env, & applicant , & op_id) ;
632637 Ok ( ( ) )
633638}
634639
@@ -642,7 +647,6 @@ pub fn select_winners(
642647 op_id : BytesN < 32 > ,
643648) -> Result < ( ) , Error > {
644649 admin:: require_not_paused ( env) ?;
645- idempotency:: require_unseen ( env, & op_id) ?;
646650
647651 let event = storage:: get_event ( env, event_id) . ok_or ( Error :: EventNotFound ) ?;
648652 if !matches ! ( event. status, EventStatus :: Active ) {
@@ -652,7 +656,9 @@ pub fn select_winners(
652656 return Err ( Error :: InvalidPillar ) ;
653657 }
654658
655- resolve_manager ( env, event_id, & event. owner ) . require_auth ( ) ;
659+ let manager = resolve_manager ( env, event_id, & event. owner ) ;
660+ manager. require_auth ( ) ;
661+ idempotency:: require_unseen ( env, & manager, & op_id) ?;
656662
657663 let existing_count = storage:: winner_count ( env, event_id) ;
658664 match event. release_kind {
@@ -804,7 +810,7 @@ pub fn select_winners(
804810 }
805811 . publish ( env) ;
806812
807- idempotency:: mark_seen ( env, & op_id) ;
813+ idempotency:: mark_seen ( env, & manager , & op_id) ;
808814 Ok ( ( ) )
809815}
810816
@@ -818,7 +824,6 @@ pub fn claim_prize(
818824 op_id : BytesN < 32 > ,
819825) -> Result < ( ) , Error > {
820826 admin:: require_not_paused ( env) ?;
821- idempotency:: require_unseen ( env, & op_id) ?;
822827
823828 let mut event = storage:: get_event ( env, event_id) . ok_or ( Error :: EventNotFound ) ?;
824829 if !matches ! ( event. status, EventStatus :: Active ) {
@@ -831,6 +836,7 @@ pub fn claim_prize(
831836 let award =
832837 storage:: get_prize_award ( env, event_id, position) . ok_or ( Error :: InvalidWinnerPosition ) ?;
833838 award. recipient . require_auth ( ) ;
839+ idempotency:: require_unseen ( env, & award. recipient , & op_id) ?;
834840
835841 let anchor =
836842 storage:: winner_at ( env, event_id, award. anchor_idx ) . ok_or ( Error :: InvalidWinnerPosition ) ?;
@@ -870,7 +876,7 @@ pub fn claim_prize(
870876 event. status = EventStatus :: Completed ;
871877 }
872878 storage:: set_event ( env, event_id, & event) ;
873- idempotency:: mark_seen ( env, & op_id) ;
879+ idempotency:: mark_seen ( env, & award . recipient , & op_id) ;
874880
875881 // State written above; release last so a reentrant token can't double-claim.
876882 escrow:: release ( env, & event. token , & award. recipient , amount) ;
0 commit comments