padreug opened issue aiolabs/lightning-pub#12

padreug
2026-04-01T16:39:56Z

12#Extension: Castle (Accounting)#

Summary

Implement a Nostr-native double-entry accounting extension for Lightning.Pub, replacing the LNbits castle extension. This is the most complex extension to port and should be approached incrementally.

Motivation

Castle provides double-entry bookkeeping for collectives (co-living spaces, makerspaces, community projects). The LNbits version depends on an external Fava/Beancount Python service for all accounting calculations — an awkward dependency that ties it to HTTP and a separate process.

A Lightning.Pub extension could:

Handle balance queries as Nostr RPC calls from any device

Accept expense submissions from mobile Nostr clients

Run approval workflows via encrypted Nostr DMs

Create tamper-evident audit trails as signed Nostr events

Key Design Decision: Fava Dependency

The LNbits version delegates all accounting math to Fava/Beancount. Options for LP:

1. Keep Fava — fastest to implement but defeats the "pure Nostr" goal and requires a sidecar Python service

2. Implement accounting in TypeScript — significant effort but fully self-contained; only needs balanced debit/credit enforcement and hierarchical account sums

3. Start simple, grow incrementally — recommended approach (see phased plan below)

Phased Implementation

Phase 1: SATS-only accounting (MVP)

Flat account list (no hierarchy)

Single currency (SATS)

Basic journal entries with balanced debits/credits

User balances computed from journal entries

Invoice generation for payments

~1500-2000 lines

Phase 2: Multi-currency + hierarchy

Hierarchical accounts with : separator (Expenses:Food:Groceries)

Fiat currency tracking with cost basis notation

Permission inheritance on account hierarchy

~1500 lines additional

Phase 3: Full feature parity

RBAC permission system (READ, SUBMIT_EXPENSE, MANAGE)

Manual payment request/approval workflow via Nostr DMs

Balance assertions and reconciliation

CSV/JSON export

~2000 lines additional

Scope (Full)

RPC Methods:

castle.createAccount        castle.listAccounts
castle.createExpense        castle.createReceivable
castle.createRevenue        castle.createEntry
castle.getBalance           castle.getAllBalances
castle.getUserEntries       castle.generateInvoice
castle.recordPayment        castle.settleReceivable
castle.payUser              castle.requestPayment
castle.approvePayment       castle.rejectPayment
castle.listPaymentRequests  castle.getSettings
castle.updateSettings       castle.grantPermission
castle.revokePermission     castle.reconcile

Data Model:

Account — name, type (Asset/Liability/Equity/Revenue/Expense), parent, metadata

JournalEntry — date, description, flag (cleared/pending/void), reference, creator_pubkey

EntryLine — entry_id, account_id, amount_sats, fiat_amount, fiat_currency, fiat_rate

AccountPermission — account_id, user_pubkey, permission_type, expires_at, granted_by

PaymentRequest — user_pubkey, amount, description, status, approved_by

Core Accounting Invariants:

1. Every entry must have balanced debits and credits

2. Fiat amounts tracked via metadata, NOT converted from current sats balance

3. User identity via Nostr pubkey (not wallet ID)

4. All calculations done in-extension (no external dependency)

Complexity

HIGH — ~5000-8000 lines total across all phases. 2-4 weeks for full implementation.

The accounting logic itself is well-defined (double-entry is centuries old), but currency handling, permission hierarchies, and reconciliation features add significant scope.

Nostr-Native Advantages

Feature | LNbits (HTTP) | Lightning.Pub (Nostr)
Expense submission | Web UI only | Any Nostr client
Balance check | API call with key | Nostr RPC from phone
Approval workflow | Web UI click | Encrypted DM reply
Audit trail | Database rows | Signed Nostr events
Multi-device | Share API key | Same Nostr keypair
Notifications | None | Nostr DM on expense/payment

Reference

LNbits castle extension: lnbits/extensions/castle/

Castle CLAUDE.md: comprehensive architecture docs

Beancount format patterns: castle/beancount_format.py

Permission system: castle/docs/PERMISSIONS-SYSTEM.md

BQL query patterns: castle/docs/BQL-BALANCE-QUERIES.md