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
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
66 changes: 52 additions & 14 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1561,6 +1561,58 @@ 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 (asset starts in Draft state)
let caps_before = client.get_capabilities();
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!(
client.supports_capability(&Symbol::new(&env, "whitelist")),
CapabilityStatus::Supported
);

// 2. After initialization (still in Draft state)
client.initialize(&admin);
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
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().events().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]
Expand Down Expand Up @@ -1819,13 +1871,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());
Expand All @@ -1842,13 +1887,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);
Expand Down
3 changes: 3 additions & 0 deletions tests/sdk_fixtures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down