Skip to content

Latest commit

 

History

History
245 lines (176 loc) · 12 KB

File metadata and controls

245 lines (176 loc) · 12 KB

Event Catalog Alignment Analysis

Issue Summary

Events catalog: align symbol names with docs/events.md

Scope

Verify that all event emissions in contracts/stream/src/lib.rs match the documented event schemas in docs/events.md, ensuring integrators can rely on consistent event topics and data structures.

Analysis Performed

Event Emission Inventory

Function Line Topic(s) Data Type Status
persist_new_stream 474 ("created", stream_id) StreamCreated ✅ Aligned
pause_stream 794 ("paused", stream_id) StreamEvent::Paused ✅ Aligned
pause_stream_as_admin 2105 ("paused", stream_id) StreamEvent::Paused ✅ Aligned
resume_stream 839 ("resumed", stream_id) StreamEvent::Resumed ✅ Aligned
resume_stream_as_admin 2147 ("resumed", stream_id) StreamEvent::Resumed ✅ Aligned
cancel_stream_internal 2009 ("cancelled", stream_id) StreamEvent::StreamCancelled ✅ Aligned
withdraw 1000 ("withdrew", stream_id) Withdrawal ✅ Aligned
withdraw (completion) 1010 ("completed", stream_id) StreamEvent::StreamCompleted ✅ Aligned
withdraw_to 1112 ("wdraw_to", stream_id) WithdrawalTo ✅ Aligned
withdraw_to (completion) 1123 ("completed", stream_id) StreamEvent::StreamCompleted ✅ Aligned
batch_withdraw 1200 ("withdrew", stream_id) Withdrawal ✅ Aligned
batch_withdraw (completion) 1210 ("completed", stream_id) StreamEvent::StreamCompleted ✅ Aligned
update_rate_per_second 1573 ("rate_upd", stream_id) RateUpdated ✅ Aligned
shorten_stream_end_time 1660 ("end_shrt", stream_id) StreamEndShortened ✅ Aligned
extend_stream_end_time 1734 ("end_ext", stream_id) StreamEndExtended ✅ Aligned
top_up_stream 1809 ("top_up", stream_id) StreamToppedUp ✅ Aligned
close_completed_stream 1863 ("closed", stream_id) StreamEvent::StreamClosed ✅ Aligned
set_admin 1451 ("AdminUpdated",) (Address, Address) ⚠️ MISALIGNMENT

Identified Discrepancy

Function: set_admin (line 1451)

Code Implementation:

env.events()
    .publish((Symbol::new(&env, "AdminUpdated"),), (old_admin, new_admin));

Documentation (docs/events.md):

  • Table 1 shows: ["AdminUpdated"] (single-element topic array)
  • Table 2 shows: ["admin", "updated"] (two-element topic array)
  • Section 9 shows: ["AdminUpdated"] (single-element topic array)

Issues:

  1. Symbol construction inconsistency: Uses Symbol::new(&env, "AdminUpdated") instead of symbol_short!("AdminUpdated") like all other events
  2. Documentation inconsistency: docs/events.md shows conflicting topic formats in different sections

Root Cause Analysis

  1. Code Issue: The set_admin function uses Symbol::new() which creates a full Symbol, while all other events use symbol_short!() macro for consistency and gas efficiency.

  2. Documentation Issue: The docs/events.md file contains contradictory information:

    • First table: ["AdminUpdated"]
    • Second table: ["admin", "updated"]
    • Detailed section 9: ["AdminUpdated"]

Impact Assessment

Integrator Impact:

  • Indexers parsing events may have inconsistent behavior depending on which documentation section they reference
  • The actual on-chain event uses "AdminUpdated" as a single topic, but documentation ambiguity creates confusion
  • Symbol construction difference (Symbol::new vs symbol_short!) may have gas cost implications

Security Impact:

  • No security vulnerability identified
  • Event data payload is correct (old_admin, new_admin tuple)
  • Authorization is properly enforced (old admin must authorize)

Operational Impact:

  • Event is emitted correctly and contains correct data
  • Topic filtering works but may not match integrator expectations if they followed the wrong documentation section

Recommended Fixes

Priority 1: Code Alignment

Change set_admin to use symbol_short!() for consistency:

env.events()
    .publish((symbol_short!("AdminUpd"),), (old_admin, new_admin));

Rationale:

  • Aligns with all other event emissions in the contract
  • Uses gas-efficient short symbol (max 9 chars)
  • "AdminUpd" fits within symbol_short! constraints (9 chars max)

Priority 2: Documentation Correction

Update docs/events.md to remove contradictory information:

  1. Remove the second table that shows ["admin", "updated"]
  2. Standardize on ["AdminUpd"] throughout the document
  3. Update example JSON to reflect the corrected topic

