From 78ac838a995d84f16accdf5287eda04a5ae9aabf Mon Sep 17 00:00:00 2001 From: Dopey Date: Thu, 26 Mar 2026 02:08:46 +0100 Subject: [PATCH] feat(contract): add get_protocol_fee_view read-only method Resolves #19 --- creator-keys/src/lib.rs | 36 ++++++++++++++ creator-keys/tests/fee_config_view.rs | 71 +++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 creator-keys/tests/fee_config_view.rs diff --git a/creator-keys/src/lib.rs b/creator-keys/src/lib.rs index e64e41a..7f9a16b 100644 --- a/creator-keys/src/lib.rs +++ b/creator-keys/src/lib.rs @@ -53,6 +53,18 @@ pub mod fee { } } +/// Stable, non-optional view of the protocol fee configuration. +/// +/// Returned by [`CreatorKeysContract::get_protocol_fee_view`] for indexer-friendly consumption. +/// When `is_configured` is `false`, both bps fields are `0` and no fee config has been stored. +#[derive(Clone)] +#[contracttype] +pub struct ProtocolFeeView { + pub creator_bps: u32, + pub protocol_bps: u32, + pub is_configured: bool, +} + #[derive(Clone)] #[contracttype] pub enum DataKey { @@ -164,6 +176,30 @@ impl CreatorKeysContract { env.storage().persistent().get(&DataKey::FeeConfig) } + /// Read-only view: returns the current protocol fee configuration. + /// + /// Returns a stable [`ProtocolFeeView`] regardless of whether a fee config has been set. + /// When no config is stored, `is_configured` is `false` and both bps fields are `0`. + /// Use this method for indexers and read-only callers that need a non-optional result. + pub fn get_protocol_fee_view(env: Env) -> ProtocolFeeView { + match env + .storage() + .persistent() + .get::(&DataKey::FeeConfig) + { + Some(config) => ProtocolFeeView { + creator_bps: config.creator_bps, + protocol_bps: config.protocol_bps, + is_configured: true, + }, + None => ProtocolFeeView { + creator_bps: 0, + protocol_bps: 0, + is_configured: false, + }, + } + } + pub fn compute_fees_for_payment(env: Env, total: i128) -> (i128, i128) { let config: fee::FeeConfig = env .storage() diff --git a/creator-keys/tests/fee_config_view.rs b/creator-keys/tests/fee_config_view.rs new file mode 100644 index 0000000..0894589 --- /dev/null +++ b/creator-keys/tests/fee_config_view.rs @@ -0,0 +1,71 @@ +//! Tests for the get_protocol_fee_view read-only method (#19). + +use creator_keys::{CreatorKeysContract, CreatorKeysContractClient}; +use soroban_sdk::{testutils::Address as _, Env}; + +#[test] +fn test_get_protocol_fee_view_unconfigured_returns_defaults() { + let env = Env::default(); + let contract_id = env.register(CreatorKeysContract, ()); + let client = CreatorKeysContractClient::new(&env, &contract_id); + + let view = client.get_protocol_fee_view(); + assert!(!view.is_configured); + assert_eq!(view.creator_bps, 0); + assert_eq!(view.protocol_bps, 0); +} + +#[test] +fn test_get_protocol_fee_view_returns_configured_values() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(CreatorKeysContract, ()); + let client = CreatorKeysContractClient::new(&env, &contract_id); + let admin = soroban_sdk::Address::generate(&env); + + client.set_fee_config(&admin, &9000u32, &1000u32); + + let view = client.get_protocol_fee_view(); + assert!(view.is_configured); + assert_eq!(view.creator_bps, 9000); + assert_eq!(view.protocol_bps, 1000); +} + +#[test] +fn test_get_protocol_fee_view_is_read_only() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(CreatorKeysContract, ()); + let client = CreatorKeysContractClient::new(&env, &contract_id); + let admin = soroban_sdk::Address::generate(&env); + + client.set_fee_config(&admin, &8000u32, &2000u32); + + let v1 = client.get_protocol_fee_view(); + let v2 = client.get_protocol_fee_view(); + + assert_eq!(v1.creator_bps, v2.creator_bps); + assert_eq!(v1.protocol_bps, v2.protocol_bps); + assert_eq!(v1.is_configured, v2.is_configured); +} + +#[test] +fn test_get_protocol_fee_view_updates_after_reconfiguration() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(CreatorKeysContract, ()); + let client = CreatorKeysContractClient::new(&env, &contract_id); + let admin = soroban_sdk::Address::generate(&env); + + client.set_fee_config(&admin, &9000u32, &1000u32); + let v1 = client.get_protocol_fee_view(); + assert_eq!(v1.protocol_bps, 1000); + + client.set_fee_config(&admin, &8000u32, &2000u32); + let v2 = client.get_protocol_fee_view(); + assert_eq!(v2.protocol_bps, 2000); + assert_eq!(v2.creator_bps, 8000); +}