Skip to content

vvylym/kzp-mini

Repository files navigation

KZP Mini

KZP Mini is a Solana implementation of a workplace mutual-aid fund (Kasa Zapomogowa Pracownicza).

Members:

  • join a shared pool
  • deposit savings
  • request loans with two guarantors
  • repay obligations
  • withdraw savings and leave

The protocol enforces financial mechanics on-chain while allowing membership policy and governance to remain off-chain. Built in Rust using Anchor.

Superteam Poland submission - entry for Build everyday real-world systems as on-chain Rust programs on Superteam Earn.

Repository: github.com/vvylym/kzp-mini

At a glance

Property Value
Blockchain Solana (devnet deployed)
Language Rust stable for host builds
Framework Anchor crates 1.1.2
Solana crates solana-client 4.1.0 · solana-program-test 4.1.0 · solana-sdk 4.0.1
Loan model Two guarantors, 3× savings cap
Savings model Shared SPL vault + ledger
Client kzp CLI
License MIT

Why KZP?

Traditional workplace savings associations rely on spreadsheets, manual bookkeeping, paper signatures, and committee decisions. That creates opaque balances, delayed settlement, manual verification, and dispute risk.

KZP Mini replaces administrative coordination with on-chain enforcement.

Concern Traditional handling Friction
Membership HR roster, payroll deductions Manual roster upkeep
Savings Spreadsheet per member Opaque balances
Loans Committee + verbal guarantees Signatures disconnected from money
Default Social pressure, delayed settlement No shared rule engine
Exit Manual “all clear” check Error-prone
Traditional concept On-chain implementation
Pool / cash box Pool + Vault PDAs
Member record Member PDA
Loan Loan PDA (PendingActive → closed on repay/default)
Two guarantors Both must co-sign before disbursement
Default Permissionless settle_default after due date; 50/50 reserved guarantor liability

Deeper domain and mapping: docs/ARCHITECTURE.md.


Key features

Savings

  • One-time entry fee on join
  • Member deposits to shared vault
  • Per-member savings ledger

Lending

  • Loan requests with two nominated guarantors
  • Partial then full co-sign
  • Automatic disbursement when both guarantors approve

Risk controls

  • Loan cap at 3× member savings
  • One unresolved loan per borrower
  • Up to five guarantees per member
  • Exit blocked while borrowing or guaranteeing

Administration

  • Pool initialization and SPL mint binding
  • Permissionless due-date default settlement from reserved guarantor savings liability

Live devnet demo

Program ID: GsjUnBFvYtcxNwCrydPUjQTngGTqdx5v7APnWahnqwkx

The same program ID is preserved across releases. The original bounty submission remains available as release/0.1.0 and v0.1.0. The current hardened revision is release/0.2.0 / v0.2.0.

0.2.0 verified lifecycle

  • Upgrade program in place
  • Initialize pool
  • Join members (admin + two guarantors)
  • Deposit borrower savings and guarantor backing
  • Request loan
  • Co-sign (guarantor A, then B)
  • Disburse principal
  • Repay loan and close terminal loan account
  • Exit pool
Step Transaction
Program upgrade explorer
Initialize pool explorer
Admin join explorer
Guarantor A join explorer
Guarantor B join explorer
Admin deposit savings explorer
Guarantor A deposit savings explorer
Guarantor B deposit savings explorer
Request loan explorer
Co-sign (guarantor A) explorer
Co-sign + disburse (B) explorer
Repay loan explorer
Exit pool explorer

0.2.0 demo accounts: pool 5CFCSvhNdCdGYCAZYcP7taA87vAmKsSLtiHPP8TBWeng · loan 2LRcvkpTdkNQn5gVpJPEfgj4imkj8bTm5JeEHGvHKZPP · mint 8GKf5BwMfFEZmkoGYuH4vNwGy1qgdxpSesq6jGp55J7a

bash scripts/devnet-demo.sh   # full scripted lifecycle

Quick start

Install

Rust stable, Solana CLI 4.x, Anchor CLI 1.1.2, Anchor crates 1.1.2, Solana crates 4.x, cargo-nextest. Full toolchain notes: docs/GETTING_STARTED.md.

Build

git clone https://github.com/vvylym/kzp-mini.git && cd kzp-mini
mkdir -p target/deploy && cp keys/program.json target/deploy/kzp_mini-keypair.json
NO_DNA=1 anchor build --ignore-keys
cargo build -p kzp-cli --release

Keypairs are local-only - see keys/README.md.

Deploy

bash scripts/deploy.sh devnet

Verify

cargo run -p kzp-cli --release -- config

CLI usage

Commands grouped by role. Full reference: docs/CLI.md.

Role Commands
Pool setup / cranks pool initialize · permissionless loan settle-default
Members pool join · pool deposit · pool exit
Borrowers loan request · loan repay · loan cancel
Guarantors loan cosign · loan withdraw-cosign
kzp pool initialize --name "My Pool" --entry-fee 50 --mint <MINT>
kzp pool join --pool <POOL> --entry-fee 50
kzp pool deposit --pool <POOL> --amount 1000000
kzp loan request --pool <POOL> --nonce 1 --amount 500000 \
  --guarantor-a <PUBKEY_A> --guarantor-b <PUBKEY_B>
