@@ -523,9 +523,12 @@ impl CalloraVault {
523523 /// # Panics
524524 /// * `"vault is paused"` – if the circuit breaker is active.
525525 pub fn deduct ( env : Env , caller : Address , amount : i128 , request_id : Option < Symbol > ) -> i128 {
526+ // ── 1. Require Soroban-level auth for the caller ──────────────────────
526527 caller. require_auth ( ) ;
527528 Self :: require_not_paused ( env. clone ( ) ) ;
528529 assert ! ( amount > 0 , "amount must be positive" ) ;
530+
531+ // ── 3. Enforce max_deduct cap ─────────────────────────────────────────
529532 let max_deduct = Self :: get_max_deduct ( env. clone ( ) ) ;
530533 assert ! ( amount <= max_deduct, "deduct amount exceeds max_deduct" ) ;
531534
@@ -537,6 +540,7 @@ impl CalloraVault {
537540 } ;
538541 assert ! ( authorized, "unauthorized caller" ) ;
539542
543+ // ── 6. Balance safety: explicit guard prevents underflow ──────────────
540544 assert ! ( meta. balance >= amount, "insufficient balance" ) ;
541545 let mut meta = Self :: get_meta ( env. clone ( ) ) ;
542546 meta. balance = meta. balance . checked_sub ( amount) . unwrap ( ) ;
@@ -550,15 +554,12 @@ impl CalloraVault {
550554 Self :: transfer_to_settlement ( env. clone ( ) , amount) ;
551555 }
552556
553- let topics = match & request_id {
554- Some ( rid) => ( Symbol :: new ( & env, "deduct" ) , caller. clone ( ) , rid. clone ( ) ) ,
555- None => (
556- Symbol :: new ( & env, "deduct" ) ,
557- caller. clone ( ) ,
558- Symbol :: new ( & env, "" ) ,
559- ) ,
560- } ;
561- env. events ( ) . publish ( topics, ( amount, meta. balance ) ) ;
557+ // ── 9. Emit event ONLY after successful deduction ─────────────────────
558+ // Schema: topics = ("deduct", caller, request_id | ""), data = (amount, new_balance)
559+ let rid = request_id. unwrap_or ( Symbol :: new ( & env, "" ) ) ;
560+ env. events ( )
561+ . publish ( ( Symbol :: new ( & env, "deduct" ) , caller, rid) , ( amount, meta. balance ) ) ;
562+
562563 meta. balance
563564 }
564565
0 commit comments