diff --git a/creator-keys/src/lib.rs b/creator-keys/src/lib.rs index 4a3142cf..211ce538 100644 --- a/creator-keys/src/lib.rs +++ b/creator-keys/src/lib.rs @@ -659,6 +659,8 @@ pub mod constants { pub const NEXT_TRADE_ID: DataKey = DataKey::NextTradeId; pub const LOCKUP_DURATION_SECS: DataKey = DataKey::LockupDurationSecs; pub const FLASH_LOAN_GUARD_LEDGERS: DataKey = DataKey::FlashLoanGuardLedgers; + /// Protocol-wide minimum investment amount in stroops (issue #792). + pub const MIN_INVESTMENT_AMOUNT: DataKey = DataKey::MinInvestmentAmount; /// Protocol-wide emergency trading halt flag (#784). pub const GLOBAL_TRADING_PAUSED: DataKey = DataKey::GlobalTradingPaused; @@ -1356,6 +1358,41 @@ pub struct SimulateResponse { pub protocol_fee: i128, } +/// Aggregated read-only snapshot of protocol-wide configuration, returned by +/// [`CreatorKeysContract::get_protocol_status`] (issue #792). +/// +/// Backs the server's `GET /protocol/status` endpoint so a single RPC call +/// surfaces the global trading-paused flag and the core config values instead +/// of one round trip per field. +/// +/// # Field Stability +/// +/// Fields are append-only. Do not reorder existing fields; the Soroban XDR +/// encoder serialises struct fields in declaration order and downstream +/// indexers rely on positional stability. +/// +/// # Defaults +/// +/// Unset config entries report their documented defaults: `false` for +/// `global_trading_paused`, [`DEFAULT_PROTOCOL_FEE_BPS`] for +/// `protocol_fee_bps`, `None` for `treasury_address`, +/// [`DEFAULT_LOCKUP_DURATION_SECS`] for `lockup_duration_seconds`, and `0` +/// for `min_investment_amount`. +#[derive(Clone, Debug, PartialEq)] +#[contracttype] +pub struct ProtocolStatus { + /// `true` while the protocol-wide emergency trading halt is active. + pub global_trading_paused: bool, + /// Protocol trade fee in basis points. + pub protocol_fee_bps: u32, + /// Current treasury address, or `None` when unconfigured. + pub treasury_address: Option
, + /// Sell lockup window in seconds. + pub lockup_duration_seconds: u64, + /// Minimum investment amount in stroops; `0` when unconfigured. + pub min_investment_amount: i128, +} + /// Initial protocol state version for read-only consumers. /// /// The actual version is stored in storage and incremented on config updates. @@ -1976,6 +2013,9 @@ pub enum DataKey { GraduatedCurve(Address), TrustedForwarder, ForwarderNonce(Address), + /// Protocol-wide minimum investment amount in stroops required for a buy + /// (issue #792). Absent means no minimum is configured. + MinInvestmentAmount, } #[derive(Clone, Debug, PartialEq)] @@ -12795,6 +12835,51 @@ impl CreatorKeysContract { is_global_trading_paused(&env) } + /// Read-only view: aggregated protocol configuration for the server's + /// `GET /protocol/status` endpoint (issue #792). + /// + /// Returns the global trading-paused flag, protocol fee basis points, + /// treasury address, sell-lockup duration, and minimum investment amount + /// in a single RPC call. Requires no authentication and never panics: + /// unset config entries fall back to their documented defaults (see + /// [`ProtocolStatus`]). The TTL of every persistent entry read here is + /// bumped so actively polled config never expires; extending a key that + /// has not been set is a no-op. + pub fn get_protocol_status(env: Env) -> ProtocolStatus { + let global_trading_paused = is_global_trading_paused(&env); + bump_persistent_ttl(&env, &constants::storage::GLOBAL_TRADING_PAUSED); + + let protocol_fee_bps = read_protocol_fee_config(&env) + .map(|config| config.protocol_bps) + .unwrap_or(DEFAULT_PROTOCOL_FEE_BPS); + bump_persistent_ttl(&env, &constants::storage::FEE_CONFIG); + + let treasury_address = env + .storage() + .persistent() + .get::