diff --git a/CONTRACT_INTERFACE.md b/CONTRACT_INTERFACE.md index a3a0bf2..3bf61d1 100644 --- a/CONTRACT_INTERFACE.md +++ b/CONTRACT_INTERFACE.md @@ -179,6 +179,34 @@ let admin_count = get_admin_count(env); --- +### `get_config` + +**Purpose**: Return a stable public contract configuration snapshot for frontends and indexers. + +**Parameters**: +- `env` (Env): The contract environment + +**Return Value**: `ContractConfig` +- `fee_config`: current fee configuration when set +- `treasury`: current treasury address when set +- `admin_count`: current admin count +- `paused`: current pause state; currently `false` because no pause feature is implemented +- `version`: contract config version string +- public limits for projects, reviews, pagination, tags, social links, verification validity, fee payment expiry, and review update cooldown + +**Authorization**: +- None (read-only, permissionless) + +**Possible Errors**: +- None + +**Example**: +```rust +let config = get_config(env); +``` + +--- + ## Project Registry ### `register_project` diff --git a/dongle-smartcontract/README.md b/dongle-smartcontract/README.md index c593002..5c733cc 100644 --- a/dongle-smartcontract/README.md +++ b/dongle-smartcontract/README.md @@ -1573,6 +1573,20 @@ soroban contract invoke \ -- get_admin_count ``` +#### Get Public Contract Configuration + +```bash +soroban contract invoke \ + --id \ + --network testnet \ + -- get_config +``` + +Returns a stable configuration snapshot for frontends and indexers, including +fee settings, treasury, admin count, pause state, version, and public limits. +`paused` is currently `false` because the contract does not yet include a pause +feature. + #### Get Admin List ```bash diff --git a/dongle-smartcontract/src/lib.rs b/dongle-smartcontract/src/lib.rs index 72a25e8..0fe4209 100644 --- a/dongle-smartcontract/src/lib.rs +++ b/dongle-smartcontract/src/lib.rs @@ -43,11 +43,11 @@ use crate::storage_manager::StorageManager; use crate::timelock_manager::TimelockManager; use crate::types::{ AdminActionEntry, AdminProposal, ClaimRequest, ClaimStatus, Collection, ContractClaimRequest, - DependencyRef, DisputeResolutionAction, DisputeStatus, DuplicateDispute, FeeConfig, - FeePaymentRecord, Project, ProjectDependency, ProjectRegistrationParams, ProjectReport, - ProjectSortMode, ProjectStats, ProjectUpdateParams, ProposalPayload, Review, ReviewRevision, - ReviewSortMode, ReviewTombstone, SecurityContactStatus, TimelockAction, VerificationRecord, - VerificationStatus, + ContractConfig, DependencyRef, DisputeResolutionAction, DisputeStatus, DuplicateDispute, + FeeConfig, FeePaymentRecord, Project, ProjectDependency, ProjectRegistrationParams, + ProjectReport, ProjectSortMode, ProjectStats, ProjectUpdateParams, ProposalPayload, Review, + ReviewRevision, ReviewSortMode, ReviewTombstone, SecurityContactStatus, TimelockAction, + VerificationRecord, VerificationStatus, }; use crate::verification_registry::VerificationRegistry; use soroban_sdk::{contract, contractimpl, Address, Env, String, Vec}; @@ -91,6 +91,25 @@ impl DongleContract { AdminManager::get_admin_approval_threshold(&env) } + pub fn get_config(env: Env) -> ContractConfig { + ContractConfig { + fee_config: FeeManager::get_fee_config(&env).ok(), + treasury: FeeManager::get_treasury(&env).ok(), + admin_count: AdminManager::get_admin_count(&env), + paused: false, + version: String::from_str(&env, "1.0.0"), + max_projects_per_user: crate::constants::MAX_PROJECTS_PER_USER, + max_reviews_per_project: crate::constants::MAX_REVIEWS_PER_PROJECT, + max_reviews_per_user: crate::constants::MAX_REVIEWS_PER_USER, + max_page_limit: crate::constants::MAX_PAGE_LIMIT, + max_tags_per_project: crate::constants::MAX_TAGS_PER_PROJECT, + max_social_links: crate::constants::MAX_SOCIAL_LINKS, + verification_validity_period: crate::constants::VERIFICATION_VALIDITY_PERIOD, + fee_payment_expiry_seconds: crate::constants::FEE_PAYMENT_EXPIRY_SECONDS, + review_update_cooldown_seconds: crate::constants::REVIEW_UPDATE_COOLDOWN_SECONDS, + } + } + pub fn set_admin_approval_threshold( env: Env, caller: Address, diff --git a/dongle-smartcontract/src/tests/config.rs b/dongle-smartcontract/src/tests/config.rs new file mode 100644 index 0000000..226e061 --- /dev/null +++ b/dongle-smartcontract/src/tests/config.rs @@ -0,0 +1,63 @@ +use crate::constants::{ + FEE_PAYMENT_EXPIRY_SECONDS, MAX_PAGE_LIMIT, MAX_PROJECTS_PER_USER, MAX_REVIEWS_PER_PROJECT, + MAX_REVIEWS_PER_USER, MAX_SOCIAL_LINKS, MAX_TAGS_PER_PROJECT, REVIEW_UPDATE_COOLDOWN_SECONDS, + VERIFICATION_VALIDITY_PERIOD, +}; +use crate::tests::fixtures::setup_contract; +use soroban_sdk::{testutils::Address as _, Address, Env, String}; + +#[test] +fn config_after_initialization_exposes_defaults_and_limits() { + let env = Env::default(); + let (client, _admin) = setup_contract(&env); + + let config = client.get_config(); + + assert_eq!(config.admin_count, 1); + assert!(!config.paused); + assert_eq!(config.version, String::from_str(&env, "1.0.0")); + assert_eq!(config.fee_config, None); + assert_eq!(config.treasury, None); + assert_eq!(config.max_projects_per_user, MAX_PROJECTS_PER_USER); + assert_eq!(config.max_reviews_per_project, MAX_REVIEWS_PER_PROJECT); + assert_eq!(config.max_reviews_per_user, MAX_REVIEWS_PER_USER); + assert_eq!(config.max_page_limit, MAX_PAGE_LIMIT); + assert_eq!(config.max_tags_per_project, MAX_TAGS_PER_PROJECT); + assert_eq!(config.max_social_links, MAX_SOCIAL_LINKS); + assert_eq!( + config.verification_validity_period, + VERIFICATION_VALIDITY_PERIOD + ); + assert_eq!( + config.fee_payment_expiry_seconds, + FEE_PAYMENT_EXPIRY_SECONDS + ); + assert_eq!( + config.review_update_cooldown_seconds, + REVIEW_UPDATE_COOLDOWN_SECONDS + ); +} + +#[test] +fn config_reflects_fee_updates() { + let env = Env::default(); + env.mock_all_auths(); + let (client, admin) = setup_contract(&env); + let token_admin = Address::generate(&env); + let token = env + .register_stellar_asset_contract_v2(token_admin) + .address(); + let treasury = Address::generate(&env); + + client.set_fee(&admin, &Some(token.clone()), &123u128, &45u128, &treasury); + + let config = client.get_config(); + let fee_config = config.fee_config.expect("fee config should be set"); + + assert_eq!(fee_config.token, Some(token)); + assert_eq!(fee_config.verification_fee, 123); + assert_eq!(fee_config.registration_fee, 45); + assert_eq!(config.treasury, Some(treasury)); + assert_eq!(config.admin_count, 1); + assert!(!config.paused); +} diff --git a/dongle-smartcontract/src/tests/mod.rs b/dongle-smartcontract/src/tests/mod.rs index 27f1642..f52c700 100644 --- a/dongle-smartcontract/src/tests/mod.rs +++ b/dongle-smartcontract/src/tests/mod.rs @@ -19,6 +19,7 @@ mod events; mod moderation; // mod pagination; mod claim; +mod config; mod dependencies; mod maintainers; mod renewal; diff --git a/dongle-smartcontract/src/types.rs b/dongle-smartcontract/src/types.rs index 9a3d35a..660bc4c 100644 --- a/dongle-smartcontract/src/types.rs +++ b/dongle-smartcontract/src/types.rs @@ -267,6 +267,25 @@ pub struct FeeConfig { pub registration_fee: u128, } +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ContractConfig { + pub fee_config: Option, + pub treasury: Option
, + pub admin_count: u32, + pub paused: bool, + pub version: String, + pub max_projects_per_user: u32, + pub max_reviews_per_project: u32, + pub max_reviews_per_user: u32, + pub max_page_limit: u32, + pub max_tags_per_project: u32, + pub max_social_links: u32, + pub verification_validity_period: u64, + pub fee_payment_expiry_seconds: u64, + pub review_update_cooldown_seconds: u64, +} + #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct FeePaymentRecord {