Skip to content

Latest commit

 

History

History
173 lines (131 loc) · 5.69 KB

File metadata and controls

173 lines (131 loc) · 5.69 KB

Contributing to PropFi

Thanks for your interest in contributing to PropFi! We welcome contributions from everyone.

Table of Contents

Code of Conduct

By participating, you agree to maintain a respectful, inclusive, and harassment-free environment for everyone.

Getting Started

  1. Fork the repository.
  2. Clone your fork:
    git clone https://github.com/your-username/propfi.git
  3. Set up the development environment as described in the README.
  4. Create a feature branch:
    git checkout -b feat/my-feature

Development Workflow

main ─── feat/my-feature ──→ PR ──→ merge to main
  • main is the default branch. All PRs merge into main.
  • Feature branches should be short-lived. Open a PR early (mark as draft) for feedback.
  • Keep your branch up to date with main via rebase, not merge.

Coding Standards

Rust (Soroban contracts)

  • Formatting: cargo fmt — all code must be formatted.
  • Linting: cargo clippy -- -D warnings — no warnings allowed.
  • Naming:
    • Contract functions: snake_case.
    • Types and structs: PascalCase.
    • Variables: snake_case.
    • Constants: SCREAMING_SNAKE_CASE.
  • Errors: Use a ContractError enum with #[contracterror] derive.
  • Events: Every state mutation must emit an event via env.events().publish().
  • Cross-contract calls: Always use the Client pattern generated by #[contractclient].
  • Admin gating: Use require_auth() and Address::require_auth() for access control.
  • No unsafe code: unsafe is not permitted unless absolutely necessary and reviewed.
  • No panics: Use Result return types instead of .unwrap() or .expect() in production code (tests are exempt).

TypeScript (SDK / Indexer)

  • Formatting: Use prettier with the project config.
  • Linting: ESLint with the provided config.
  • Naming:
    • Functions and variables: camelCase.
    • Types and interfaces: PascalCase.
    • Constants: UPPER_SNAKE_CASE.
    • Files: kebab-case.ts.
  • Types: Prefer interface over type for object shapes. Use type for unions and aliases.
  • Async: Use async/await consistently. Avoid raw .then().
  • Imports: Group imports: external → internal. Use named exports unless a default export is required by a framework.

General

  • No commented-out code.
  • No debug logging or console.log in production code.
  • Document public APIs with doc comments (/// in Rust, /** */ in TypeScript).
  • Keep functions small and single-purpose.

Testing

All changes must include tests.

Rust unit tests

  • Place tests in a #[cfg(test)] mod tests block at the bottom of the source file.
  • Use Soroban's test harness (SorobanTest or Env::default()).
  • Test both happy paths and error cases.
  • Run tests before pushing:
    cargo test --workspace

TypeScript tests

  • Tests live in __tests__/ directories alongside the source.
  • Use vitest or jest as configured.
  • Run tests before pushing:
    cd sdk && npm test
    cd indexer && npm test

Integration tests

  • Integration tests live in contracts/integration_tests/.
  • Ensure integration tests pass for any cross-contract changes:
    cargo test -p propfi-integration-tests

Pull Request Process

  1. Before opening a PR, ensure:
    • cargo test --workspace passes.
    • cargo clippy -- -D warnings is clean.
    • cargo fmt --check is clean.
    • TypeScript projects build (npm run build).
  2. PR title should follow Conventional Commits.
  3. PR description must include:
    • What this PR does.
    • Why it's needed (link to issue if applicable).
    • How it was tested.
  4. PR size: Keep PRs focused. Split large changes into multiple PRs.
  5. Review: At least one maintainer approval is required before merging.
  6. Merge: Squash-merge into main with a clean commit message.

Commit Conventions

Use Conventional Commits:

<type>(<scope>): <description>

[optional body]

Types: feat, fix, refactor, test, docs, style, chore, ci.

Examples:

feat(property-registry): add valuation update with oracle verification
fix(fraction-vault): prevent overflow in buy_fraction calculation
test(mortgage-pool): add liquidation edge case tests
docs(README): update deployment instructions

Contract Development Guide

Adding a new contract

  1. Create contracts/<name>/Cargo.toml — use an existing contract's Cargo.toml as a template.
  2. Create contracts/<name>/src/lib.rs with a module structure.
  3. Add the contract to the workspace Cargo.toml.
  4. Implement initialize, core functions, events, and tests.
  5. Add integration test coverage in tests/integration/.

Cross-contract dependencies

When your contract calls another PropFi contract:

  1. Import the client: use crate::property_registry::ContractClient as PropertyRegistryClient;
  2. Pass the contract address as a function parameter.
  3. Gate sensitive operations with ComplianceRegistryClient::is_compliant().
  4. Add the dependency to Cargo.toml (path dependency).

Event naming

Events should follow the pattern VerbPastTense:

  • PropertyRegistered, FractionPurchased, YieldDistributed, LoanOpened.

Each event payload must contain the affected address or ID as the first key for easy indexing.