This guide explains how to run and understand the executable documentation examples that demonstrate contract invocation patterns for all three EarnProof contracts.
The EarnProof contracts repository includes comprehensive documentation examples that are executable and validated. These examples:
- Demonstrate real-world contract invocation patterns
- Use synthetic identifiers (e.g.,
"test-issuer-123","proof-id-456") - Run in a local Soroban sandbox environment
- Are automatically validated in CI to prevent documentation drift
- Fail if method signatures or expected behaviors change
cargo test --doc --workspaceThis command runs all examples across all contracts and displays:
- Number of examples found
- Pass/fail status for each example
- Execution time
Run examples for the Protocol Config contract:
cargo test --doc protocol_configRun examples for the Issuer Registry contract:
cargo test --doc issuer_registryRun examples for the Proof Registry contract:
cargo test --doc proof_registryRun cross-contract integration examples:
cargo test --doc integrationcargo test --doc example_initialize_protocol
cargo test --doc example_register_issuer
cargo test --doc example_end_to_end_workflowTo see println! output and more details:
cargo test --doc --workspace -- --nocaptureAll examples are located in tests/doc-examples/:
protocol_config.rs— Protocol-level operations (initialization, schema management, pause controls, admin changes)issuer_registry.rs— Issuer lifecycle management (registration, status transitions, metadata updates, address rotation)proof_registry.rs— Proof lifecycle management (registration, revocation, validity checks)integration.rs— Cross-contract workflows and error scenarios
Each file contains markdown documentation with embedded Rust examples that:
- Set up a test environment with
Env::default() - Mock all authentication with
env.mock_all_auths() - Register contracts and create clients
- Invoke contract methods with synthetic data
- Assert expected outcomes
All examples use synthetic, clearly-named identifiers that represent hashes:
// Protocol config admin - represents a Stellar account
let admin = Address::from_str(&env, "GCFIRY65OQE7DFP5KLNS2PF2LVZMUZYJX4OZIEQ36N2IQANUB5XVYOJR");
// Issuer ID hash - represents sha256("test-issuer-123")
let issuer_id_hash = BytesN::from_array(&env, &[1u8; 32]);
// Proof ID hash - represents sha256("proof-id-456")
let proof_id_hash = BytesN::from_array(&env, &[10u8; 32]);
// Commitment hash - represents sha256(credential_payload)
let commitment_hash = BytesN::from_array(&env, &[11u8; 32]);All examples use env.mock_all_auths() to simulate authorization without requiring real Stellar signatures:
let env = Env::default();
env.mock_all_auths(); // Allows all addresses to pass require_auth() checks
// Now all contract calls requiring authorization will succeed
client.initialize(&admin);
client.pause();
client.register_issuer(&issuer_id_hash, &issuer_address, &metadata_hash);Examples demonstrate state transitions:
Issuer Lifecycle:
// Register issuer in Active state
client.register_issuer(&issuer_id_hash, &issuer_address, &metadata_hash);
assert!(client.is_active_issuer(&issuer_id_hash));
// Suspend issuer
client.suspend_issuer(&issuer_id_hash);
assert!(!client.is_active_issuer(&issuer_id_hash));
// Reactivate issuer
client.reactivate_issuer(&issuer_id_hash);
assert!(client.is_active_issuer(&issuer_id_hash));
// Revoke issuer (terminal state)
client.revoke_issuer(&issuer_id_hash);
assert!(!client.is_active_issuer(&issuer_id_hash));Proof Lifecycle:
// Register proof in Active state
client.register_proof(&proof_id_hash, &commitment_hash, &issuer_address, &schema_version, &expires_at);
assert!(client.is_valid_proof(&proof_id_hash));
// Revoke proof (terminal state)
client.revoke_proof(&proof_id_hash);
assert!(client.is_revoked(&proof_id_hash));
assert!(!client.is_valid_proof(&proof_id_hash));- Initialization — Set up protocol with admin and default state
- Schema Approval — Approve schema versions for proof registration
- Pause Protocol — Pause and unpause to control proof registration
- Change Admin — Transfer admin responsibilities
- Deprecate Schema — Mark schema versions as deprecated
- Initialization — Set up issuer registry with admin
- Register Issuer — Register an issuer with ID hash, address, and metadata
- Suspend/Reactivate — Demonstrate temporary suspension and reactivation
- Revoke Issuer — Revoke issuer (terminal state)
- Update Metadata — Update issuer's metadata hash
- Rotate Address — Change issuer's signing address
- Initialization — Set up proof registry with cross-contract references
- Register Proof — Register proof with validation checks
- Issuer Revocation — Issuer revokes their own proof
- Admin Revocation — Admin revokes a proof for compliance
- Validity Checks — Check proof status and expiration
- End-to-End Workflow — Complete flow from initialization through proof registration
- Paused Protocol Blocks Registration — Demonstrates error when protocol is paused
- Suspended Issuer Blocks Registration — Demonstrates error when issuer is inactive
- Unapproved Schema Blocks Registration — Demonstrates error with unapproved schema version
Examples demonstrate that CI fails if:
- Method signatures change
- Return values differ from expected
- Status transitions are broken
- Authorization requirements change
- Cross-contract validations are removed
All error-case examples use #[should_panic(expected = "...")] to verify that operations fail with expected error messages.
Documentation examples run automatically in CI via:
cargo test --doc --workspaceThis ensures:
- Drift detection: If a contract method signature or behavior changes, related examples fail immediately
- Documentation accuracy: Examples are guaranteed to work as written
- Regression prevention: New contributors cannot accidentally break documented patterns
-
Run all examples before committing:
cargo test --doc --workspace -
Run specific contract examples when working on that contract:
cargo test --doc issuer_registry -
Use
--nocaptureto debug example behavior:cargo test --doc example_register_issuer -- --nocapture -
Update examples when changing contract APIs:
- If you change a method signature, update the corresponding examples
- If you change expected behavior, update assertions
- If you add a new method, add a corresponding example
- Backend Integration Guide — Contract method signatures and parameter types
- Storage Model Reference — Data storage, TTL policies, and lifecycle events
- Main README — Project overview and quick setup