Problem Statement / Feature Objective
Several critical state transitions across the protocol—such as admin key rotations, fee rate changes, oracle feed updates, and contract upgrades—do not emit Soroban events. This makes off-chain monitoring, auditing, and event-driven integrations impossible without actively polling contract state. In the event of a malicious admin action (e.g., unauthorized fee change), there is no on-chain record of when or how the change occurred, hindering forensic analysis. The objective is to add comprehensive event emissions for all state-changing operations across all contracts, following a standardized event schema.
Technical Invariants & Bounds
Each event must include: (1) topics: [Symbol::new("event_name"), Symbol::new(contract_type)], (2) data: serialized payload with relevant before/after values. Soroban events are defined using env.events().publish() with topics as a Vec and data as a Bytes. The event size must not exceed 2048 bytes (Soroban limit). The event name must be a SCREAMING_SNAKE_CASE string. The following operations MUST emit events: AdminChanged(old, new), FeeRateChanged(old_bps, new_bps), OracleUpdated(old_feed, new_feed), ContractUpgraded(old_hash, new_hash), PauseToggled(previous, current), ParameterChanged(param_name, old_value, new_value). Each event emission costs ~500 instructions plus ~1,500 instructions per event data byte. The total gas overhead per state change increases from ~10,000 to ~12,000 instructions.
Codebase Navigation Guide
Admin operations: contracts/common/src/admin.rs — set_admin() at line 25. Fee management: contracts/settlement/src/fees.rs — set_fee_rate() at line 55. Oracle updates: contracts/tariff-oracle/src/lib.rs — update_oracle() at line 200. Contract upgrades: contracts/common/src/upgrade.rs — upgrade() at line 40. Pause mechanism: contracts/common/src/pause.rs — set_paused(). Event definitions: there may be an existing pattern in contracts/common/src/events.rs or events are defined inline. Tests: each contract's test.rs.
Implementation Blueprint
Step 1: Create contracts/common/src/events.rs with a standardized Events struct containing helper methods: emit_admin_changed(env, old, new), emit_fee_rate_changed(env, old, new), emit_oracle_updated(env, old, new), emit_contract_upgraded(env, old, new), emit_pause_toggled(env, previous, current), emit_parameter_changed(env, name, old, new). Each method calls env.events().publish() with appropriate topics and serialized data. Step 2: In contracts/common/src/admin.rs, call emit_admin_changed() after successful admin update. Step 3: In contracts/settlement/src/fees.rs, call emit_fee_rate_changed() after fee rate change. Step 4: In contracts/tariff-oracle/src/lib.rs, call emit_oracle_updated() after oracle update. Step 5: In contracts/common/src/upgrade.rs, call emit_contract_upgraded() after successful upgrade. Step 6: In contracts/common/src/pause.rs, call emit_pause_toggled() after pause state change. Step 7: Add tests that verify events are emitted with correct topics and data by using Soroban test framework's event recording. Step 8: Run full test suite.
Problem Statement / Feature Objective
Several critical state transitions across the protocol—such as admin key rotations, fee rate changes, oracle feed updates, and contract upgrades—do not emit Soroban events. This makes off-chain monitoring, auditing, and event-driven integrations impossible without actively polling contract state. In the event of a malicious admin action (e.g., unauthorized fee change), there is no on-chain record of when or how the change occurred, hindering forensic analysis. The objective is to add comprehensive event emissions for all state-changing operations across all contracts, following a standardized event schema.
Technical Invariants & Bounds
Each event must include: (1) topics: [Symbol::new("event_name"), Symbol::new(contract_type)], (2) data: serialized payload with relevant before/after values. Soroban events are defined using env.events().publish() with topics as a Vec and data as a Bytes. The event size must not exceed 2048 bytes (Soroban limit). The event name must be a SCREAMING_SNAKE_CASE string. The following operations MUST emit events: AdminChanged(old, new), FeeRateChanged(old_bps, new_bps), OracleUpdated(old_feed, new_feed), ContractUpgraded(old_hash, new_hash), PauseToggled(previous, current), ParameterChanged(param_name, old_value, new_value). Each event emission costs ~500 instructions plus ~1,500 instructions per event data byte. The total gas overhead per state change increases from ~10,000 to ~12,000 instructions.
Codebase Navigation Guide
Admin operations: contracts/common/src/admin.rs — set_admin() at line 25. Fee management: contracts/settlement/src/fees.rs — set_fee_rate() at line 55. Oracle updates: contracts/tariff-oracle/src/lib.rs — update_oracle() at line 200. Contract upgrades: contracts/common/src/upgrade.rs — upgrade() at line 40. Pause mechanism: contracts/common/src/pause.rs — set_paused(). Event definitions: there may be an existing pattern in contracts/common/src/events.rs or events are defined inline. Tests: each contract's test.rs.
Implementation Blueprint
Step 1: Create contracts/common/src/events.rs with a standardized Events struct containing helper methods: emit_admin_changed(env, old, new), emit_fee_rate_changed(env, old, new), emit_oracle_updated(env, old, new), emit_contract_upgraded(env, old, new), emit_pause_toggled(env, previous, current), emit_parameter_changed(env, name, old, new). Each method calls env.events().publish() with appropriate topics and serialized data. Step 2: In contracts/common/src/admin.rs, call emit_admin_changed() after successful admin update. Step 3: In contracts/settlement/src/fees.rs, call emit_fee_rate_changed() after fee rate change. Step 4: In contracts/tariff-oracle/src/lib.rs, call emit_oracle_updated() after oracle update. Step 5: In contracts/common/src/upgrade.rs, call emit_contract_upgraded() after successful upgrade. Step 6: In contracts/common/src/pause.rs, call emit_pause_toggled() after pause state change. Step 7: Add tests that verify events are emitted with correct topics and data by using Soroban test framework's event recording. Step 8: Run full test suite.