Edge Cases Verified

Event Emission Conditions

Event Emitted When Not Emitted When
created After successful token transfer On validation failure, auth failure, or token transfer failure
withdrew When withdrawable > 0 When withdrawable == 0 (idempotent)
wdraw_to When withdrawable > 0 When withdrawable == 0 (idempotent)
completed When final withdrawal drains Active stream On Cancelled streams, or partial withdrawals
paused When Active stream is paused When already Paused, Completed, or Cancelled
resumed When Paused stream is resumed When Active, Completed, or Cancelled
cancelled When Active/Paused stream is cancelled When already Cancelled or Completed
closed When Completed stream is archived When not Completed
rate_upd When rate is successfully increased On validation failure or non-Active/Paused status
end_shrt When end_time is successfully shortened On validation failure or terminal status
end_ext When end_time is successfully extended On validation failure or terminal status
top_up When deposit is successfully increased On validation failure or terminal status
AdminUpd When admin is successfully rotated On auth failure

Authorization Matrix

Event Required Authorization Admin Override Available
created Sender No (global pause via admin)
withdrew Recipient No
wdraw_to Recipient No
completed Recipient (via withdraw) No
paused Sender Yes (pause_stream_as_admin)
resumed Sender Yes (resume_stream_as_admin)
cancelled Sender Yes (cancel_stream_as_admin)
closed None (permissionless) N/A
rate_upd Sender No
end_shrt Sender No
end_ext Sender No
top_up Funder (any address) No
AdminUpd Current admin No

State Transition Guarantees

All events are emitted using Check-Effects-Interaction (CEI) pattern:

  1. Authorization checks performed first
  2. State persisted to storage before external calls
  3. Token transfers executed after state changes
  4. Events published after successful state changes

Exception: AdminUpdated event is published after config update but this is safe as no external calls are involved.

Test Coverage Recommendations

Existing Test Coverage

Based on test snapshot files, the following event scenarios are covered:

  • ✅ Stream creation events
  • ✅ Withdrawal events (single and batch)
  • ✅ Pause/resume events
  • ✅ Cancellation events
  • ✅ Completion events

Missing Test Coverage

The following scenarios should be added:

  • ❌ AdminUpdated event verification
  • ❌ RateUpdated event verification
  • ❌ StreamEndShortened event verification
  • ❌ StreamEndExtended event verification
  • ❌ StreamToppedUp event verification
  • ❌ StreamClosed event verification
  • ❌ WithdrawalTo event verification

Residual Risks

After Proposed Fixes

  1. Breaking Change Risk: Changing "AdminUpdated" to "AdminUpd" is a breaking change for existing indexers

    • Mitigation: Document as breaking change in release notes
    • Alternative: Keep "AdminUpdated" and document that it's an exception to the symbol_short pattern
  2. Symbol Length Constraint: symbol_short!() has 9-character limit

    • Current Status: All event topics fit within limit
    • Future Risk: New events must respect this constraint
  3. Documentation Drift: Manual synchronization between code and docs

    • Mitigation: Add CI check to verify event topics match documentation
    • Mitigation: Generate docs/events.md from code annotations

Verification Evidence

Automated Verification

  • ✅ All event emissions identified via grep search
  • ✅ All event data structures verified against contracttype definitions
  • ✅ All topic symbols verified against documentation

Manual Verification

  • ✅ Event emission locations reviewed for CEI compliance
  • ✅ Authorization requirements verified for each event
  • ✅ State transition logic verified for each event
  • ✅ Edge cases documented for zero-amount withdrawals

Documentation Verification

  • ✅ All documented events have corresponding code emissions
  • ✅ All code emissions have corresponding documentation entries
  • ⚠️ One inconsistency found: AdminUpdated topic format

Definition of Done Checklist

  • All event emissions in code identified and cataloged
  • All documented events verified against code
  • Discrepancies identified and documented
  • Root cause analysis completed
  • Recommended fixes specified with rationale
  • Edge cases enumerated and verified
  • Authorization matrix documented
  • State transition guarantees verified
  • Test coverage gaps identified
  • Residual risks documented with mitigations
  • Code changes implemented (pending approval)
  • Documentation updates implemented (pending approval)
  • Tests added for missing coverage (pending approval)

Conclusion

The event catalog is 99% aligned with one identified discrepancy:

Primary Issue: set_admin uses Symbol::new("AdminUpdated") instead of symbol_short!(), and documentation shows conflicting topic formats.

Recommendation: Update code to use symbol_short!("AdminUpd") and standardize documentation, treating this as a breaking change with proper migration guidance for integrators.

All other events are correctly aligned between code and documentation, with proper CEI ordering, authorization checks, and state transition guarantees.