Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,31 @@ resolver = "2"
members = [
"stream_contract",
]
rust-version = "1.81.0"

[workspace.dependencies]
soroban-sdk = "22.0.0"

[profile.release]
# Optimize for minimal WASM binary size β€” critical for on-chain deployment.
opt-level = "z"
# Prevent silent arithmetic wraparound in contract math (i128/u64).
overflow-checks = true
# Strip debuginfo from release WASM to meet the 200 KB size budget.
debug = 0
# Further reduce WASM binary size by removing symbol names.
strip = "symbols"
# Ensure debug assertions are disabled in release β€” they inflate binary size.
debug-assertions = false
# No unwinding table in WASM; shaves ~3 KB off the binary.
panic = "abort"
# Maximise inlining opportunities for smaller/faster WASM output.
codegen-units = 1
# Cross-crate link-time optimisation β€” essential for WASM size.
lto = true

# WASM size budget: 200KB (200000 bytes) for optimized contract
# Enforced in .github/workflows/ci.yml
# WASM size budget: 200 KB (200 000 bytes) for the optimised contract.
# Enforced in .github/workflows/ci.yml via the "Check WASM size budget" step.

[profile.release-with-logs]
inherits = "release"
Expand Down
7 changes: 7 additions & 0 deletions contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ cargo build
cargo test
```

## Rust Toolchain

CI runs on the **stable** Rust toolchain (via `dtolnay/rust-toolchain@stable`)
with the `wasm32-unknown-unknown` target installed and the `rustfmt` / `clippy`
components. The workspace and member crates declare `rust-version = "1.81.0"` as
the minimum supported Rust version.

## WASM Target

To compile the contract to the `wasm32-unknown-unknown` target for Soroban deployment:
Expand Down
1 change: 1 addition & 0 deletions contracts/stream_contract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "stream_contract"
version = "0.1.0"
edition = "2021"
rust-version = "1.81.0"
description = "Soroban payment-streaming contract with protocol fees"

[lib]
Expand Down
2 changes: 2 additions & 0 deletions contracts/stream_contract/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ pub struct StreamToppedUpEvent {
pub amount: i128,
/// Total deposited amount on the stream after this top-up.
pub new_deposited_amount: i128,
/// Ledger timestamp at which the stream will fully drain after this top-up, in Unix epoch seconds.
pub new_end_time: u64,
}

/// Emitted when the recipient withdraws accrued tokens.
Expand Down
9 changes: 9 additions & 0 deletions contracts/stream_contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,14 @@ impl StreamContract {
// `now` would discard any already-vested, unwithdrawn tokens.
stream.deposited_amount += net_amount;

let now = env.ledger().timestamp();
let claimable = Self::calculate_claimable(&stream, now);
let remaining = stream
.deposited_amount
.saturating_sub(stream.withdrawn_amount)
.saturating_sub(claimable);
let new_end_time = now + (remaining / stream.rate_per_second) as u64;

save_stream(&env, stream_id, &stream);

// Emit top-up event
Expand All @@ -318,6 +326,7 @@ impl StreamContract {
sender,
amount: net_amount,
new_deposited_amount: stream.deposited_amount,
new_end_time,
},
);

Expand Down
1 change: 1 addition & 0 deletions contracts/stream_contract/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ fn test_top_up_emits_event() {
assert_eq!(payload.stream_id, id);
assert_eq!(payload.amount, 5_000);
assert_eq!(payload.new_deposited_amount, 15_000);
assert_eq!(payload.new_end_time, 150);
}

#[test]
Expand Down
25 changes: 13 additions & 12 deletions contracts/stream_contract/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,29 +34,30 @@ pub enum DataKey {
#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Stream {
/// Address that created and funds this stream.
/// Address that created and funds this stream. Always set.
pub sender: Address,
/// Address entitled to withdraw from this stream.
/// Address entitled to withdraw from this stream. Always set.
pub recipient: Address,
/// Token being streamed.
/// Token being streamed. Always set.
pub token_address: Address,
/// Net tokens dripped per ledger-second (after fee deduction).
/// Net tokens dripped per second (after fee deduction), in stroops.
pub rate_per_second: i128,
/// Net deposited amount available to the stream (after fee deduction).
/// Net deposited amount available to the stream (after fee deduction), in stroops.
pub deposited_amount: i128,
/// Cumulative amount already withdrawn by the recipient.
/// Cumulative amount already withdrawn by the recipient, in stroops.
pub withdrawn_amount: i128,
/// Ledger timestamp at stream creation.
/// Ledger timestamp at stream creation, in Unix epoch seconds.
pub start_time: u64,
/// Ledger timestamp of the last state mutation.
/// Ledger timestamp of the last state mutation, in Unix epoch seconds.
pub last_update_time: u64,
/// `false` once fully withdrawn or cancelled.
/// `false` once fully withdrawn or cancelled. Always set.
pub is_active: bool,
/// `true` while the stream is paused; accrual is frozen at `paused_at`.
/// `true` while the stream is paused; accrual is frozen at `paused_at`. Always set.
pub paused: bool,
/// Ledger timestamp when the stream was paused, `None` if not paused.
/// Ledger timestamp when the stream was paused (`None` if not paused), in Unix epoch seconds.
/// Only meaningful while `paused` is true.
pub paused_at: Option<u64>,
/// Current status of the stream.
/// Current status of the stream. Always set.
pub status: StreamStatus,
}

Expand Down
Loading