Summary
shadow_mode.rs in contracts/governance/ simulates governance proposal execution without committing state, which is a valuable safety feature. However, the simulation results are only available as return values from a direct contract call. Off-chain monitoring tools and indexers cannot observe shadow-mode execution paths because no events are emitted during a dry run.
Motivation
- Indexers and governance dashboards need a durable record of shadow-mode simulation outcomes to build "what-if" analytics for DAO proposals.
- Emitting events during dry-run (even if the ledger state is not modified) allows event subscribers to detect proposals that would fail on execution before the vote closes.
- This is consistent with the audit trail philosophy in
audit_log.rs.
Proposed Implementation
- Add a
ShadowModeResult event type:
#[contracttype]
pub struct ShadowModeResult {
pub proposal_id: u32,
pub success: bool,
pub simulated_state_changes: Vec<String>, // human-readable summary
pub failure_reason: Option<String>,
}
- At the end of
simulate_proposal in shadow_mode.rs, emit this event regardless of success/failure outcome.
- Ensure the simulation does not actually write any state (use a read-only check pattern — read storage, compute result, emit event, return result without writing).
Acceptance Criteria / Definition of Done
Summary
shadow_mode.rsincontracts/governance/simulates governance proposal execution without committing state, which is a valuable safety feature. However, the simulation results are only available as return values from a direct contract call. Off-chain monitoring tools and indexers cannot observe shadow-mode execution paths because no events are emitted during a dry run.Motivation
audit_log.rs.Proposed Implementation
ShadowModeResultevent type:simulate_proposalinshadow_mode.rs, emit this event regardless of success/failure outcome.Acceptance Criteria / Definition of Done
ShadowModeResultevent is defined inevents.rs(or equivalent).simulate_proposalemits the event with correctsuccessflag andfailure_reasonwhen applicable.success = true, (b) failing simulation emits event withsuccess = falseand non-nullfailure_reason.cargo testpasses with no regressions.