@@ -358,6 +358,20 @@ pub struct SlippageEvent {
358358 pub slippage_bps : u32 ,
359359}
360360
361+ #[ contractevent]
362+ #[ derive( Clone , Debug ) ]
363+ pub struct SlippageThresholdSetEvent {
364+ pub version : u32 ,
365+ pub threshold_bps : u32 ,
366+ }
367+
368+ #[ contractevent]
369+ #[ derive( Clone , Debug ) ]
370+ pub struct TelemetryEvent {
371+ pub version : u32 ,
372+ pub function_name : Symbol ,
373+ }
374+
361375#[ contractevent]
362376#[ derive( Clone , Debug ) ]
363377pub struct AdminActionQueuedEvent {
@@ -618,6 +632,10 @@ pub enum DataKey {
618632 Threshold ,
619633 MultisigProposal ( u64 ) ,
620634 NextMultisigID ,
635+ // ── Issue #496: slippage threshold for batch operations ─────────────
636+ SlippageThreshold ,
637+ // ── Issue #1044: fee recipient address ───────────────────────────
638+ FeeRecipient ,
621639}
622640
623641const ORACLE_PRICE_DECIMALS : i128 = 10_000_000 ;
@@ -628,6 +646,11 @@ pub struct FiatBridge;
628646
629647#[ contractimpl]
630648impl FiatBridge {
649+ // ── Issue #1041: telemetry helper ───────────────────────────────────
650+ fn emit_telemetry ( env : & Env , function_name : Symbol ) {
651+ TelemetryEvent { version : EVENT_VERSION , function_name } . publish ( env) ;
652+ }
653+
631654 pub fn init (
632655 env : Env ,
633656 admin : Address ,
@@ -637,6 +660,9 @@ impl FiatBridge {
637660 signers : Vec < Address > ,
638661 threshold : u32 ,
639662 ) -> Result < ( ) , Error > {
663+ // ── Issue #1041: emit telemetry event
664+ Self :: emit_telemetry ( & env, Symbol :: new ( & env, "init" ) ) ;
665+
640666 if env. storage ( ) . instance ( ) . has ( & DataKey :: Admin ) {
641667 return Err ( Error :: AlreadyInitialized ) ;
642668 }
@@ -730,6 +756,9 @@ impl FiatBridge {
730756 max_slippage : u32 ,
731757 memo_hash : Option < BytesN < 32 > > ,
732758 ) -> Result < BytesN < 32 > , Error > {
759+ // ── Issue #1041: emit telemetry event
760+ Self :: emit_telemetry ( & env, Symbol :: new ( & env, "deposit" ) ) ;
761+
733762 env. storage ( ) . instance ( ) . extend_ttl ( MIN_TTL , MAX_TTL ) ;
734763 Self :: validate_memo_hash ( & env, & memo_hash) ?;
735764 from. require_auth ( ) ;
@@ -2393,6 +2422,9 @@ impl FiatBridge {
23932422 }
23942423
23952424 pub fn withdraw_fees ( env : Env , to : Address , token : Address , amount : i128 ) -> Result < ( ) , Error > {
2425+ // ── Issue #1041: emit telemetry event
2426+ Self :: emit_telemetry ( & env, Symbol :: new ( & env, "withdraw_fees" ) ) ;
2427+
23962428 let admin: Address = env
23972429 . storage ( )
23982430 . instance ( )
@@ -2417,22 +2449,39 @@ impl FiatBridge {
24172449 return Err ( Error :: FeeWithdrawalExceedsBalance ) ;
24182450 }
24192451
2452+ // ── Issue #1044: use fee_recipient if set, otherwise use the provided 'to' address
2453+ let recipient = env
2454+ . storage ( )
2455+ . instance ( )
2456+ . get ( & DataKey :: FeeRecipient )
2457+ . unwrap_or ( to) ;
2458+
24202459 let token_client = token:: Client :: new ( & env, & token) ;
2421- token_client. transfer ( & env. current_contract_address ( ) , & to , & amount) ;
2460+ token_client. transfer ( & env. current_contract_address ( ) , & recipient , & amount) ;
24222461
24232462 env. storage ( ) . persistent ( ) . set ( & key, & ( current - amount) ) ;
2424- FeeWithdrawnEvent { version : EVENT_VERSION , to : to . clone ( ) , amount } . publish ( & env) ;
2463+ FeeWithdrawnEvent { version : EVENT_VERSION , to : recipient , amount } . publish ( & env) ;
24252464 Ok ( ( ) )
24262465 }
24272466
24282467 pub fn withdraw_fees_batch ( env : Env , to : Address , tokens : Vec < Address > ) -> Result < ( ) , Error > {
2468+ // ── Issue #1041: emit telemetry event
2469+ Self :: emit_telemetry ( & env, Symbol :: new ( & env, "withdraw_fees_batch" ) ) ;
2470+
24292471 let admin: Address = env
24302472 . storage ( )
24312473 . instance ( )
24322474 . get ( & DataKey :: Admin )
24332475 . ok_or ( Error :: NotInitialized ) ?;
24342476 admin. require_auth ( ) ;
24352477
2478+ // ── Issue #1044: use fee_recipient if set, otherwise use the provided 'to' address
2479+ let recipient = env
2480+ . storage ( )
2481+ . instance ( )
2482+ . get ( & DataKey :: FeeRecipient )
2483+ . unwrap_or ( to) ;
2484+
24362485 let contract = env. current_contract_address ( ) ;
24372486 for token in tokens. iter ( ) {
24382487 let key = DataKey :: FeeVault ( token. clone ( ) ) ;
@@ -2442,9 +2491,9 @@ impl FiatBridge {
24422491 }
24432492
24442493 let token_client = token:: Client :: new ( & env, & token) ;
2445- token_client. transfer ( & contract, & to , & current) ;
2494+ token_client. transfer ( & contract, & recipient , & current) ;
24462495 env. storage ( ) . persistent ( ) . set ( & key, & 0i128 ) ;
2447- FeeWithdrawnEvent { version : EVENT_VERSION , to : to . clone ( ) , amount : current } . publish ( & env) ;
2496+ FeeWithdrawnEvent { version : EVENT_VERSION , to : recipient . clone ( ) , amount : current } . publish ( & env) ;
24482497 }
24492498
24502499 Ok ( ( ) )
@@ -2602,6 +2651,33 @@ impl FiatBridge {
26022651 . get ( & DataKey :: WithdrawCooldownThreshold )
26032652 . unwrap_or ( 0 )
26042653 }
2654+ pub fn get_slippage_threshold ( env : Env ) -> u32 {
2655+ env. storage ( )
2656+ . instance ( )
2657+ . get ( & DataKey :: SlippageThreshold )
2658+ . unwrap_or ( 0 )
2659+ }
2660+
2661+ // ── Issue #1044: fee recipient management ───────────────────────────
2662+ pub fn set_fee_recipient ( env : Env , recipient : Address ) -> Result < ( ) , Error > {
2663+ // ── Issue #1041: emit telemetry event
2664+ Self :: emit_telemetry ( & env, Symbol :: new ( & env, "set_fee_recipient" ) ) ;
2665+
2666+ let admin: Address = env
2667+ . storage ( )
2668+ . instance ( )
2669+ . get ( & DataKey :: Admin )
2670+ . ok_or ( Error :: NotInitialized ) ?;
2671+ admin. require_auth ( ) ;
2672+
2673+ env. storage ( ) . instance ( ) . set ( & DataKey :: FeeRecipient , & recipient) ;
2674+ Ok ( ( ) )
2675+ }
2676+
2677+ pub fn get_fee_recipient ( env : Env ) -> Option < Address > {
2678+ env. storage ( ) . instance ( ) . get ( & DataKey :: FeeRecipient )
2679+ }
2680+
26052681 pub fn get_receipt_by_index ( env : Env , idx : u64 ) -> Option < Receipt > {
26062682 let max_receipts: u64 = env. storage ( ) . instance ( ) . get ( & DataKey :: ReceiptCounter ) . unwrap_or ( 0 ) ;
26072683 if idx >= max_receipts {
@@ -3004,6 +3080,9 @@ impl FiatBridge {
30043080 env : Env ,
30053081 operations : Vec < BatchAdminOp > ,
30063082 ) -> Result < BatchResult , Error > {
3083+ // ── Issue #1041: emit telemetry event
3084+ Self :: emit_telemetry ( & env, Symbol :: new ( & env, "execute_batch_admin" ) ) ;
3085+
30073086 let admin: Address = env
30083087 . storage ( )
30093088 . instance ( )
@@ -3066,6 +3145,17 @@ impl FiatBridge {
30663145 . instance ( )
30673146 . set ( & DataKey :: AntiSandwichDelay , & ledgers) ;
30683147 Ok ( ( ) )
3148+ } else if * op_name == Symbol :: new ( env, "set_slippage_threshold" ) {
3149+ let threshold_bps = Self :: bytes_to_u32 ( env, & op. payload ) ?;
3150+ // Validate slippage threshold is reasonable (0-10000 bps = 0-100%)
3151+ if threshold_bps > 10000 {
3152+ return Err ( Error :: SlippageTooHigh ) ;
3153+ }
3154+ env. storage ( )
3155+ . instance ( )
3156+ . set ( & DataKey :: SlippageThreshold , & threshold_bps) ;
3157+ SlippageThresholdSetEvent { version : EVENT_VERSION , threshold_bps } . publish ( env) ;
3158+ Ok ( ( ) )
30693159 } else if * op_name == Symbol :: new ( env, "set_limit" ) {
30703160 // Payload: [Address(token), i128(limit)]
30713161 // For simplicity in multisig mockup, we might need a better encoding or specialized ops.
0 commit comments