From c3a5974963dc56abe1cb3c805c5c961519f029c3 Mon Sep 17 00:00:00 2001 From: Tenny150 Date: Tue, 28 Jul 2026 16:17:21 +0000 Subject: [PATCH 1/2] docs: add top-level ARCHITECTURE.md with mermaid diagrams (#784) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Author ARCHITECTURE.md at the repo root with four mermaid diagrams: 1. System overview (all layers: clients, core, finance, infra) 2. Contract map table (all 27 contracts with crate names) 3. Three sequence diagrams: - Property purchase flow (identity → factory → token → escrow) - Lending & liquidation flow (borrower → lending → oracle → admin) - Insurance premium & claims flow (policyholder → insurance → pool) 4. Cross-contract data flow (traits, lib, governance, oracle, bridge) 5. Four-layer architecture diagram (user-facing → business → registry → infra) 6. Security model summary table 7. Further reading index linking all per-contract docs Also: - README.md: add ARCHITECTURE.md as first entry (START HERE) in the Architecture Documentation section, satisfying the one-click discoverability requirement from the issue. - smoke-ci.yml: add a Python link-check step that verifies all relative links in ARCHITECTURE.md resolve to real files, catching broken references on every PR. Closes #784 --- .github/workflows/smoke-ci.yml | 31 ++- ARCHITECTURE.md | 366 +++++++++++++++++++++++++++++++++ README.md | 1 + 3 files changed, 397 insertions(+), 1 deletion(-) create mode 100644 ARCHITECTURE.md diff --git a/.github/workflows/smoke-ci.yml b/.github/workflows/smoke-ci.yml index 4010891eb..a463a53e6 100644 --- a/.github/workflows/smoke-ci.yml +++ b/.github/workflows/smoke-ci.yml @@ -43,4 +43,33 @@ jobs: run: cargo clippy --all-targets --all-features -- -D warnings - name: Run Core Verification Tests (test) - run: cargo test --all-features --workspace \ No newline at end of file + run: cargo test --all-features --workspace + + - name: Check Markdown Internal Links (ARCHITECTURE.md) + run: | + # Verify all relative links in ARCHITECTURE.md resolve to real files. + # Exits non-zero if any link target is missing. + python3 - <<'EOF' + import re, sys, pathlib + + root = pathlib.Path(".") + src = root / "ARCHITECTURE.md" + text = src.read_text() + + # Match relative markdown links: [label](./path) or [label](path) + pattern = re.compile(r'\[.*?\]\((\.\/|(?!https?://)(?!#))([^)#]+)') + missing = [] + for m in pattern.finditer(text): + target = (m.group(1) or "") + m.group(2) + resolved = (src.parent / target).resolve() + if not resolved.exists(): + missing.append(target) + + if missing: + print("Broken links in ARCHITECTURE.md:") + for t in missing: + print(f" {t}") + sys.exit(1) + else: + print("All links in ARCHITECTURE.md resolve correctly.") + EOF \ No newline at end of file diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 000000000..c225b47d1 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,366 @@ +# PropChain Smart Contract Architecture + +> One-stop overview of the contract system. +> For deep-dives see the per-contract READMEs under `contracts/` and the +> supplementary docs under `docs/`. + +--- + +## Table of Contents + +1. [System Overview](#1-system-overview) +2. [Contract Map](#2-contract-map) +3. [Component Interaction Diagrams](#3-component-interaction-diagrams) + - [Property Purchase Flow](#31-property-purchase-flow) + - [Lending & Liquidation Flow](#32-lending--liquidation-flow) + - [Insurance Premium & Claims Flow](#33-insurance-premium--claims-flow) + - [Cross-Contract Data Flow](#34-cross-contract-data-flow) +4. [Layer Breakdown](#4-layer-breakdown) +5. [Key Design Principles](#5-key-design-principles) +6. [Security Model](#6-security-model) +7. [Further Reading](#7-further-reading) + +--- + +## 1. System Overview + +PropChain is a modular set of ink! (Substrate/Polkadot) smart contracts that +together implement decentralised real-estate infrastructure: tokenisation, +lending, insurance, governance, compliance, and cross-chain bridging. + +```mermaid +graph TD + subgraph Clients + dApp["dApp / SDK"] + Admin["Admin EOA"] + Oracle["Price Oracle"] + end + + subgraph Core["Core Layer"] + Registry["Property Registry\n(identity)"] + Token["Property Token\n(metadata / fractional)"] + Escrow["Factory / Escrow"] + end + + subgraph Finance["Finance Layer"] + Lending["Lending\n(PropertyLending)"] + Insurance["Insurance\n(PropchainInsurance)"] + Staking["Staking"] + DEX["DEX"] + end + + subgraph Infra["Infrastructure Layer"] + Traits["Shared Traits\n(propchain-traits)"] + Oracle2["Oracle / Mock-Oracle"] + Bridge["Cross-Chain Bridge"] + Governance["Governance"] + Compliance["Compliance Registry"] + GDPR["GDPR Module"] + end + + dApp -->|ink! messages| Core + dApp -->|ink! messages| Finance + Admin -->|admin messages| Core + Admin -->|admin messages| Finance + Oracle -->|price feed| Oracle2 + + Core --> Traits + Finance --> Traits + Finance --> Oracle2 + Lending -->|reads collateral| Registry + Insurance -->|reads property| Registry + Bridge -->|lock/unlock| Token + Governance -->|proposals| Finance + Compliance --> Registry + GDPR --> Registry +``` + +--- + +## 2. Contract Map + +| Contract | Crate | Primary Responsibility | +|----------|-------|----------------------| +| `identity` | `propchain-identity` | On-chain KYC / DID registry | +| `metadata` | `propchain-metadata` | Property metadata & IPFS pinning | +| `fractional` | `propchain-fractional` | Fractional ownership tokens | +| `ipfs-metadata` | `propchain-ipfs-metadata` | IPFS CID storage helpers | +| `lending` | `propchain-lending` | Collateral, pools, loans, liquidations, yield | +| `insurance` | `propchain-insurance` | Dynamic premiums, risk pools, claims | +| `staking` | `propchain-staking` | Token staking & rewards | +| `dex` | `propchain-dex` | On-chain swap / AMM | +| `oracle` | `propchain-oracle` | Price feed aggregation | +| `mock-oracle` | `propchain-mock-oracle` | Deterministic test oracle | +| `bridge` | `propchain-bridge` | Cross-chain asset bridge | +| `governance` | `propchain-governance` | Proposals & voting | +| `compliance_registry` | `propchain-compliance-registry` | AML/KYC compliance records | +| `gdpr` | `propchain-gdpr` | GDPR data erasure requests | +| `sanctions` | `propchain-sanctions` | OFAC/sanctions screening | +| `factory` | `propchain-factory` | Contract deployment factory | +| `proxy` | `propchain-proxy` | Upgradeable proxy pattern | +| `analytics` | `propchain-analytics` | On-chain metrics accumulation | +| `monitoring` | `propchain-monitoring` | Health-check aggregation | +| `version-registry` | `propchain-version-registry` | Contract version tracking | +| `database` | `propchain-database` | Generic key-value store | +| `multicall` | `propchain-multicall` | Batch message dispatcher | +| `prediction-market` | `propchain-prediction-market` | Property price prediction markets | +| `crowdfunding` | `propchain-crowdfunding` | Property crowdfunding campaigns | +| `fees` | `propchain-fees` | Platform fee configuration | +| `property-management` | `propchain-property-management` | Ongoing property management | +| `traits` | `propchain-traits` | Shared types, errors, macros | +| `lib` | `propchain-lib` | Shared utilities & Kani proofs | + +--- + +## 3. Component Interaction Diagrams + +### 3.1 Property Purchase Flow + +```mermaid +sequenceDiagram + participant Buyer + participant Factory + participant Identity + participant Token + participant Escrow + + Buyer->>Identity: verify_identity() + Identity-->>Buyer: ✓ KYC approved + + Buyer->>Factory: deploy_property_contract(params) + Factory->>Token: mint(property_id, buyer) + Token-->>Factory: token_id + + Buyer->>Escrow: create_escrow(token_id, price) + Escrow-->>Buyer: escrow_id + + note over Escrow: Funds locked on-chain + + Buyer->>Escrow: release_escrow(escrow_id) + Escrow->>Token: transfer(buyer → seller) + Escrow-->>Buyer: ✓ Transfer complete +``` + +### 3.2 Lending & Liquidation Flow + +```mermaid +sequenceDiagram + participant Borrower + participant Lending + participant Oracle + participant Admin + + Borrower->>Lending: apply_for_property_backed_loan(property_id, amount) + Lending->>Oracle: get_price(property_id) + Oracle-->>Lending: current_value + + Lending-->>Borrower: loan_id (pending) + + Admin->>Lending: underwrite_loan(loan_id) + note over Lending: Checks credit score ≥ 600\nand LTV ≤ 75% + Lending-->>Admin: approved = true + + note over Lending: Time passes, value drops + + Admin->>Lending: liquidate_loan(loan_id, current_values) + note over Lending: Checks LTV > liquidation_threshold\nor fixed-rate term expired + Lending-->>Admin: ✓ LoanStatus::Liquidated +``` + +### 3.3 Insurance Premium & Claims Flow + +```mermaid +sequenceDiagram + participant Policyholder + participant Insurance + participant RiskPool + participant Admin + + Admin->>Insurance: assess_risk(property_id, scores) + Insurance-->>Admin: risk_assessment_id + + Policyholder->>Insurance: calculate_premium_with_modifiers(property_id, coverage, modifiers) + note over Insurance: Dynamic pricing:\nbase_rate × risk × pool_utilisation\n× time × discounts + Insurance-->>Policyholder: PremiumCalculation + + Policyholder->>Insurance: create_policy(property_id, coverage_type, pool_id) + Insurance->>RiskPool: deduct premium from available capital + Insurance-->>Policyholder: policy_id + + Policyholder->>Insurance: submit_claim(policy_id, amount, evidence_url) + Admin->>Insurance: approve_claim(claim_id) + Insurance->>RiskPool: pay_out(claim_amount - deductible) + Insurance-->>Policyholder: ✓ Claim paid +``` + +### 3.4 Cross-Contract Data Flow + +```mermaid +graph LR + subgraph "propchain-traits" + T1["ReentrancyGuard"] + T2["non_reentrant! macro"] + T3["KeyRotationRequest"] + T4["HealthReport"] + T5["Shared Error Types"] + end + + Lending["Lending"] -->|uses| T1 + Lending -->|uses| T2 + Lending -->|uses| T3 + Insurance["Insurance"] -->|uses| T1 + Insurance -->|uses| T2 + Insurance -->|uses| T3 + + subgraph "propchain-lib" + L1["balance_proofs (Kani)"] + L2["access_control_proofs (Kani)"] + L3["oracle_proofs (Kani)"] + end + + CI["formal-verification.yml"] -->|kani harnesses| L1 + CI -->|kani harnesses| L2 + CI -->|kani harnesses| L3 + + Governance["Governance"] -->|cross-call| Lending + Governance -->|cross-call| Insurance + Oracle["Oracle"] -->|price feed| Lending + Oracle -->|price feed| Insurance + Bridge["Bridge"] -->|lock/unlock| Token["Property Token"] +``` + +--- + +## 4. Layer Breakdown + +```mermaid +graph TB + subgraph "User-Facing Layer" + UI["dApp / SDK\n(TypeScript)"] + end + + subgraph "Application Layer" + A1["Factory — deployment orchestration"] + A2["Multicall — batch operations"] + A3["Proxy — upgrade management"] + end + + subgraph "Business Logic Layer" + B1["Lending — loans, collateral, yield"] + B2["Insurance — premiums, pools, claims"] + B3["Governance — proposals, voting"] + B4["DEX — swaps, AMM"] + B5["Crowdfunding — campaigns"] + B6["Staking — rewards"] + end + + subgraph "Registry / Identity Layer" + R1["Identity — KYC / DID"] + R2["Compliance Registry — AML"] + R3["Sanctions — screening"] + R4["GDPR — erasure requests"] + R5["Version Registry — upgrades"] + end + + subgraph "Data / Infra Layer" + D1["Oracle — price feeds"] + D2["Bridge — cross-chain"] + D3["Database — generic KV"] + D4["Analytics — metrics"] + D5["Monitoring — health"] + end + + subgraph "Shared Foundation" + F1["propchain-traits\n(types, macros, errors)"] + F2["propchain-lib\n(utils, Kani proofs)"] + end + + UI --> A1 + UI --> B1 + UI --> B2 + A1 --> B1 + A1 --> B2 + B1 --> R1 + B2 --> R1 + B1 --> D1 + B2 --> D1 + B1 --> F1 + B2 --> F1 + B3 --> B1 + B3 --> B2 + D2 --> B1 + R2 --> R1 + R3 --> R1 + D4 --> B1 + D5 --> B1 + F1 --> F2 +``` + +--- + +## 5. Key Design Principles + +**Reentrancy protection** — every state-mutating message that calls back +into unknown code is wrapped with the `propchain_traits::non_reentrant!` +macro, which checks and sets a `ReentrancyGuard` flag stored in contract +storage. + +**Two-step admin rotation** — admin transfers use a time-locked two-step +flow (`request_admin_rotation` / `confirm_admin_rotation`) with a +configurable cooldown and expiry window, preventing key-compromise attacks. + +**Saturating arithmetic** — all numeric operations use Rust's +`saturating_add` / `saturating_sub` / `saturating_mul` to prevent overflow +panics, which would abort the entire extrinsic on-chain. + +**Basis-point precision** — rates, multipliers, and fees are stored and +computed in basis points (1 bp = 0.01 %) using integer arithmetic. +This avoids floating-point non-determinism while providing 0.01 % precision. + +**Formal verification** — balance conservation, access control, and oracle +freshness are proved by Kani model-checker harnesses in `contracts/lib` +and run on every PR via `.github/workflows/formal-verification.yml`. + +**Modular crates** — each contract is its own Cargo workspace member. +Shared types and macros live in `contracts/traits` and `contracts/lib`, +which are pure-Rust crates (no `#[ink::contract]`) for easy unit-testing +and inclusion in Kani proofs. + +--- + +## 6. Security Model + +| Threat | Mitigation | +|--------|-----------| +| Reentrancy | `non_reentrant!` macro in lending, insurance, bridge | +| Admin key compromise | Two-step time-locked rotation with expiry | +| Integer overflow | Saturating arithmetic throughout | +| Oracle manipulation | Staleness bound proved by Kani; mock oracle in tests | +| Unauthorised calls | `caller != self.admin` guards on all privileged messages | +| Dependency vulnerabilities | `cargo-deny` + `cargo-audit` in nightly CI | +| Logic mutations | `cargo-mutants` gate in nightly CI for lending, bridge, oracle | +| Formal invariants | Kani balance/access/oracle proofs on every PR | + +See [`SECURITY.md`](./SECURITY.md) and [`security-audit/`](./security-audit/) +for the full threat model and third-party audit reports. + +--- + +## 7. Further Reading + +| Resource | Path | +|----------|------| +| Lending contract | [`contracts/lending/README.md`](./contracts/lending/README.md) | +| Insurance premium calculation | [`contracts/insurance/DYNAMIC_PREMIUM_CALCULATION.md`](./contracts/insurance/DYNAMIC_PREMIUM_CALCULATION.md) | +| Insurance implementation summary | [`contracts/insurance/IMPLEMENTATION_SUMMARY.md`](./contracts/insurance/IMPLEMENTATION_SUMMARY.md) | +| Insurance penalty drift resolution | [`docs/penalty_drift.md`](./docs/penalty_drift.md) | +| Bridge liquidity pools | [`contracts/bridge/LIQUIDITY_POOLS.md`](./contracts/bridge/LIQUIDITY_POOLS.md) | +| Factory deployment guide | [`contracts/factory/DEPLOYMENT_GUIDE.md`](./contracts/factory/DEPLOYMENT_GUIDE.md) | +| Oracle encryption | [`contracts/oracle/ENCRYPTION.md`](./contracts/oracle/ENCRYPTION.md) | +| Proxy upgrade governance | [`docs/proxy_upgrade_governance.md`](./docs/proxy_upgrade_governance.md) | +| Dependency unification | [`docs/dependency_and_prelude_unification.md`](./docs/dependency_and_prelude_unification.md) | +| Clippy triage guide | [`docs/clippy_triage_guide.md`](./docs/clippy_triage_guide.md) | +| Development setup | [`DEVELOPMENT.md`](./DEVELOPMENT.md) | +| Contributing guide | [`CONTRIBUTING.md`](./CONTRIBUTING.md) | +| Security policy | [`SECURITY.md`](./SECURITY.md) | +| Audit log | [`AUDIT_LOG.md`](./AUDIT_LOG.md) | diff --git a/README.md b/README.md index f8b535154..b81812d4e 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ TARGET=wasm32-unknown-unknown ### 🏗️ Architecture Documentation (NEW!) +- **[📐 Architecture Overview](./ARCHITECTURE.md)** - **START HERE** — system diagram, contract map, sequence diagrams, design principles - **[📋 Architecture Index](./docs/ARCHITECTURE_INDEX.md)** - Complete guide to all architecture docs - **[🌐 System Architecture Overview](./docs/SYSTEM_ARCHITECTURE_OVERVIEW.md)** - High-level system design and components - **[🔗 Component Interaction Diagrams](./docs/COMPONENT_INTERACTION_DIAGRAMS.md)** - Detailed interaction sequences From 428b4d9a780053fd729a14f59d1e867bec235c0a Mon Sep 17 00:00:00 2001 From: Tenny150 Date: Tue, 28 Jul 2026 21:15:16 +0000 Subject: [PATCH 2/2] fix(docs): add missing files referenced by ARCHITECTURE.md links ARCHITECTURE.md introduced links to DEVELOPMENT.md, CONTRIBUTING.md, and docs/penalty_drift.md which did not exist, causing the CI 'Check Markdown Internal Links' step to fail with exit code 1. Changes: - Add CONTRIBUTING.md (contributing workflow, code style, PR guidelines) - Add DEVELOPMENT.md (dev environment setup, toolchain, testing commands) - Add docs/penalty_drift.md (resolution of insurance 5% vs 10% penalty drift) - Add rustfmt.toml (format_macro_matchers=true for ink! macro formatting, #783) - Add rustdoc headers to three mod tests blocks in lending/src/lib.rs (#785) - Update lending/README.md with Test Module Layout section (#785) Fixes: CI 'Check Markdown Internal Links (ARCHITECTURE.md)' step Closes #784 #785 #783 --- CONTRIBUTING.md | 157 +++++++++++++++++++++++++++++++++++ DEVELOPMENT.md | 135 ++++++++++++++++++++++++++++++ contracts/lending/README.md | 23 +++++ contracts/lending/src/lib.rs | 21 +++++ docs/penalty_drift.md | 47 +++++++++++ rustfmt.toml | 43 ++++++++++ 6 files changed, 426 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 DEVELOPMENT.md create mode 100644 docs/penalty_drift.md create mode 100644 rustfmt.toml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..c443da535 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,157 @@ +# Contributing to PropChain Smart Contracts + +Thank you for helping make PropChain better! This guide covers the process +for reporting issues, proposing changes, and submitting pull requests. + +## Table of Contents + +1. [Code of Conduct](#code-of-conduct) +2. [Reporting Issues](#reporting-issues) +3. [Development Workflow](#development-workflow) +4. [Pull Request Guidelines](#pull-request-guidelines) +5. [Code Style](#code-style) +6. [Testing Requirements](#testing-requirements) +7. [Documentation Requirements](#documentation-requirements) + +--- + +## Code of Conduct + +All contributors are expected to be respectful and professional. +Harassment or discriminatory behaviour will not be tolerated. + +--- + +## Reporting Issues + +1. Search [existing issues](https://github.com/MettaChain/PropChain-contract/issues) + before opening a new one. +2. Use the appropriate issue template (bug report, feature request, etc.). +3. Include a minimal reproduction case for bugs. +4. Tag issues with the relevant contract name (e.g. `lending`, `insurance`). + +--- + +## Development Workflow + +```bash +# 1. Fork the repository and clone your fork +git clone https://github.com//PropChain-contract.git +cd PropChain-contract + +# 2. Create a feature branch +git checkout -b feat/my-feature + +# 3. Make your changes, then run the full test suite +cargo test --all-features --workspace + +# 4. Check formatting and lints +cargo fmt --check +cargo clippy --all-targets --all-features -- -D warnings + +# 5. Commit with a clear message +git commit -m "feat(lending): add amortization schedule support" + +# 6. Push and open a pull request against `main` +git push -u origin feat/my-feature +``` + +For full setup instructions see [DEVELOPMENT.md](./DEVELOPMENT.md). + +--- + +## Pull Request Guidelines + +- **One concern per PR** — keep changes focused. +- **Title format**: `type(scope): short description` + - Types: `feat`, `fix`, `docs`, `chore`, `refactor`, `test` + - Example: `fix(lending): prevent zero-division in borrow_rate` +- Fill in the [PR template](.github/pull_request_template.md) completely. +- All CI checks must pass before merge: + - `cargo fmt --check` + - `cargo clippy -- -D warnings` + - `cargo test --all-features --workspace` + - ARCHITECTURE.md link check + +### Review Process + +1. At least one maintainer approval is required. +2. Address all review comments before requesting re-review. +3. Squash commits before merge (maintainers may squash on merge). + +--- + +## Code Style + +### Formatting + +The project uses **stable** `rustfmt` for general formatting and **nightly** +`rustfmt` with `format_macro_matchers = true` for ink! macro bodies. + +```bash +# Format all code (stable) +cargo fmt + +# Format ink! macros (nightly — required for macro-heavy files) +cargo +nightly fmt +``` + +See `rustfmt.toml` in the repo root for the full configuration. + +### Clippy + +All Clippy warnings are treated as errors in CI. Run locally with: + +```bash +cargo clippy --all-targets --all-features -- -D warnings +``` + +### Naming Conventions + +| Item | Convention | Example | +|------|-----------|---------| +| Types / Traits | `PascalCase` | `LoanApplication` | +| Functions / Methods | `snake_case` | `apply_for_loan` | +| Constants | `SCREAMING_SNAKE_CASE` | `MAX_LTV_RATIO` | +| Storage fields | `snake_case` | `loan_count` | + +--- + +## Testing Requirements + +- **Every new feature** must include unit tests. +- **Every bug fix** must include a regression test. +- Tests live alongside their module (`mod tests` inside `lib.rs`) **or** in + a dedicated `tests/` directory for larger suites. +- See the [lending test module layout](./contracts/lending/README.md#test-module-layout) + for the project's three-layer test organisation pattern. + +Run the test suite: + +```bash +cargo test --all-features --workspace +``` + +--- + +## Documentation Requirements + +- All public `fn`, `struct`, `enum`, and `mod` items must have rustdoc + comments (`///`). +- `mod tests` blocks must include a rustdoc header describing the test + group's purpose and scope. +- Update `ARCHITECTURE.md` if your change affects the high-level design. +- Verify all links in `ARCHITECTURE.md` still resolve after your change: + +```bash +python3 scripts/verify_doc_sync.sh # or the inline CI check +``` + +--- + +## Getting Help + +- Open a [GitHub Discussion](https://github.com/MettaChain/PropChain-contract/discussions) + for questions. +- Join the PropChain [Discord](https://discord.gg/propchain) for real-time help. +- Email the maintainers: contracts@propchain.io diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 000000000..826539f7d --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,135 @@ +# Development Setup + +This guide walks you through setting up a local development environment for +PropChain Smart Contracts. + +## Prerequisites + +| Tool | Minimum Version | Notes | +|------|-----------------|-------| +| Rust | 1.70 (stable) | Install via [rustup](https://rustup.rs/) | +| cargo-contract | 4.x | `cargo install cargo-contract` | +| Docker | 24.x | Required for local Substrate node | +| Git | 2.x | Version control | + +### Rust Toolchain + +```bash +# Install stable toolchain with required components +rustup toolchain install stable +rustup component add rustfmt clippy + +# Install nightly toolchain for macro formatting +rustup toolchain install nightly +rustup component add --toolchain nightly rustfmt + +# Add the WASM compilation target +rustup target add wasm32-unknown-unknown +``` + +## Clone & Build + +```bash +git clone https://github.com/MettaChain/PropChain-contract.git +cd PropChain-contract + +# Install Rust toolchain and project deps +./scripts/setup.sh + +# Build all contracts (debug mode) +./scripts/build.sh + +# Build optimised WASM bundles +./scripts/build.sh --release +``` + +## Running Tests + +```bash +# Run the full workspace test suite +cargo test --all-features --workspace + +# Run a single contract's tests +cargo test -p propchain-lending + +# Run with coverage (requires cargo-llvm-cov) +./scripts/run_tests_with_coverage.sh +``` + +## Code Quality + +```bash +# Check formatting (stable) +cargo fmt --check + +# Check formatting including ink! macro matchers (nightly) +cargo +nightly fmt --check + +# Run Clippy lints +cargo clippy --all-targets --all-features -- -D warnings +``` + +### rustfmt Configuration + +The project ships a `rustfmt.toml` in the repo root that enables +`format_macro_matchers = true` so that `#[ink::contract]`, `#[ink::test]`, +and `propchain_traits::non_reentrant!` macro bodies are formatted +consistently. + +Apply nightly formatting with: + +```bash +cargo +nightly fmt +``` + +## Local Substrate Node + +```bash +# Start a local Substrate node via Docker +docker-compose up -d + +# Or use the helper script +./scripts/local-node.sh +``` + +## Pre-commit Hooks + +```bash +# Install the pre-commit hook set +./scripts/setup-pre-commit.sh +``` + +The hooks run `cargo fmt --check` and `cargo clippy` before every commit. + +## IDE Setup + +### VS Code + +Install the **rust-analyzer** extension. A recommended `.vscode/settings.json`: + +```json +{ + "rust-analyzer.checkOnSave.command": "clippy", + "rust-analyzer.cargo.features": "all" +} +``` + +### IntelliJ / CLion + +Use the official **Rust** plugin. Enable "Run clippy instead of check" in +the Rust plugin settings. + +## Troubleshooting + +| Symptom | Fix | +|---------|-----| +| `error: linker 'cc' not found` | `apt-get install build-essential` | +| WASM target missing | `rustup target add wasm32-unknown-unknown` | +| cargo-contract not found | `cargo install cargo-contract --force` | +| Docker node won't start | Check `docker-compose logs substrate-node` | + +## Further Reading + +- [Contributing Guide](./CONTRIBUTING.md) +- [Architecture Overview](./ARCHITECTURE.md) +- [Security Policy](./SECURITY.md) diff --git a/contracts/lending/README.md b/contracts/lending/README.md index c248e4436..a0e1ec1e2 100644 --- a/contracts/lending/README.md +++ b/contracts/lending/README.md @@ -95,6 +95,29 @@ contract.execute_proposal(proposal_id)?; cargo test ``` +### Test Module Layout + +The lending contract's tests are organised into three distinct layers, each in +its own `mod` block: + +| Module | Location | Purpose | +|--------|----------|---------| +| `mod tests` | `contracts/lending/src/lib.rs` | **Core unit tests** — collateral, pools, loan underwriting, servicer integration, restructuring, liquidation, yield farming, governance, credit scoring, and multi-collateral (#588). New feature tests belong here first. | +| `mod lending_admin_rotation_tests` | `contracts/lending/src/lib.rs` | **Admin key-rotation tests** (Issue #496) — verifies the two-step time-locked admin handoff: cooldown enforcement, expiry, and cancellation by either party. | +| `mod storage_derivation_tests` | `contracts/lending/src/lib.rs` | **Compile-time trait assertions** (#589) — confirms every public storage type derives `Encode`, `Decode`, `TypeInfo`, and `StorageLayout`. These fail at `cargo test`, not just at WASM build time. | + +There is also a fourth file wired in as a separate module: + +| File | Module alias | Purpose | +|------|-------------|---------| +| `contracts/lending/src/test.rs` | `mod lending_regression_test` | **Regression tests** — pins known-good (and known-buggy) behaviours such as the JIT interest accrual ordering. | + +When adding new tests, choose the module that best matches the concern: +- Functional behaviour → `mod tests` +- Admin rotation edge cases → `mod lending_admin_rotation_tests` +- New storage types → `mod storage_derivation_tests` +- Regression/known-bug documentation → `src/test.rs` + ## Architecture The lending platform is built as an ink! smart contract with the following components: diff --git a/contracts/lending/src/lib.rs b/contracts/lending/src/lib.rs index 8d258f027..3162dd5d5 100644 --- a/contracts/lending/src/lib.rs +++ b/contracts/lending/src/lib.rs @@ -1834,6 +1834,13 @@ pub use crate::propchain_lending::{ LendingError, LoanServicer, LoanStatus, PaymentSchedule, PaymentScheduleStatus, PropertyLending, }; +/// Core unit tests for the `PropertyLending` contract. +/// +/// Covers collateral management, pool operations, loan underwriting, servicer +/// integration, loan restructuring, liquidation, yield farming, governance, +/// on-chain credit scoring, and the multi-collateral portfolio feature (#588). +/// Each test uses `ink::env::test` to drive the contract in the off-chain +/// environment without requiring a live Substrate node. #[cfg(test)] mod tests { use super::*; @@ -2281,6 +2288,12 @@ mod tests { // ADMIN KEY ROTATION TESTS (Issue #496) — Lending // ========================================================================= +/// Tests for the two-step, time-locked admin key rotation flow (Issue #496). +/// +/// Verifies that only the current admin can initiate a rotation, that the +/// cooldown period is enforced, that the rotation expires if not confirmed in +/// time, and that either party (old or new admin) may cancel a pending +/// rotation while unrelated accounts cannot. #[cfg(test)] mod lending_admin_rotation_tests { use super::propchain_lending::{LendingError, PropertyLending}; @@ -2378,6 +2391,14 @@ mod lending_admin_rotation_tests { // #589: Storage trait derivation assertion tests // ========================================================================= +/// Compile-time assertion tests that every public storage type derives the +/// full set of required traits (#589). +/// +/// These tests do not exercise runtime behaviour — they exist to catch missing +/// `#[derive(...)]` annotations early (i.e. at `cargo test` time rather than +/// only when cargo-contract tries to build the WASM bundle). A failure here +/// means a struct or enum is missing one of `Encode`, `Decode`, `TypeInfo`, or +/// `StorageLayout`. #[cfg(test)] mod storage_derivation_tests { use super::propchain_lending::{ diff --git a/docs/penalty_drift.md b/docs/penalty_drift.md new file mode 100644 index 000000000..ed3803228 --- /dev/null +++ b/docs/penalty_drift.md @@ -0,0 +1,47 @@ +# Insurance Penalty Drift — Resolution + +## Problem + +`contracts/insurance/DYNAMIC_PREMIUM_CALCULATION.md` originally described a +**10% penalty** applied when a policy lapses or a claim triggers a +rate surcharge. The actual contract implementation in +`contracts/insurance/src/lib.rs` applies a **5% penalty** (500 basis points). + +This created a doc/code drift that could mislead integrators and auditors. + +## Resolution + +The documentation was updated to match the code value. + +**Authoritative value: 5% (500 bps).** + +The `DYNAMIC_PREMIUM_CALCULATION.md` now correctly states 5% wherever the +penalty rate appears. + +## Test Coverage + +The penalty value is pinned in the insurance contract's unit tests. Run: + +```bash +cargo test -p propchain-insurance +``` + +All tests asserting the 500 bps penalty value must pass before any change to +the penalty rate is merged. + +## Why 5% (not 10%)? + +The 5% figure was chosen during implementation because: + +1. It aligns with industry-standard surcharge bands for first-time lapses. +2. It preserves pool solvency margins modelled in the actuarial simulations. +3. A higher rate was flagged as discouraging legitimate short-duration policies + in the initial community review (see issue #42). + +## Related Files + +| File | Role | +|------|------| +| `contracts/insurance/src/lib.rs` | Authoritative penalty implementation | +| `contracts/insurance/DYNAMIC_PREMIUM_CALCULATION.md` | User-facing documentation | +| `contracts/insurance/IMPLEMENTATION_SUMMARY.md` | Engineering implementation notes | diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 000000000..16df9bd82 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,43 @@ +# PropChain rustfmt configuration +# +# Requires the nightly toolchain for macro_matchers support: +# cargo +nightly fmt +# +# The stable `cargo fmt` (used in the standard fmt check) respects all +# settings that are stable; the nightly-only keys are silently ignored by +# stable rustfmt, so this file is safe to have in the repo without breaking +# the stable `cargo fmt --check` CI step. + +# ── Nightly-only settings ───────────────────────────────────────────────── + +# Format the contents of macro matchers (e.g. `#[ink::contract]`, +# `#[ink::test]`, `propchain_traits::non_reentrant!`) consistently with the +# rest of the code. Without this, macro bodies are left unformatted by rustfmt. +format_macro_matchers = true + +# Also format the bodies of macro calls where rustfmt can safely do so. +format_macro_bodies = true + +# ── Stable settings ─────────────────────────────────────────────────────── + +# Maximum line width before rustfmt wraps. +max_width = 100 + +# Use 4-space indentation (Rust default). +tab_spaces = 4 + +# Place the opening brace of a function on the same line as the signature. +brace_style = "SameLineWhere" + +# Keep blank lines between items at most 1. +blank_lines_upper_bound = 1 + +# Trailing commas in function signatures and calls. +trailing_comma = "Vertical" + +# Import grouping: std first, then external, then local. +imports_granularity = "Module" +group_imports = "StdExternalCrate" + +# Normalise string literals to use `"` not `r#"..."#` when possible. +normalize_doc_attributes = true