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
10 changes: 10 additions & 0 deletions contracts/split/src/storage_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ use soroban_sdk::{contracttype, symbol_short, Address, Env, IntoVal, Symbol, Try
///
/// All variants are unit (carry no data). Instance storage is wiped on
/// upgrade unless explicitly preserved, so these represent live config.
///
/// Soroban's XDR spec caps a `#[contracttype]` enum at **50 variants**, so
/// this enum must never grow past that limit — it is already one of four
/// enums the key registry is split across for exactly this reason (see the
/// module-level docs above). When adding a new instance-storage key, always
/// **append** a new variant at the end; never reorder or remove an existing
/// variant, since XDR encodes variants positionally and reordering would
/// silently corrupt every value already written under the old positions. If
/// this enum is at or near 50 variants, add the new key to a fifth enum
/// instead of extending this one.
#[contracttype]
#[derive(Clone)]
pub enum StorageKey {
Expand Down
55 changes: 45 additions & 10 deletions contracts/split/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,29 @@ pub struct CloneOverrides {
#[contracttype]
#[derive(Clone, Debug)]
pub enum SplitRule {
/// Pay this exact amount regardless of funded total.
/// Pay this exact amount regardless of the invoice's funded total.
///
/// # Example
///
/// `Fixed(2_500)` always pays out `2_500`, whether `funded` is `2_500`,
/// `10_000`, or anything else.
Fixed(i128),
/// Pay `funded * bps / 10_000` to the recipient.
/// Pay `funded * bps / 10_000` to the recipient, where `bps` is basis
/// points (10_000 = 100%).
///
/// # Example
///
/// `Percentage(3_000)` (30%) on `funded = 10_000` yields
/// `10_000 * 3_000 / 10_000 = 3_000`.
Percentage(u32),
/// Pay `funded * bps / 10_000` only when `funded > threshold`; else 0.
/// Encoded as (threshold, bps).
/// Pay `funded * bps / 10_000` only once `funded` strictly exceeds
/// `threshold`; otherwise pay `0`. Encoded as `(threshold, bps)`.
///
/// # Example
///
/// `Tiered(5_000, 2_000)` (20% once past 5_000) on `funded = 8_000`
/// yields `8_000 * 2_000 / 10_000 = 1_600`, because `8_000 > 5_000`.
/// On `funded = 4_000` it yields `0`, because `4_000 <= 5_000`.
Tiered(i128, u32),
}

Expand Down Expand Up @@ -1562,13 +1579,23 @@ pub struct UpgradeProposal {

/// Hot invoice fields stored in instance storage for TTL-efficient reads.
///
/// These four fields are read on every `pay()` call. Keeping them in the
/// contract *instance* bucket means their TTL is extended by a single
/// `extend_ttl` call that covers all active invoices simultaneously —
/// O(1) per payment rather than one persistent-rent charge per invoice entry.
/// These four fields are read on every `pay()` call.
///
/// Cold creation params and audit metadata stay in persistent storage
/// (`InvoiceCore` / `InvoiceExt` / `InvoiceExt2`).
/// # Design
///
/// Soroban charges rent independently per storage entry, and each entry's
/// TTL must be extended on its own. Keeping these hot fields in the
/// contract's *instance* bucket — rather than one persistent entry per
/// invoice — means a single `extend_ttl` call on the instance covers every
/// active invoice's hot data simultaneously: O(1) per payment rather than
/// one persistent-rent `extend_ttl` charge per invoice entry.
///
/// This is a trade-off: instance storage is wiped on contract upgrade unless
/// explicitly preserved, and it grows with every invoice ever created (there
/// is no per-key eviction). Cold creation params and audit metadata that are
/// not needed on the payment hot path stay in persistent storage instead
/// (`InvoiceCore` / `InvoiceExt` / `InvoiceExt2`), where they can expire and
/// be restored independently per invoice.
#[contracttype]
#[derive(Clone, Debug)]
pub struct InvoiceHot {
Expand All @@ -1588,6 +1615,14 @@ pub struct InvoiceHot {

impl InvoiceStatus {
/// Encode as a single byte — saves XDR overhead vs. the full enum variant.
///
/// # Examples
///
/// ```
/// use split::types::InvoiceStatus;
///
/// assert_eq!(InvoiceStatus::Released.to_u8(), 1);
/// ```
pub fn to_u8(&self) -> u8 {
match self {
InvoiceStatus::Pending => 0,
Expand Down
Loading