From 4a92d7226602ba92478e37144fffd2e89f35effc Mon Sep 17 00:00:00 2001 From: mrmoney10010-design Date: Wed, 29 Jul 2026 08:36:49 -0500 Subject: [PATCH 1/3] docs/test: expose contract capabilities, clean versioning docs, and add unit tests --- README.md | 4 +-- src/test.rs | 57 ++++++++++++++++++++++++++++++++----------- tests/sdk_fixtures.rs | 3 +++ 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 6623011..99f3e6d 100644 --- a/README.md +++ b/README.md @@ -77,9 +77,7 @@ value-encoding rules, and the no-real-user-data guarantee. ## Investor Tooling - [Investor Eligibility Read Helpers](docs/investor-eligibility.md) — compliance, holding-cap, and transfer eligibility read helpers for SDKs and dashboards - -- [Dashboard Integration Readiness Review](docs/dashboard-readiness-review.md) — API gaps, event limitations, and SEP-41 token compatibility risks for front-end integrations -- [Dashboard Release Readiness Review (MVP)](docs/dashboard-release-readiness.md) — UI/UX gaps, test coverage requirements, and security flow risks for the dashboard application +- [Contract Capability Flags](docs/capabilities.md) — read-only capability flags describing supported modules and protocol behaviors for SDKs and dashboards - [Requirement Traceability Mapping](docs/traceability-mapping.md) — mandatory completion table format for PR acceptance criteria mapping, with status tracking and incomplete criteria handling - [Compliance Registry Reads and Indexing Strategy](docs/compliance-registry-reads.md) — supported point reads, event-indexed pagination, consistency guarantees, and dashboard/SDK boundaries diff --git a/src/test.rs b/src/test.rs index 0801264..ec9d560 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1561,6 +1561,49 @@ fn default_capabilities(env: &Env) -> ContractCapabilities { } } +#[test] +fn test_contract_capabilities() { + let (env, client, admin, _user1, _user2) = setup(); + env.mock_all_auths(); + + // 1. Before initialization + let caps_before = client.get_capabilities(); + let mut expected_before = default_capabilities(&env); + assert_eq!(caps_before, expected_before); + + // supports_capability works before initialization + assert_eq!( + client.supports_capability(&Symbol::new(&env, "whitelist")), + CapabilityStatus::Supported + ); + + // 2. After initialization + client.initialize(&admin); + let caps_after = client.get_capabilities(); + expected_before.initialized = true; + assert_eq!(caps_after, expected_before); + + // 3. Read-only / no state changes + // Calling capability endpoints must publish no events and not modify balances or storage + let events_len = env.events().all().len(); + let _ = client.get_capabilities(); + let _ = client.supports_capability(&Symbol::new(&env, "whitelist")); + let _ = client.get_capability_keys(); + assert_eq!(env.events().all().len(), events_len); + + // 4. Backward compatibility: unknown capability returns Unsupported + assert_eq!( + client.supports_capability(&Symbol::new(&env, "some_future_capability")), + CapabilityStatus::Unsupported + ); + + // 5. Check capability keys registry agreement + let keys = client.get_capability_keys(); + assert_eq!(keys.len(), 33); + assert!(keys.contains(Symbol::new(&env, "whitelist"))); + assert!(keys.contains(Symbol::new(&env, "rbac"))); +} + // ─── Asset lifecycle invariants (#55) ───────────────────────────────────────── #[test] @@ -1819,13 +1862,6 @@ fn test_holding_cap_blocks_mint_over_limit() { assert!(r.is_ok()); assert_eq!(client.get_balance_of(&user2), 500); - // Before initialize — no auth mocked, no admin in storage. - assert_eq!( - client.supports_capability(&Symbol::new(&env, "whitelist")), - CapabilityStatus::Supported - ); - assert_eq!(client.get_capability_keys().len(), 33); - // Mint that would push the holder over the cap is rejected. let r = client.try_mint_asset(&user1, &user2, &1); assert!(r.is_err()); @@ -1842,13 +1878,6 @@ fn test_holding_cap_blocks_transfer_over_limit() { client.whitelist_user(&admin, &user1); client.whitelist_user(&admin, &user2); - // And while paused. - assert_eq!( - client.supports_capability(&Symbol::new(&env, "whitelist")), - CapabilityStatus::Supported - ); - assert_eq!(client.get_capability_keys().len(), 33); - // Give user1 a balance, then cap user2's holding at 300. client.mint_asset(&user1, &user1, &1000); client.propose_holding_cap(&admin, &300); diff --git a/tests/sdk_fixtures.rs b/tests/sdk_fixtures.rs index f542174..6e4e58d 100644 --- a/tests/sdk_fixtures.rs +++ b/tests/sdk_fixtures.rs @@ -2249,6 +2249,9 @@ fn fixture_capabilities() { } assert_unique_ids(&scenarios); + // Note: The specific contract capability flags (from `src/capabilities.rs`) + // are comprehensively verified in the unit test suite (`src/test.rs` under + // `test_contract_capabilities`). write_or_verify( "06-capabilities.json", &envelope( From adff90348bd98ee6087707dc5b82805299f3e176 Mon Sep 17 00:00:00 2001 From: mrmoney10010-design Date: Wed, 29 Jul 2026 08:43:35 -0500 Subject: [PATCH 2/3] test: fix event count assertions in test_contract_capabilities --- src/test.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test.rs b/src/test.rs index ec9d560..ca15d46 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1585,11 +1585,11 @@ fn test_contract_capabilities() { // 3. Read-only / no state changes // Calling capability endpoints must publish no events and not modify balances or storage - let events_len = env.events().all().len(); + let events_len = env.events().all().events().len(); let _ = client.get_capabilities(); let _ = client.supports_capability(&Symbol::new(&env, "whitelist")); let _ = client.get_capability_keys(); - assert_eq!(env.events().all().len(), events_len); + assert_eq!(env.events().all().events().len(), events_len); // 4. Backward compatibility: unknown capability returns Unsupported assert_eq!( From 7243120168241d2a68538d4d2d1c4eefc422a0bc Mon Sep 17 00:00:00 2001 From: mrmoney10010-design Date: Wed, 29 Jul 2026 08:45:35 -0500 Subject: [PATCH 3/3] test: fix capability assertions to support Draft to Active state transitions --- src/test.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/test.rs b/src/test.rs index ca15d46..b73acd4 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1566,10 +1566,12 @@ fn test_contract_capabilities() { let (env, client, admin, _user1, _user2) = setup(); env.mock_all_auths(); - // 1. Before initialization + // 1. Before initialization (asset starts in Draft state) let caps_before = client.get_capabilities(); - let mut expected_before = default_capabilities(&env); - assert_eq!(caps_before, expected_before); + let mut expected = default_capabilities(&env); + expected.pause.asset_active = false; + expected.pause.operations_enabled = false; + assert_eq!(caps_before, expected); // supports_capability works before initialization assert_eq!( @@ -1577,11 +1579,18 @@ fn test_contract_capabilities() { CapabilityStatus::Supported ); - // 2. After initialization + // 2. After initialization (still in Draft state) client.initialize(&admin); - let caps_after = client.get_capabilities(); - expected_before.initialized = true; - assert_eq!(caps_after, expected_before); + let caps_after_init = client.get_capabilities(); + expected.initialized = true; + assert_eq!(caps_after_init, expected); + + // 3. After setting status to Active + client.set_asset_status(&admin, &AssetStatus::Active); + let caps_after_active = client.get_capabilities(); + expected.pause.asset_active = true; + expected.pause.operations_enabled = true; + assert_eq!(caps_after_active, expected); // 3. Read-only / no state changes // Calling capability endpoints must publish no events and not modify balances or storage