kzp loan cosign --loan <LOAN>
kzp loan repay --loan <LOAN> --amount 500000
kzp pool exit --pool <POOL>

Global flags: --cluster, --rpc-url, --wallet, --dry-run.


System architecture

                    Pool PDA
                        │
                        ▼
                   Vault PDA
                        │
        ┌───────────────┼───────────────┐
        ▼               ▼               ▼
   Member PDA      Member PDA      Member PDA
        │
        ▼
    Loan PDA
Account Purpose
Pool Admin, mint, counters
Vault SPL token custody
Member Savings, loan/guarantee obligations
Loan Principal, guarantors, status

Instructions (10): initialize_pool · join_pool · deposit_savings · request_loan · co_sign_loan · repay_loan · cancel_loan · withdraw_cosign · settle_default · exit_pool

Details: docs/ARCHITECTURE.md · docs/INSTRUCTIONS.md · docs/STATE.md


Financial model

Two parallel views:

  1. SPL vault - actual token balance
  2. Ledger - pool.total_savings and member.savings_balance

Entry fees fund the vault but not member savings (liquidity buffer). Disburse and exit are fail-closed if vault balance is insufficient.

Full model: docs/ACCOUNTING.md.


Loan lifecycle

Pending → Active → full repay (loan account closed)
                 ↘ due default (loan account closed)
Pending → cancel_loan
State Guarantor tracking Escape hatches
Pending pending_guarantee_count Borrower: cancel_loan · Guarantor: withdraw_cosign
Active active_guarantee_count + loan-local backing Repay or permissionless settle_default after due date
Closed Counts and backing cleared Guarantors may exit when obligations are cleared

Security & trust model

Enforced on-chain

  • Membership and savings state
  • Loan limits and guarantor rules
  • Co-sign before disbursement
  • Vault liquidity checks
  • Arithmetic safety (checked_add / checked_sub)

Off-chain / trusted

  • Who may join the pool (workplace policy)
  • Whether a due loan should be cranked as defaulted (off-chain policy)
  • SPL mint legitimacy at pool creation

Full threat model: docs/SECURITY.md.


Project structure

programs/kzp-mini/src/
├── instructions/   Anchor account constraints + one handle per instruction
├── operations/     Pure business rules (unit-tested)
├── state.rs        Pool, Member, Loan
└── utils/          PDA helpers

cli/                kzp command-line client
tests/              solana-program-test integration suite
docs/               Architecture, CLI, accounting, security
scripts/            ci.sh, deploy.sh, devnet-demo.sh
keys/               Local keypairs (gitignored)

Philosophy: instructions = account validation and orchestration · operations = testable rules without Anchor contexts.


Testing

Layer Coverage
Unit tests programs/kzp-mini/src/operations/
Integration 62 solana-program-test scenarios
Specs BDD criteria in docs/USE_CASES.md
bash scripts/ci.sh

Conventions: tests/README.md.


Documentation

Document Audience Purpose
README.md Everyone Overview and navigation
docs/GETTING_STARTED.md Developers Install, deploy, devnet setup
docs/CLI.md Operators Full CLI by role
docs/ARCHITECTURE.md Reviewers Accounts, instructions, mapping
docs/ACCOUNTING.md Auditors Ledger vs vault, limits
docs/SECURITY.md Auditors Threat model
docs/INSTRUCTIONS.md Integrators Instruction account metas
docs/STATE.md Integrators Account layouts
docs/USE_CASES.md Contributors Acceptance criteria
docs/ERRORS.md Integrators Error codes

Index: docs/README.md.


Limitations & tradeoffs

Topic Choice Implication
Policy vs code Eligibility/default policy off-chain Any signer can settle_default after due_ts; off-chain policy decides when to crank
Single admin One pool.admin No multisig in this release
Default split 50/50 (div_ceil on odd amounts) First guarantor pays extra token on odd sums
Loan cap 3× savings, 5 guarantees May block edge cases
Ledger vs vault Both tracked; fail-closed exit/disburse Safer; monitor for drift
Pending loans Only borrower can cancel Abandoned PDAs pay rent until cancelled
Upgrades No migration instruction Schema changes need fresh pool deploy
Toolchain Stable host Rust, Anchor crates 1.1.2, Solana crates 4.x SBF builds still use Solana's bundled compiler; do not set a workspace rust-version above that compiler's support

Roadmap

Planned

  • Multisig pool administration
  • On-chain governance voting for defaults
  • Accrued yield on member savings (pool-level interest distribution)
  • Dynamic guarantee models (e.g. variable split)
  • Account migration support

Contributing

bash scripts/ci.sh

Before opening a PR: cargo fmt, cargo clippy, cargo nextest, anchor build. See docs/GETTING_STARTED.md for toolchain details.


License

MIT

About

"Build everyday real-world systems as on-chain Rust programs" challenge by Superteam Poland.

Topics

Resources

License

Security policy

Stars

1 star

Watchers

1 watching

Forks

Contributors