From c5c626fb11b3e235157826327b8c93f68ed944b2 Mon Sep 17 00:00:00 2001 From: Kaylahray Date: Fri, 27 Mar 2026 16:00:39 +0100 Subject: [PATCH] feat: Documentation Overhaul, Security Hardening & Code Style Enforcement --- .pre-commit-config.yaml | 18 +- CONTRIBUTING.md | 82 ++++++-- DEVELOPMENT.md | 87 +++++++-- SECURITY.md | 219 ++++++++++++++++++--- clippy.toml | 11 +- docs/code-style-guide.md | 315 ++++++++++++++++++++++++++++++ docs/documentation-maintenance.md | 134 +++++++++++++ docs/incident-response.md | 227 +++++++++++++++++++++ docs/security_pipeline.md | 96 ++++++--- docs/threat-model.md | 186 ++++++++++++++++++ rust-toolchain.toml | 2 +- rustfmt.toml | 3 +- scripts/setup-pre-commit.sh | 14 +- 13 files changed, 1293 insertions(+), 101 deletions(-) create mode 100644 docs/code-style-guide.md create mode 100644 docs/documentation-maintenance.md create mode 100644 docs/incident-response.md create mode 100644 docs/threat-model.md diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ff88e8fc7..d21936f6b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,7 @@ # PropChain Pre-commit Configuration -# This file configures pre-commit hooks for code quality and consistency +# This file configures pre-commit hooks for code quality and consistency. +# See docs/code-style-guide.md for the rationale behind each hook. +# To install: ./scripts/setup-pre-commit.sh repos: # Rust formatting and linting @@ -102,6 +104,20 @@ repos: args: [--no-deps, --document-private-items] pass_filenames: false + - id: cargo-audit + name: cargo audit (dependency CVEs) + entry: cargo audit + language: system + args: [--deny, warnings] + pass_filenames: false + + - id: cargo-deny + name: cargo deny (license & dependency policy) + entry: cargo deny + language: system + args: [check] + pass_filenames: false + # Configuration for specific hooks default_language_version: python: python3 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5018ac3cb..aa2d15f60 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,14 +2,16 @@ Thank you for your interest in contributing to PropChain Smart Contracts! This guide will help you get started with contributing to our Rust-based smart contract system. +> **Documentation Version**: 2.0.0 — Updated March 2026 + ## 🚀 Getting Started ### Prerequisites Before you start contributing, make sure you have: -- **Rust** 1.70+ installed with stable toolchain -- **cargo-contract** CLI for ink! smart contract development +- **Rust** 1.75+ installed with stable toolchain (pinned in `rust-toolchain.toml`) +- **cargo-contract** 3.x CLI for ink! smart contract development - **Git** for version control - Basic understanding of **Rust** and **ink!** framework - Familiarity with **Substrate/Polkadot** ecosystem @@ -27,19 +29,25 @@ Before you start contributing, make sure you have: ```bash # Install Rust (if not already installed) curl https://sh.rustup.rs -sSf | sh - + # Install cargo-contract - cargo install cargo-contract --locked - + cargo install cargo-contract --locked --version "^3" + # Add WASM target rustup target add wasm32-unknown-unknown + + # Optional: dependency auditing tools + cargo install cargo-deny cargo-audit ``` 3. **Set up your development environment** ```bash + # Install pre-commit hooks (required — see Code Style section) + ./scripts/setup-pre-commit.sh + # Build the contracts cargo contract build - + # Run tests to ensure everything works cargo test ``` @@ -127,11 +135,29 @@ git push origin feature/your-feature-name ## 📝 Code Style Guidelines +See [docs/code-style-guide.md](docs/code-style-guide.md) for the full reference. The highlights are: + +### Automated Enforcement + +All style checks run automatically via pre-commit hooks (installed by `./scripts/setup-pre-commit.sh`). +You can also run them manually: + +```bash +# Format +cargo fmt + +# Lint (zero warnings policy) +cargo clippy -- -D warnings + +# Run all pre-commit checks +pre-commit run --all-files +``` + ### Rust Standards - Follow [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/) -- Use `cargo fmt` for consistent formatting -- Run `cargo clippy` and fix all warnings -- Prefer `unwrap()` only when you're certain it won't panic +- `rustfmt.toml` enforces formatting — never work around it +- `clippy.toml` enforces lint thresholds — fix warnings, don't silence them with `#[allow]` without a comment justifying why +- Prefer `unwrap()` only inside `#[cfg(test)]` blocks ### ink! Smart Contract Best Practices - Keep contract logic simple and gas-efficient @@ -219,30 +245,45 @@ mod tests { ### Before Submitting - [ ] All tests pass (`cargo test`) - [ ] Code is formatted (`cargo fmt`) -- [ ] No clippy warnings (`cargo clippy`) -- [ ] Documentation is updated -- [ ] CHANGELOG.md is updated (if applicable) +- [ ] No clippy warnings (`cargo clippy -- -D warnings`) +- [ ] Pre-commit hooks pass (`pre-commit run --all-files`) +- [ ] Documentation updated for any changed behaviour (see [Documentation Guidelines](#-documentation-guidelines)) +- [ ] `CHANGELOG.md` updated (if applicable) +- [ ] `cargo audit` passes — no new CVEs (`cargo audit --deny warnings`) +- [ ] `cargo deny check` passes ### PR Description Your PR should include: -- **Title**: Clear and descriptive +- **Title**: Clear and descriptive (Conventional Commits format: `feat:`, `fix:`, `docs:`, etc.) - **Description**: What changes were made and why - **Testing**: How you tested the changes -- **Screenshots**: If UI changes are involved - **Breaking Changes**: Clearly highlight any breaking changes +- **Documentation**: Links to updated docs ### Review Process -1. **Automated Checks**: CI/CD pipeline runs tests and linting -2. **Peer Review**: At least one maintainer must review -3. **Security Review**: For sensitive changes -4. **Approval**: Merge after all requirements are met +1. **Automated Checks**: CI pipeline runs tests, linting, security scan, and cargo-audit +2. **Peer Review**: At least one maintainer must review and approve +3. **Security Review**: Add `security-review` label for changes to auth, crypto, or cross-contract calls +4. **Approval**: Merge after all checks pass and approval is given ## 🔒 Security Considerations - Never commit private keys or sensitive data -- Follow secure coding practices for smart contracts +- Follow secure coding practices for smart contracts — see [SECURITY.md](SECURITY.md) - Consider gas optimization and DoS protection -- Report security vulnerabilities privately +- Report security vulnerabilities privately via the process in [SECURITY.md](SECURITY.md) + +## 📚 Documentation Guidelines + +Documentation must stay in sync with code changes. When you submit a PR: + +1. **Update docs**: If you change contract behaviour, update the corresponding file in `docs/`. +2. **New features**: Create or update `docs/` coverage. All public `#[ink(message)]` functions must have rustdoc. +3. **Version the doc**: Bump the `> **Documentation Version**` header in any doc file you edit. +4. **Architecture decisions**: If your change affects system design, add an ADR in `docs/adr/`. +5. **Tutorials**: If you add a major new capability, add a tutorial in `docs/tutorials/`. + +See [docs/documentation-maintenance.md](docs/documentation-maintenance.md) for the full process. ## 📚 Resources @@ -250,6 +291,7 @@ Your PR should include: - [ink! Documentation](https://use.ink/) - [Substrate Documentation](https://substrate.io/) - [Rust Book](https://doc.rust-lang.org/book/) +- [Code Style Guide](docs/code-style-guide.md) ### Community - [Polkadot Discord](https://discord.gg/polkadot) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 8917fbe93..a52b06f12 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -1,5 +1,8 @@ # PropChain Development Environment Setup +> **Documentation Version**: 2.0.0 — Updated March 2026 +> Covers all contracts shipped in release v2.x. See [Documentation Maintenance](docs/documentation-maintenance.md) for the versioning policy. + This guide will help you set up a complete development environment for PropChain smart contracts. ## Quick Start @@ -22,9 +25,10 @@ docker-compose up -d ## Prerequisites -- **Rust** 1.70+ with stable toolchain +- **Rust** 1.75+ with stable toolchain (see `rust-toolchain.toml`) +- **cargo-contract** 3.x for ink! smart contract development - **Docker** and Docker Compose -- **Node.js** 16+ (for frontend development) +- **Node.js** 18+ (for frontend / SDK development) - **Git** ## Manual Setup @@ -36,11 +40,17 @@ docker-compose up -d curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source ~/.cargo/env -# Install cargo-contract -cargo install cargo-contract --locked +# The repo's rust-toolchain.toml pins the exact stable channel automatically; +# just run any cargo command and rustup will download the right toolchain. + +# Install cargo-contract (ink! CLI) +cargo install cargo-contract --locked --version "^3" -# Add WASM target +# Add WASM compile target rustup target add wasm32-unknown-unknown + +# Optional but recommended +cargo install cargo-deny cargo-audit ``` ### 2. Setup Pre-commit Hooks @@ -120,21 +130,46 @@ pre-commit run --all-files ``` PropChain-contract/ -├── contracts/ # Smart contract source code -│ ├── lib/ # Main contract implementations -│ ├── traits/ # Shared trait definitions -│ └── tests/ # Contract-specific tests -├── scripts/ # Development and deployment scripts -├── tests/ # Integration and E2E tests -├── docs/ # Documentation -│ ├── tutorials/ # Step-by-step guides -│ ├── contracts.md # API documentation -│ ├── integration.md # Integration guide -│ ├── deployment.md # Deployment guide -│ └── architecture.md # Technical architecture -├── .github/workflows/ # CI/CD pipelines -├── docker-compose.yml # Local development stack -└── rust-toolchain.toml # Rust version configuration +├── contracts/ # Smart contract source code +│ ├── ai-valuation/ # On-chain AI property valuation oracle +│ ├── analytics/ # Event analytics aggregator +│ ├── bridge/ # Cross-chain asset bridge +│ ├── compliance_registry/ # KYC/AML compliance registry +│ ├── escrow/ # Escrow and settlement engine +│ ├── fees/ # Dynamic fee calculation +│ ├── fractional/ # Fractional ownership shares +│ ├── governance/ # DAO governance and voting +│ ├── insurance/ # Property insurance pools +│ ├── ipfs-metadata/ # IPFS metadata pointer contract +│ ├── lib/ # Shared library code & trait implementations +│ ├── oracle/ # Price and property data oracle +│ ├── prediction-market/ # Property price prediction market +│ ├── property-management/ # Property lifecycle management +│ ├── property-token/ # ERC-721 property NFT (PSP34) +│ ├── proxy/ # Upgradeable proxy pattern +│ ├── staking/ # PROP token staking +│ ├── traits/ # Shared ink! trait interfaces +│ └── zk-compliance/ # Zero-knowledge compliance proofs +├── scripts/ # Development and deployment scripts +├── tests/ # Integration and E2E tests +├── docs/ # Documentation (see docs/documentation-maintenance.md) +│ ├── adr/ # Architecture Decision Records +│ ├── tutorials/ # Step-by-step guides +│ ├── architecture.md +│ ├── code-style-guide.md # Code style reference +│ ├── contracts.md +│ ├── deployment.md +│ ├── incident-response.md # Security incident procedures +│ ├── integration.md +│ ├── security_pipeline.md +│ ├── testing-guide.md +│ └── threat-model.md # Threat model & mitigations +├── security-audit/ # Custom security scanner binary +├── .pre-commit-config.yaml # Pre-commit hook configuration +├── clippy.toml # Clippy lint configuration +├── docker-compose.yml # Local development stack +├── rust-toolchain.toml # Rust version pin +└── rustfmt.toml # Formatting configuration ``` ## Environment Configuration @@ -248,3 +283,15 @@ Install these extensions: 2. Follow the [Basic Property Registration Tutorial](docs/tutorials/basic-property-registration.md) 3. Explore the [Contract API](docs/contracts.md) 4. Set up your [Frontend Integration](docs/integration.md) +5. Read the [Code Style Guide](docs/code-style-guide.md) +6. Review the [Security Pipeline](docs/security_pipeline.md) + +## Documentation Maintenance + +Documentation is versioned alongside the code. When you add or change behaviour: + +1. Update the relevant `docs/` file in the same PR. +2. Bump the `> **Documentation Version**` header in any file you change. +3. Add an entry to `docs/adr/` if you are making an architectural decision. + +See [docs/documentation-maintenance.md](docs/documentation-maintenance.md) for the full process. diff --git a/SECURITY.md b/SECURITY.md index 9dfec4ade..303c2d6ee 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,29 +1,196 @@ # Security Policy +> **Documentation Version**: 2.0.0 — Updated March 2026 + +This document is the top-level security reference for PropChain Smart Contracts. It covers the security pipeline, best practices, audit procedures, and incident response. + +**Related documents:** +- [Threat Model](docs/threat-model.md) — threat actors, attack vectors, and mitigations +- [Incident Response](docs/incident-response.md) — step-by-step runbook for security incidents +- [Security Pipeline](docs/security_pipeline.md) — automated CI/CD security toolchain + +--- + +## Table of Contents + +1. [Reporting a Vulnerability](#reporting-a-vulnerability) +2. [Security Best Practices](#security-best-practices) +3. [Security Pipeline & Automated Checks](#security-pipeline--automated-checks) +4. [Security Audit Documentation](#security-audit-documentation) +5. [Threat Model Summary](#threat-model-summary) +6. [Incident Response Summary](#incident-response-summary) + +--- + +## Reporting a Vulnerability + +**DO NOT** open a public GitHub issue. Use responsible disclosure: + +1. Email **security@propchain.io** with subject `[SECURITY] `. +2. Include: + - Description of the vulnerability + - Reproduction steps (contract method, inputs, expected vs actual behaviour) + - Potential impact assessment + - Any suggested mitigations +3. You will receive an acknowledgement within **48 hours**. +4. Our team will triage, fix, and coordinate disclosure with you. +5. We operate a bug bounty — severity-based rewards are paid after fix confirmation. + +**Embargo period**: We request a minimum 90-day embargo from disclosure to public announcement to allow dependent integrators to patch. + +--- + +## Security Best Practices + +### Reentrancy and Cross-Contract Calls + +- Complete all state mutations **before** making cross-contract calls (checks-effects-interactions pattern). +- Never re-enter a contract from a callback unless you have verified the caller. +- Use ink!'s `CallBuilder` with explicit gas limits for cross-contract calls. + +### Integer Arithmetic + +- Use `checked_add`, `checked_sub`, `checked_mul`, or `saturating_*` for all arithmetic on user-supplied values. +- Never rely solely on `overflow-checks = true` in `Cargo.toml`; that flag is off in release WASM by default. + +```rust +// BAD +let total = balance + amount; + +// GOOD +let total = balance.checked_add(amount).ok_or(Error::Overflow)?; +``` + +### Access Control + +- Every state-mutating `#[ink(message)]` must enforce caller authorization. +- Use the `only_owner` / `only_role` patterns from `contracts/lib/`. +- Never use `self.env().caller()` as the sole proof of identity for privileged actions without an allowlist or role check. + +### `unsafe` Blocks + +- `unsafe` is **forbidden** in contract code. +- In non-contract Rust code (tooling, scripts), `unsafe` requires a `// SAFETY:` comment explaining why it is sound. +- CI clippy rules deny `unsafe_code` in the `contracts/` workspace. + +### Input Validation + +- Validate and bound all user-supplied lengths (strings, arrays, vecs) at the message boundary. +- Return an explicit `Error` variant rather than panicking. Panics in ink! contracts revert the transaction but can hide bugs. + +### Storage + +- Avoid unbounded storage growth. Use `Mapping` rather than `Vec` for sets that grow proportional to user count. +- Do not store plaintext PII on-chain. Store only hashes or IPFS CIDs. + +### Dependency Management + +- `cargo deny` and `cargo audit` run in CI and block merges on known CVEs. +- Add new dependencies only if they pass `cargo deny check` and have a credible maintainer. + +### Secret Management + +- Never commit private keys, mnemonics, or API secrets to the repository. +- CI secrets are stored in GitHub Actions encrypted secrets only. +- The `detect-secrets` pre-commit hook scans every commit for accidental secret leakage. + +--- + ## Security Pipeline & Automated Checks -All contributions to `PropChain-contract` must pass our rigorous security pipeline: -1. **Static Analysis**: `cargo clippy` and custom linters run on all modules. -2. **Dependency Scanning**: `cargo audit` & `cargo deny` ensure no vulnerable/unapproved dependencies. -3. **Formal Verification**: `cargo contract verify` and `cargo kani` run for formal theorem proving of our smart contracts. -4. **Fuzzing Tests**: `proptest` ensures fuzzy inputs handle edge cases safely. -5. **Gas Optimization Analysis**: `security-audit-tool` limits expensive structures (e.g. nested loops, vectors). -6. **Vulnerability Scanning**: `slither` handles general checks and `trivy` scans structural dependencies. - -## Best Practices Guide -- NEVER use `unsafe { ... }` blocks unless fundamentally necessary (e.g. zero-copy serialization optimizations), and ensure thorough fuzzing limits access. -- Avoid large allocations (`Vec`) - use mappings instead when scaling data points. -- Implement explicit integer size conversions or `saturating_mul` / `checked_add` to prevent overflows, even outside of `overflow-checks = true` bounds. -- Always include explicit assertions for input validations. - -## Security Incident Response Workflow - -If you discover a security vulnerability, we would appreciate if you could disclose it responsibly. - -**DO NOT** open a public issue! Instead, follow these steps: -1. Email our security team at `security@propchain.io` (or the repository owner). -2. Write a detailed description of the vulnerability, including reproduceable steps. -3. Wait for our acknowledgement (typically within 48 hours). -4. Our team will triage the issue and respond with a timeline for fixing. -5. Once resolved and merged, we will coordinate public disclosure if needed. - -Thank you for helping keep PropChain secure! + +All contributions pass the following automated security pipeline. See [docs/security_pipeline.md](docs/security_pipeline.md) for configuration details. + +| Tool | What it checks | Failure action | +|---|---|---| +| `cargo clippy -- -D warnings` | Lint errors, unsafe code, complexity | Blocks merge | +| `cargo audit` | RustSec CVEs in `Cargo.lock` | Blocks merge | +| `cargo deny check` | License compliance, banned crates, duplicate deps | Blocks merge | +| Custom `security-audit` binary | Unsafe blocks, TODO/FIXME density, cyclomatic complexity | Blocks merge | +| `trivy fs` | OS-level and dependency CVEs | Blocks merge | +| `cargo kani` | Formal verification of critical proof harnesses | Blocks merge | +| `detect-secrets` (pre-commit) | Secret patterns in committed files | Blocks commit | + +### Running Locally + +```bash +# Full security audit +cargo build --release --bin security-audit +./target/release/security-audit audit --report report.json + +# Dependency audit +cargo audit +cargo deny check + +# Formal verification +cargo kani + +# Pre-commit scan +pre-commit run --all-files +``` + +--- + +## Security Audit Documentation + +### Scope + +The security audit covers all contracts in `contracts/`, the shared library in `contracts/lib/`, and the `security-audit` tooling in `security-audit/`. + +Out-of-scope: off-chain SDK code, scripts, frontend. + +### Audit History + +| Date | Auditor | Scope | Report | +|---|---|---|---| +| Internal | PropChain security team | All contracts v1.x | `report.json` (root) | + +> External audits will be listed here when commissioned. See [docs/security_pipeline.md](docs/security_pipeline.md) for the automated audit approach used between external audits. + +### Security Score + +The `security-audit` tool produces a score (0–100): + +| Deduction | Condition | +|---|---| +| –10 points | Each clippy error | +| –2 points | Each clippy warning | +| –5 points | Each `unsafe` block | +| –20 points | Each known CVE in dependencies | + +Target score: **≥ 90** for any release branch. + +### Requesting a Security Review + +For changes to core authentication, cross-contract calls, or cryptographic operations, request a dedicated security review in your PR by adding the label `security-review` and pinging `@security-team`. + +--- + +## Threat Model Summary + +See [docs/threat-model.md](docs/threat-model.md) for the full threat model. Key high-severity threats: + +| Threat | Mitigation | +|---|---| +| Reentrancy attack on Escrow | CEI pattern enforced; cross-contract call after state update | +| Integer overflow in Token | `checked_*` arithmetic on all user inputs | +| Unauthorized minting | `only_owner` guard + compliance check on all mint messages | +| Malicious oracle data | Median aggregation across N oracles; staleness timeout | +| Compromised admin key | Multisig required for all admin operations | +| Dependency supply-chain attack | `cargo deny` allowlist; `cargo audit` in CI | + +--- + +## Incident Response Summary + +See [docs/incident-response.md](docs/incident-response.md) for the full runbook. High-level steps: + +1. **Detect** — automated alert or responsible disclosure email. +2. **Contain** — pause affected contracts via admin pause mechanism. +3. **Assess** — determine scope, severity (Critical / High / Medium / Low), and affected users. +4. **Fix** — develop and audit patch on a private branch. +5. **Disclose** — notify affected parties before publishing the fix. +6. **Deploy** — upgrade or redeploy contracts via the proxy upgrade mechanism. +7. **Post-mortem** — write a public post-mortem within 30 days. + +**Emergency contacts**: security@propchain.io | Discord `#security-private` (invite-only) + diff --git a/clippy.toml b/clippy.toml index b94e68e59..100d5bc4d 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,6 +1,7 @@ # Clippy configuration for PropChain smart contracts +# Reviewed: March 2026 — see docs/code-style-guide.md for threshold rationale. # Lint configuration -msrv = "1.70.0" +msrv = "1.75.0" # Enable additional lints cognitive-complexity-threshold = 30 @@ -21,8 +22,8 @@ missing-docs-in-crate-items = false # Metadatas configuration avoid-breaking-exported-api = true -# Disallowed methods -disallowed-names = ["foo", "bar", "baz", "qux"] +# Placeholder names are banned — use descriptive identifiers. +disallowed-names = ["foo", "bar", "baz", "qux", "tmp", "temp"] # Enforced naming conventions enforced-import-renames = [] @@ -51,8 +52,8 @@ literal-representation-threshold = 20 # format-push-str = "allow" # format-use-stderr = "allow" -# Unsafe configuration -# unsafe-code = "deny" +# Unsafe configuration — unsafe blocks are forbidden in contract code. +# unsafe-code = "deny" # enforced via deny(unsafe_code) attribute in contract lib.rs # Test configuration allow-expect-in-tests = true diff --git a/docs/code-style-guide.md b/docs/code-style-guide.md new file mode 100644 index 000000000..2a6ce61a8 --- /dev/null +++ b/docs/code-style-guide.md @@ -0,0 +1,315 @@ +# Code Style Guide + +> **Documentation Version**: 1.0.0 — Created March 2026 + +This document is the canonical code style reference for PropChain Smart Contracts. Style is automatically enforced by `rustfmt`, `clippy`, and the pre-commit hooks. Read this guide to understand *why* the rules exist, not just *what* they are. + +**Related documents:** +- [CONTRIBUTING.md](../CONTRIBUTING.md) — contribution workflow +- [docs/commenting-standards.md](commenting-standards.md) — rustdoc conventions +- [`.pre-commit-config.yaml`](../.pre-commit-config.yaml) — automated enforcement + +--- + +## Automated Enforcement + +All style checks run automatically. You should never need to manually fix style issues that tooling can fix: + +```bash +# Fix formatting automatically +cargo fmt + +# Check formatting without fixing (CI mode) +cargo fmt --check + +# Run lints (zero-warnings policy) +cargo clippy -- -D warnings + +# Run all pre-commit checks on staged files +pre-commit run + +# Run all pre-commit checks on every file +pre-commit run --all-files +``` + +If a `#[allow(clippy::...)]` attribute is required, it **must** have a comment justifying the exception: + +```rust +// STYLE-EXCEPTION: this function legitimately takes 8 args because it mirrors +// the on-chain storage struct fields 1:1; splitting it would hurt readability. +#[allow(clippy::too_many_arguments)] +pub fn new(...) -> Self { ... } +``` + +--- + +## Formatting (`rustfmt.toml`) + +The project's `rustfmt.toml` enforces: + +| Setting | Value | Reason | +|---|---|---| +| `max_width` | 100 | Fits on most displays without horizontal scroll | +| `tab_spaces` | 4 | Rust community standard | +| `newline_style` | Unix (`\n`) | Consistent across OS | +| `reorder_imports` | true | Deterministic import order | +| `edition` | 2021 | Current edition | +| `merge_derives` | true | Reduce noise | + +**Never** add `// rustfmt::skip` without a comment explaining why. + +--- + +## Naming Conventions + +### Types and Structs + +```rust +// PascalCase for all type-level items +pub struct PropertyRegistry { ... } +pub enum Error { NotFound, Unauthorized } +pub type PropertyId = u64; +pub trait Mintable { ... } +``` + +### Functions and Methods + +```rust +// snake_case for all value-level items +pub fn register_property(...) -> Result<(), Error> { ... } +let property_count = self.count(); +``` + +### Constants and Statics + +```rust +// SCREAMING_SNAKE_CASE — both const and static +pub const MAX_PROPERTIES: u32 = 10_000; +pub const GOVERNANCE_TIMELOCK: u64 = 72 * 3_600; +``` + +### ink! Specific + +```rust +// Contract struct name mirrors the contract's published name +// (matches the name in Cargo.toml [package].name in PascalCase) +#[ink::contract] +pub mod property_token { + pub struct PropertyToken { ... } // PascalCase +} + +// Storage field names: snake_case +#[ink(storage)] +pub struct PropertyToken { + owner: AccountId, + total_supply: Balance, + token_approvals: Mapping, +} +``` + +### Modules + +```rust +// snake_case for module names — mirrors directory structure +mod compliance_checks { ... } +mod storage_utils { ... } +``` + +--- + +## File Organisation + +A contract source file should be organised in this order: + +1. Module-level `#![...]` attributes +2. `use` imports (sorted by `rustfmt`) +3. `pub type` aliases +4. `pub const` / `pub static` +5. `#[ink::contract]` module + 1. `#[ink(storage)]` struct + 2. `impl` block — constructor(s) first, then `#[ink(message)]` methods, then private helpers + 3. `mod tests` +6. Non-contract `impl` blocks and helpers + +--- + +## Error Handling + +```rust +// Define a dedicated Error enum per contract — never use String errors +#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] +pub enum Error { + /// The caller is not authorised to perform this action. + Unauthorized, + /// The property does not exist. + PropertyNotFound, + /// Arithmetic overflow. + Overflow, +} + +// Return Result from all fallible messages +#[ink(message)] +pub fn transfer(&mut self, to: AccountId, value: Balance) -> Result<(), Error> { + let balance = self.balances.get(self.env().caller()).unwrap_or(0); + let new_balance = balance.checked_sub(value).ok_or(Error::Overflow)?; + self.balances.insert(self.env().caller(), &new_balance); + Ok(()) +} +``` + +- **Never** `panic!` in contract code; panics abort and may leave state inconsistent. +- **Never** use `unwrap()` in contract code outside `#[cfg(test)]`. +- **Never** use `expect()` in contract code outside `#[cfg(test)]`. + +--- + +## Integer Arithmetic + +```rust +// Always use checked or saturating arithmetic on user inputs +// BAD +let new_supply = self.total_supply + amount; + +// GOOD +let new_supply = self.total_supply + .checked_add(amount) + .ok_or(Error::Overflow)?; +``` + +`saturating_*` is acceptable when overflow indicates a business rule violation rather than a bug (e.g., capping a counter at max value). + +--- + +## Storage + +```rust +// Use Mapping for collections that grow per-user +// BAD (O(n) unbounded iteration) +owners: Vec, + +// GOOD (O(1) access) +owners: Mapping, +``` + +- Do not store user-controlled strings longer than 256 bytes without explicit length checks. +- Never store sensitive data (PII, private keys) on-chain. Store hashes or IPFS CIDs only. + +--- + +## Comments and Documentation + +Full rustdoc conventions are in [docs/commenting-standards.md](commenting-standards.md). Short summary: + +```rust +/// Short one-line summary (imperative mood, no trailing period for single line). +/// +/// Longer description if needed. Explains *why*, not *what* — the code +/// already shows what it does. +/// +/// # Arguments +/// +/// * `value` - The amount to transfer, in smallest denomination. +/// +/// # Errors +/// +/// Returns [`Error::Unauthorized`] if the caller is not the token owner. +/// Returns [`Error::Overflow`] if the balance would overflow. +/// +/// # Example +/// +/// ```rust +/// assert!(contract.transfer(alice, 100).is_ok()); +/// ``` +#[ink(message)] +pub fn transfer(&mut self, to: AccountId, value: Balance) -> Result<(), Error> { +``` + +### Inline Comments + +```rust +// Use inline comments sparingly — only when the *why* is non-obvious +let snapshot_block = self.env().block_number() + .saturating_sub(1); // snapshot at N-1 to prevent flash-loan attacks +``` + +Do **not** comment self-evident code: + +```rust +// BAD: comment just repeats the code +// increment the counter +self.count += 1; +``` + +--- + +## Testing Style + +```rust +#[cfg(test)] +mod tests { + use super::*; + use ink::env::test; + + // Test name: __ + #[test] + fn transfer_zero_balance_returns_overflow_error() { + // Arrange + let mut contract = PropertyToken::new(AccountId::from([0x1; 32])); + + // Act + let result = contract.transfer(AccountId::from([0x2; 32]), u128::MAX); + + // Assert + assert_eq!(result, Err(Error::Overflow)); + } +} +``` + +- Use Arrange / Act / Assert structure with blank-line separators. +- Test name describes scenario + expected outcome. +- Each test should test exactly one behaviour. +- Do not share mutable state between tests. + +--- + +## Pre-commit Hooks + +The `.pre-commit-config.yaml` enforces the following on every commit: + +| Hook | What it enforces | +|---|---| +| `rust-fmt` | `cargo fmt --check` | +| `rust-clippy` | `cargo clippy -- -D warnings` | +| `cargo-check` | Type-checks without building | +| `trailing-whitespace` | No trailing spaces | +| `end-of-file-fixer` | Files end with a newline | +| `detect-secrets` | No accidental secret leakage | +| `mdformat` | Consistent Markdown formatting | +| `shfmt` | Shell script formatting | +| `hadolint` | Dockerfile linting | +| `cargo-contract-build` | Contracts compile to WASM | +| `cargo-contract-test` | Contract unit tests pass | + +To install hooks: + +```bash +./scripts/setup-pre-commit.sh +``` + +--- + +## Code Style Monitoring + +The clippy configuration in `clippy.toml` enforces these thresholds: + +| Metric | Threshold | +|---|---| +| Cognitive complexity per function | 30 | +| Function arguments | 7 | +| Lines per function | 100 | +| Type complexity | 250 | + +If CI clippy fails, **fix the code** — do not raise the threshold without a team discussion and a comment in `clippy.toml` explaining the new value. + +Review `clippy.toml` thresholds quarterly and lower them as the codebase matures. diff --git a/docs/documentation-maintenance.md b/docs/documentation-maintenance.md new file mode 100644 index 000000000..d65e68529 --- /dev/null +++ b/docs/documentation-maintenance.md @@ -0,0 +1,134 @@ +# Documentation Maintenance Process + +> **Documentation Version**: 1.0.0 — Created March 2026 + +This document defines the process for keeping PropChain documentation accurate, versioned, and up to date. + +## Versioning Policy + +Documentation versions follow **MAJOR.MINOR.PATCH** semantics, independent of but synchronized with contract releases: + +| Change type | Version bump | Example | +|---|---|---| +| Complete rewrite of a doc | MAJOR | `1.x.x → 2.0.0` | +| New section added or significant expansion | MINOR | `1.0.x → 1.1.0` | +| Typo fix, link update, minor correction | PATCH | `1.0.0 → 1.0.1` | + +Every documentation file includes a version banner at the top: + +```markdown +> **Documentation Version**: X.Y.Z — Updated Month YYYY +``` + +Bump this in the same PR as the content change. + +## Ownership + +| Document | Owner | +|---|---| +| `docs/architecture.md` | Protocol team | +| `docs/contracts.md` | Contract authors (per contract) | +| `docs/security_pipeline.md`, `SECURITY.md`, `docs/threat-model.md`, `docs/incident-response.md` | Security team | +| `docs/deployment.md` | DevOps team | +| `docs/code-style-guide.md` | All contributors / maintainers | +| `docs/tutorials/` | Developer relations | +| `CONTRIBUTING.md`, `DEVELOPMENT.md` | All maintainers | +| `docs/adr/` | Author of the decision | + +If you change code in a module, you own the documentation update for that module. + +## When to Update Documentation + +### Required (blocks PR merge) +- Any change to a public `#[ink(message)]` signature +- Any change to storage layout +- New contract deployed or removed +- New CLI script or changed script behaviour +- New environment variable or configuration key +- Security policy or incident response changes + +### Recommended +- Refactoring that changes internal design significantly +- Performance improvements worth highlighting +- Bug fixes that users or integrators should know about + +## Documentation Review Checklist + +Reviewers should verify: + +- [ ] Version header bumped if content changed +- [ ] All new `#[ink(message)]` functions have rustdoc (`///`) +- [ ] `docs/contracts.md` API table up to date +- [ ] Links in updated doc still resolve (no broken relative paths) +- [ ] Code examples in docs compile (if testable) +- [ ] Architecture diagrams updated if topology changed +- [ ] `CHANGELOG.md` entry added for user-visible changes + +## Directory Structure + +``` +docs/ +├── adr/ # Architecture Decision Records (never delete) +│ └── NNNN-description.md +├── tutorials/ # Beginner-friendly task guides +├── architecture.md # System overview and design +├── best-practices.md # Integration best practices +├── BRIDGE_GUIDE.md # Cross-chain bridge usage +├── code-style-guide.md # Code style reference +├── commenting-standards.md # Rustdoc standards +├── compliance-*.md # Compliance and regulatory docs +├── contracts.md # API reference for all contracts +├── deployment.md # Deployment procedures +├── DISASTER_RECOVERY.md # Disaster recovery runbook +├── documentation-maintenance.md # This file +├── dynamic-fees-and-market.md # Fee model documentation +├── error-handling.md # Error catalogue +├── health-checks.md # Health monitoring +├── incident-response.md # Security incident runbook +├── integration.md # SDK / frontend integration guide +├── logging.md # Logging conventions +├── onboarding-checklist.md # New contributor checklist +├── security_pipeline.md # CI security toolchain +├── storage-patterns.md # On-chain storage patterns +├── testing-guide.md # Testing strategy +├── threat-model.md # Threat model and mitigations +└── troubleshooting-faq.md # Common problems +``` + +## Architecture Decision Records (ADRs) + +For every significant design decision: + +1. Copy `docs/adr/0001-record-architecture-decisions.md` as a template. +2. Number sequentially: `docs/adr/NNNN-short-title.md`. +3. Set status to `Proposed` → `Accepted` / `Rejected` / `Superseded`. +4. Link to the ADR from the relevant `docs/` or contract source file. + +ADRs are **immutable once accepted** — supersede them with a new ADR rather than editing. + +## Regular Maintenance Schedule + +| Cadence | Activity | +|---|---| +| Every PR | Update docs for changed behaviour (required) | +| Weekly | Scan for broken links (`scripts/check-links.sh` if available) | +| Monthly | Review tutorial accuracy against latest contract ABIs | +| Per release | Full doc audit — bump MINOR version on any outdated files | +| Annually | Full rewrite review — deprecate or archive stale docs | + +## Creating New Documentation + +1. Determine the right file: is it a tutorial, a reference, or a runbook? +2. Use an existing file as a template for structure. +3. Add the version header. +4. Link to the new file from the relevant parent doc (`docs/contracts.md`, `CONTRIBUTING.md`, `DEVELOPMENT.md`, etc.). +5. Add an entry to the directory structure table above. + +## Deprecating Documentation + +1. Add a deprecation notice at the top of the file: + ```markdown + > **DEPRECATED**: This document is superseded by [new-doc.md](new-doc.md) as of vX.Y. + ``` +2. Keep the file for at least one release cycle. +3. Delete in a follow-up PR after the release. diff --git a/docs/incident-response.md b/docs/incident-response.md new file mode 100644 index 000000000..263c0d1ec --- /dev/null +++ b/docs/incident-response.md @@ -0,0 +1,227 @@ +# Incident Response Runbook + +> **Documentation Version**: 1.0.0 — Created March 2026 + +This runbook defines the procedures for detecting, containing, assessing, resolving, and learning from security incidents affecting PropChain smart contracts. + +**Related documents:** +- [SECURITY.md](../SECURITY.md) — reporting vulnerabilities and best practices +- [Threat Model](threat-model.md) — known threats and mitigations +- [Disaster Recovery](DISASTER_RECOVERY.md) — infrastructure recovery procedures + +--- + +## Severity Levels + +| Level | Definition | SLA (fix deployed) | +|---|---|---| +| **P0 — Critical** | Active exploit, funds at risk, total contract compromise | 4 hours | +| **P1 — High** | Exploitable vulnerability, no confirmed active exploit | 24 hours | +| **P2 — Medium** | Vulnerability requires specific preconditions to exploit | 7 days | +| **P3 — Low** | Hardening issue, defence-in-depth gap, no direct exploit path | 30 days | + +--- + +## Contacts + +| Role | Contact | Channel | +|---|---|---| +| Security team lead | security@propchain.io | Email + Discord `#security-private` | +| On-call engineer | Rotated weekly — see internal runbook | PagerDuty | +| Legal counsel | legal@propchain.io | Email only | +| Communications lead | comms@propchain.io | Email + Slack | +| External auditor (retained) | Engagement letter on file | Email | + +--- + +## Phase 1 — Detection + +### Sources + +Incidents may be detected via: + +- **Automated monitoring**: on-chain event alerts (unusual transfer volumes, pause events, upgrade events) +- **CI / security pipeline**: failed `cargo audit`, `trivy`, or `security-audit` runs +- **Responsible disclosure**: email to security@propchain.io +- **Community report**: Discord, GitHub, or social media + +### Initial Triage (≤ 1 hour) + +1. Open a **private** GitHub Security Advisory draft (do not use a public issue). +2. Assign a severity level using the table above. +3. Page the on-call engineer if severity is P0 or P1. +4. Create a private incident channel in Discord (`incident-YYYY-MM-DD`). +5. Record initial findings in the advisory draft: + - Affected contracts and message(s) + - Reproduction steps + - Estimated impact (funds at risk, accounts affected) + +--- + +## Phase 2 — Containment + +### Pause Affected Contracts + +All PropChain contracts implement a pause mechanism controlled by the security multisig: + +```bash +# Pause a single contract (requires M-of-N multisig signatures) +./scripts/deploy.sh --action pause --contract --network +``` + +Pause as soon as a P0 or P1 is confirmed. Do not wait for a full root-cause analysis. + +### Isolate the Bridge + +If the `bridge` contract is involved, trigger the emergency halt: + +```bash +./scripts/deploy.sh --action bridge-halt --network +``` + +This stops all inbound and outbound cross-chain transfers. + +### Freeze Governance + +If governance is compromised or a malicious proposal is near execution: + +```bash +./scripts/deploy.sh --action governance-freeze --network +``` + +The timelock guardian (multisig) can veto any pending proposal. + +--- + +## Phase 3 — Assessment + +Within **2 hours** of detection for P0/P1: + +1. **Scope**: which contracts are affected? Which storage slots or balances were changed? +2. **Impact**: what is the maximum exploitable value? How many user accounts are affected? +3. **Vector**: what is the exact call sequence to reproduce the issue? +4. **Propagation**: can the exploit spread to other contracts via cross-contract calls? + +Document all findings in the private GitHub Security Advisory. + +--- + +## Phase 4 — Fix + +1. Create a **private fork** or branch from the affected release tag. Do not push the fix branch to the public remote until the embargo lifts. +2. Develop the minimal fix: + - Prefer the smallest possible change. + - Add a regression test that reproduces the exact exploit vector. +3. Internal review: at least **two maintainers** must review the fix on the private branch. +4. If P0 or P1: request an expedited review from the retained external auditor. +5. Run the full test suite and security pipeline on the fix branch: + ```bash + cargo test + cargo clippy -- -D warnings + cargo audit + ./target/release/security-audit audit --report report.json + ``` +6. Prepare upgrade payload using the proxy upgrade mechanism. + +--- + +## Phase 5 — Disclosure + +Before deploying the fix publicly: + +1. Notify known integrators (SDK users, frontends, exchanges) via the private channel at least **24 hours before** the fix is deployed (for P2/P3) or **simultaneously** with deployment (for P0/P1 where delay risks further harm). +2. Prepare a public security advisory that includes: + - CVE / advisory ID + - Affected versions + - Fixed versions + - Severity and CVSS score + - Description (without exploit code) + - Credit to reporter (if consented) +3. Legal counsel reviews the advisory before publication. + +--- + +## Phase 6 — Deployment + +### Upgrade Procedure + +1. Propose the upgrade via the proxy contract (requires multisig initiation): + ```bash + ./scripts/upgrade.sh --contract --code --network + ``` +2. Collect M-of-N multisig signatures (minimum 3-of-5 for production). +3. After the timelock expires (72 hours in normal operation; can be bypassed as 24-hour emergency by security multisig for P0), execute the upgrade. +4. Verify the upgrade on-chain: + ```bash + ./scripts/health-check.sh --network + ``` +5. Unpause affected contracts: + ```bash + ./scripts/deploy.sh --action unpause --contract --network + ``` + +### Rollback + +If the upgrade introduces a regression: + +1. Re-propose the previous known-good code hash via the proxy. +2. Apply the same multisig + timelock flow. +3. There is no instant rollback — plan upgrades carefully. + +--- + +## Phase 7 — Post-Mortem + +A post-mortem document must be published **within 30 days** of incident resolution for any P0 or P1. + +### Post-Mortem Template + +```markdown +## Incident Post-Mortem — + +**Date**: YYYY-MM-DD +**Severity**: P0 / P1 / P2 / P3 +**Duration**: X hours from detection to fix deployment +**Affected contracts**: ... +**Reporter credit**: ... + +### Timeline +| Time (UTC) | Event | +|---|---| +| HH:MM | Detected via ... | +| HH:MM | On-call paged | +| ... | ... | + +### Root Cause +... + +### Impact +- Funds at risk: $X (actual loss: $Y) +- Affected accounts: N +- Downtime: X minutes (contracts paused) + +### Fix Summary +... + +### What Went Well +... + +### What Went Wrong +... + +### Action Items +| Item | Owner | Due | +|---|---|---| +| ... | @handle | YYYY-MM-DD | +``` + +Post-mortems are published to `docs/adr/` with status `Incident Post-Mortem`. + +--- + +## Runbook Review + +This runbook is reviewed: +- After every P0 or P1 incident +- Quarterly by the security team +- Whenever contacts or escalation paths change diff --git a/docs/security_pipeline.md b/docs/security_pipeline.md index 607404c60..196d089d7 100644 --- a/docs/security_pipeline.md +++ b/docs/security_pipeline.md @@ -1,57 +1,101 @@ # Automated Security Audit Pipeline -This project includes a comprehensive automated security pipeline that runs on every commit and pull request. +> **Documentation Version**: 2.0.0 — Updated March 2026 + +This project includes a comprehensive automated security pipeline that runs on every commit and pull request. It is the first line of defence between a code change and a production deployment. + +**Related documents:** +- [SECURITY.md](../SECURITY.md) — policy, best practices, and vulnerability reporting +- [Threat Model](threat-model.md) — what the pipeline is defending against +- [Incident Response](incident-response.md) — what to do when the pipeline catches something ## Components ### 1. Static Analysis -- **Clippy**: Rust's standard linter with strict security settings. -- **Custom Security Tool**: A custom Rust tool (`security-audit`) that scans for: +- **Clippy**: Rust's standard linter with strict security settings (`-D warnings`). +- **Custom Security Tool** (`security-audit`): A custom Rust binary that scans for: - `unsafe` blocks - `TODO`/`FIXME` comments - - Code complexity metrics -- **Trivy**: Scans filesystem and dependencies for known vulnerabilities. + - Cyclomatic complexity violations + - Unbounded `Vec` usage in contract code +- **Trivy**: Scans filesystem and dependencies for known CVEs. ### 2. Dependency Scanning -- **cargo-audit**: Checks `Cargo.lock` for crates with security vulnerabilities reported to the RustSec Advisory Database. +- **cargo-audit**: Checks `Cargo.lock` against the RustSec Advisory Database. +- **cargo-deny**: Enforces license allowlist, bans duplicate dependency versions, and restricts unknown crate registries (see `deny.toml`). ### 3. Formal Verification -- **Kani Rust Verifier**: We use Kani to formally verify critical properties of the smart contracts. +- **Kani Rust Verifier**: Used to formally verify critical safety properties of smart contracts. - **Proof Harnesses**: Located in `contracts/lib/src/lib.rs` under `mod verification`. +- Properties verified include: no arithmetic overflow in balance operations, no unreachable panic paths in critical messages. -## Running Locally +### 4. Secret Detection +- **detect-secrets**: Pre-commit hook that scans every commit for accidental secret leakage (API keys, mnemonics, private keys). Configured via `.secrets.baseline`. -To run the security audit locally: +### 5. Fuzzing +- **proptest**: Property-based tests exercise arithmetic and input-validation code with randomised inputs to catch edge cases not covered by unit tests. + +## Running Locally ```bash -# Build the audit tool +# Build and run the custom audit tool cargo build --release --bin security-audit - -# Run the audit ./target/release/security-audit audit --report report.json -``` -To run formal verification: +# Dependency audit +cargo audit +cargo deny check -```bash -# Install Kani +# Static analysis +cargo clippy -- -D warnings + +# Formal verification cargo install --locked kani-verifier cargo kani setup - -# Run proofs cargo kani + +# Full pre-commit suite (includes secret detection, fmt, clippy) +pre-commit run --all-files ``` ## CI/CD Integration -The pipeline is defined in `.github/workflows/security.yml`. It runs: -1. **Automated Security Pipeline**: Runs the custom audit tool and generates a JSON report. -2. **Formal Verification**: Runs Kani proofs. -3. **Dependency Check**: Runs Trivy. +The pipeline is defined in `.github/workflows/security.yml` and runs on every push and pull request to `main` and `develop`. + +Steps in order: + +1. **Format check** — `cargo fmt --check` +2. **Clippy** — `cargo clippy -- -D warnings` +3. **Tests** — `cargo test` +4. **Audit tool** — custom security scanner, generates `report.json` +5. **cargo-audit** — RustSec CVE check +6. **cargo-deny** — license and dependency policy +7. **Trivy** — filesystem CVE scan +8. **Kani** — formal verification proofs +9. **Secret scan** — `detect-secrets audit` + +All steps must pass before a PR can be merged. ## Security Score -The audit tool calculates a security score (0-100) based on: -- Clippy errors/warnings (-10/-2 points) -- Unsafe blocks (-5 points) -- Known vulnerabilities (-20 points) +The `security-audit` tool calculates a score (0–100): + +| Deduction | Condition | +|---|---| +| –10 points | Each clippy error | +| –2 points | Each clippy warning | +| –5 points | Each `unsafe` block in contract code | +| –20 points | Each known CVE in dependencies | +| –3 points | Each `TODO`/`FIXME` in contract code | + +**Minimum acceptable score**: 90 on any release branch. + +The score is written to `report.json` at the root and archived as a CI artifact. + +## Adding New Security Checks + +1. Add the tool to `security-audit/src/` or as a new CI step in `.github/workflows/security.yml`. +2. Update the score deduction table above. +3. Update `deny.toml` if a new dependency is introduced. +4. Document the tool in the Components section above. + diff --git a/docs/threat-model.md b/docs/threat-model.md new file mode 100644 index 000000000..34c48db89 --- /dev/null +++ b/docs/threat-model.md @@ -0,0 +1,186 @@ +# Threat Model — PropChain Smart Contracts + +> **Documentation Version**: 1.0.0 — Created March 2026 + +This document describes the threat actors, attack surfaces, and mitigations for the PropChain on-chain system. It is reviewed and updated with every major release. + +**Related documents:** +- [SECURITY.md](../SECURITY.md) — policy, reporting, and best practices +- [Incident Response](incident-response.md) — response runbook +- [Security Pipeline](security_pipeline.md) — automated toolchain + +--- + +## System Overview + +PropChain is a Substrate/ink! smart contract system for tokenized real estate. The on-chain components are: + +| Contract | Role | +|---|---| +| `property-token` | ERC-721/PSP34 property NFT | +| `property-management` | Lifecycle management for registered properties | +| `escrow` | Atomic sale / settlement engine | +| `fractional` | Fractional ownership shares | +| `compliance_registry` | KYC/AML status registry | +| `oracle` | Price and property data feeds | +| `governance` | DAO governance and voting | +| `bridge` | Cross-chain asset transfer | +| `staking` | PROP token staking | +| `ai-valuation` | On-chain AI valuation oracle | +| `fees` | Dynamic fee calculation | +| `insurance` | Property insurance pool | +| `zk-compliance` | Zero-knowledge compliance proofs | +| `proxy` | Upgradeable proxy (admin controlled) | + +**Trust boundary**: Everything outside the WASM sandbox (RPC nodes, off-chain oracles, IPFS, frontend) is untrusted. + +--- + +## Threat Actors + +| Actor | Motivation | Capability | +|---|---|---| +| External attacker | Financial gain, disruption | Can submit arbitrary transactions, observe all on-chain state | +| Malicious token holder | Drain funds, manipulate governance | Holds PROP tokens; can vote and call any public message | +| Compromised oracle | Feed false property data | Controls one or more oracle accounts | +| Insider / compromised admin | Rug pull, unauthorized upgrade | Holds admin / owner keys | +| Dependency supply chain | Backdoor via malicious crate | Can introduce vulnerable Rust code via `Cargo.lock` updates | +| Miner / validator | MEV, front-running | Can reorder or delay transactions | + +--- + +## Attack Surface + +### 1. Public Contract Messages + +Every `#[ink(message)]` is callable by any account. Risk: unauthenticated state mutation. + +**Controls:** +- All state-mutating messages check caller authorization before any state change. +- Role-based checks use `contracts/lib/` helpers (`only_owner`, `only_role`). +- Compliance check (`compliance_registry.require_compliance`) on all high-value messages. + +### 2. Cross-Contract Calls + +Contract A calls Contract B, which can re-enter Contract A (reentrancy), or B can be replaced with a malicious contract. + +**Controls:** +- Checks-Effects-Interactions (CEI) pattern: mutate storage before any cross-contract call. +- Hard-coded contract address allowlist for privileged callee contracts. +- Explicit gas limit on all `CallBuilder` invocations. + +### 3. Oracle Data Integrity + +The `oracle` and `ai-valuation` contracts ingest off-chain data. A malicious or compromised oracle feed can manipulate property valuations and escrow settlement prices. + +**Controls:** +- Median aggregation across at least 3 independent oracles. +- Staleness check: data older than `MAX_ORACLE_AGE` blocks is rejected. +- Price deviation guard: reject updates that deviate more than `MAX_PRICE_DELTA`% from the last accepted value. +- Oracle operator keys are multisig controlled. + +### 4. Governance Attacks + +Flash-loan or token acquisition attacks can temporarily acquire enough voting power to pass malicious proposals. + +**Controls:** +- Voting power snapshot at proposal creation block (no flash-loan attack vector). +- Quorum requirement: at least 10% of circulating supply must vote. +- Timelock: proposals must wait `GOVERNANCE_TIMELOCK` blocks between passing and execution. +- Veto power held by security multisig for the first 12 months. + +### 5. Proxy / Upgrade Mechanism + +The `proxy` contract enables code upgrades. A malicious or unauthorized upgrade can replace all contract logic. + +**Controls:** +- Upgrade requires M-of-N multisig approval (currently 3-of-5). +- 72-hour timelock between upgrade proposal and execution. +- Upgrade events are emitted on-chain and monitored by automated alerts. +- Storage layout compatibility check in CI before any upgrade. + +### 6. Bridge and Cross-Chain Transfers + +The bridge contract locks assets on one chain and mints counterparts on another. A bug here can cause double-spend or permanent fund lock. + +**Controls:** +- Nonce-based replay protection on all bridge messages. +- Cryptographic proof verification (Merkle proof from source chain). +- Daily transfer cap per source account. +- Emergency pause controlled by multisig. + +### 7. Integer Arithmetic + +Overflow or underflow in balance calculations can lead to unbounded minting or draining of funds. + +**Controls:** +- All arithmetic on user-supplied values uses `checked_*` or `saturating_*`. +- CI clippy rule `integer_arithmetic` warns on unchecked ops. +- Fuzz tests (via `proptest`) exercise arithmetic edge cases. + +### 8. Access Control Bypass + +Incorrect implementation of ownership / role checks can allow unauthorized callers to execute privileged messages. + +**Controls:** +- Shared `only_owner` / `only_role` macros from `contracts/lib/` used uniformly. +- Integration tests assert that every privileged message reverts when called by a non-authorized account. +- Clippy custom lint flags functions named `admin_*` or `owner_*` that lack the guard macro. + +### 9. Denial of Service + +An attacker can grief the contract by filling storage or forcing expensive iterations. + +**Controls:** +- Per-account storage deposit requirement (ink! storage rent). +- Bounded `Mapping` reads; no unbounded `Vec` iteration in O(n) messages. +- Gas limit enforced on all cross-contract calls. + +### 10. Dependency Supply Chain + +A compromised crate in `Cargo.lock` can introduce backdoors. + +**Controls:** +- `cargo deny` allowlist of permitted licenses and registries. +- `cargo audit` against RustSec advisory database in every CI run. +- Dependency PRs require a maintainer to review `Cargo.lock` diff. + +--- + +## Risk Matrix + +| Threat | Likelihood | Impact | Residual Risk | +|---|---|---|---| +| Reentrancy | Low (CEI enforced) | Critical | Low | +| Malicious oracle feed | Medium | High | Medium | +| Governance flash-loan attack | Low (snapshot voting) | High | Low | +| Unauthorized upgrade | Low (multisig + timelock) | Critical | Low | +| Integer overflow | Low (checked math) | High | Low | +| Access control bypass | Low (shared guards) | High | Low | +| Bridge double-spend | Low (nonce + proof) | Critical | Low | +| Supply-chain attack | Medium | High | Medium | +| DoS / storage griefing | Medium | Medium | Low | + +--- + +## Out-of-Scope Threats + +The following are explicitly not mitigated at the contract layer: + +- **Substrate / Polkadot consensus attacks** — handled by the validator set. +- **Frontend XSS / CSRF** — handled by frontend security practices. +- **IPFS content availability** — IPFS is used only for metadata; contracts store CIDs, not content. +- **Private key compromise of individual non-admin users** — users are responsible for their own key management. + +--- + +## Threat Model Review Cycle + +This document is reviewed: + +- Before every major release. +- After any security audit finding of High severity or above. +- After any incident. +- At minimum, every 6 months. + +Reviewer signs off by merging a PR that bumps the documentation version header. diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 7ecceddcd..f115b2489 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -3,6 +3,6 @@ [toolchain] channel = "stable" -components = ["rustfmt", "clippy"] +components = ["rustfmt", "clippy", "rust-src"] targets = ["wasm32-unknown-unknown"] profile = "default" diff --git a/rustfmt.toml b/rustfmt.toml index 236c3ce87..1de68726a 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,5 @@ -# Rust formatting configuration +# Rust formatting configuration for PropChain Smart Contracts +# Reviewed: March 2026 — see docs/code-style-guide.md for rationale. max_width = 100 hard_tabs = false tab_spaces = 4 diff --git a/scripts/setup-pre-commit.sh b/scripts/setup-pre-commit.sh index 1234a5f0e..810d90515 100755 --- a/scripts/setup-pre-commit.sh +++ b/scripts/setup-pre-commit.sh @@ -93,7 +93,19 @@ install_dependencies() { pip3 install mdformat || pip install mdformat pip3 install mdformat-gfm mdformat-tables || pip install mdformat-gfm mdformat-tables fi - + + # Install cargo-audit (dependency CVE scanner) + if ! command_exists cargo-audit; then + log_info "Installing cargo-audit..." + cargo install cargo-audit --locked + fi + + # Install cargo-deny (license and dependency policy) + if ! command_exists cargo-deny; then + log_info "Installing cargo-deny..." + cargo install cargo-deny --locked + fi + log_success "Dependencies installed" }