Skip to content

feat: cancellation fee, StreamInterface, role-based access control, sender collateral - #539

Merged
Chuks-coderr merged 2 commits into
SoroStream:mainfrom
Me7858:288
Aug 31, 2026
Merged

feat: cancellation fee, StreamInterface, role-based access control, sender collateral#539
Chuks-coderr merged 2 commits into
SoroStream:mainfrom
Me7858:288

Conversation

@Me7858

@Me7858 Me7858 commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements four protocol enhancements as a single cohesive PR. All features are gated behind admin-configurable parameters and default to their existing (no-op) behaviour on existing deployments.


#288 — Cancellation Fee

  • New admin function set_cancellation_fee (callable by super-admin or FeeManager role)
  • get_cancellation_fee_bps returns the current rate (0 by default)
  • On cancel_stream, a configurable percentage (up to 100%) is deducted from the sender's unstreamed refund and accumulated in the protocol treasury
  • Fee is waived for fee-exempt senders and for streams that have already passed their end_time (natural expiry)
  • CancelFeeCollected event emitted with (stream_id, sender, fee_amount, fee_bps)

closes #288


#291 — StreamInterface / Composability Trait

  • New file composability.rs defines the ISoroStreamComposability trait with #[contractclient]
  • The auto-generated SoroStreamComposabilityClient stub enables external contracts (lending protocols, DAOs, vesting managers) to create, query, and withdraw from streams with minimal surface area
  • Exposed operations: composable_create_stream, composable_withdraw, composable_get_claimable, composable_get_stream, composable_get_streams_for, composable_has_claimable, composable_get_version
  • Full SoroStreamInterface in interface.rs remains the canonical reference for all functions
  • Usage example documented in composability.rs doc-comment

closes #291


#292 — Role-Based Access Control

  • New file roles.rs implements the role registry with four roles:
    • SuperAdmin — full privileges, stored under existing ADMIN_KEY
    • FeeManager — may call set_protocol_fee, set_cancellation_fee, sweep_fees
    • EmergencyPause — may call emergency_pause / emergency_resume
    • Analytics — read-only access to get_stats, get_protocol_stats, audit log
  • Per-role storage helpers (get/set/revoke_*) with instance-storage keys rfee, rpause, ranal
  • Admin functions: assign_fee_manager, revoke_fee_manager, assign_emergency_pause_role, revoke_emergency_pause_role, assign_analytics_role, revoke_analytics_role
  • RoleAssigned / RoleRevoked events and audit log entries on every change
  • No storage migration required: existing deployments with only a super-admin key continue to work

closes #292


#293 — Sender Collateral / Stake Mechanism

  • stake(sender, token, amount) — sender deposits collateral; held in contract escrow
  • initiate_unstake(sender, token, amount) — begins 24-hour cooldown before withdrawal
  • complete_unstake(sender, token) — finalises unstake after cooldown elapses
  • slash_stake(admin, sender, token, amount, destination) — super-admin only; forfeits collateral to any address (typically treasury) as penalty
  • set_min_stake_amount(admin, token, amount) / get_min_stake_amount(token) — per-token minimum threshold
  • check_sender_stake helper called in create_stream; returns InsufficientStake if minimum is set and not met; no-op when minimum is 0 (default)
  • Events: StakeDeposited, UnstakeInitiated, UnstakeCompleted, StakeSlashed, MinStakeSet

closes #293


Technical Notes

  • Fixed OptionalStreamStatus wrapper enum in types.rs — Soroban's #[contracttype] macro cannot serialise Option<EnumType> directly inside a struct; replaced with an explicit enum variant
  • Updated integration_tests.rs and rate_limit_tests.rs to use the refactored CreateStreamParams struct signature
  • Removed always-false 0i128 < 0 guard flagged by Clippy

Testing

cargo test        # 52 tests, 0 failures
cargo clippy      # 0 errors

Me7858 and others added 2 commits August 30, 2026 13:19
…ollateral

- SoroStream#288: Add admin-configurable cancellation fee (cancellation_fee_basis_points)
  - set_cancellation_fee / get_cancellation_fee_bps functions
  - Fee deducted from sender refund on early cancel_stream
  - No fee for naturally expired streams or fee-exempt senders
  - CancelFeeCollected event emitted on each fee deduction
  - FeeManager role (see SoroStream#292) may also configure the fee

- SoroStream#291: Add ISoroStreamComposability trait for external contract integration
  - composability.rs: ISoroStreamComposability trait with #[contractclient]
  - Exposes composable_create_stream, composable_withdraw, composable_get_claimable,
    composable_get_stream, composable_get_streams_for, composable_has_claimable,
    composable_get_version
  - Full SoroStreamInterface trait in interface.rs as canonical integration target
  - Usage example documented in composability.rs doc-comment

- SoroStream#292: Add role-based access control with four roles
  - roles.rs: AdminRole enum (SuperAdmin, FeeManager, EmergencyPause, Analytics)
  - Persistent storage helpers: get/set/revoke_* for each role
  - lib.rs: assign_fee_manager, revoke_fee_manager, get_fee_manager
  - lib.rs: assign_emergency_pause_role, revoke_emergency_pause_role
  - lib.rs: assign_analytics_role, revoke_analytics_role
  - Audit log entry + RoleAssigned / RoleRevoked events on each change
  - has_any_admin_role query function

- SoroStream#293: Add sender collateral / stake mechanism
  - stake / initiate_unstake / complete_unstake with 24h cooldown
  - slash_stake: admin can forfeit bad-actor stake to any destination
  - set_min_stake_amount / get_min_stake_amount per token
  - check_sender_stake called in create_stream (no-op if min=0)
  - StakeDeposited, StakeSlashed, MinStakeSet, UnstakeInitiated, UnstakeCompleted events

- Fix OptionalStreamStatus wrapper for StreamQueryFilter (Soroban contracttype
  does not support Option<EnumType> in struct fields)
- Update integration_tests.rs and rate_limit_tests.rs to use CreateStreamParams
- Fix clippy: remove always-false 0i128 < 0 guard in create_stream_with_federation

closes SoroStream#288
closes SoroStream#291
closes SoroStream#292
closes SoroStream#293
@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@Me7858 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Chuks-coderr
Chuks-coderr merged commit 433b1b5 into SoroStream:main Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants