26 KiB
Accounting Analysis: Net Settlement Entry Pattern
Date: 2025-01-12 Prepared By: Senior Accounting Review Subject: Castle Extension - Lightning Payment Settlement Entries Status: Technical Review
Executive Summary
This document provides a professional accounting assessment of Castle's net settlement entry pattern used for recording Lightning Network payments that settle fiat-denominated receivables. The analysis identifies areas where the implementation deviates from traditional accounting best practices and provides specific recommendations for improvement.
Key Findings:
- ✅ Double-entry integrity maintained
- ✅ Functional for intended purpose
- ❌ Zero-amount postings violate accounting principles
- ❌ Redundant satoshi tracking
- ❌ No exchange gain/loss recognition
- ⚠️ Mixed currency approach lacks clear hierarchy
Background: The Technical Challenge
Castle operates as a Lightning Network-integrated accounting system for collectives (co-living spaces, makerspaces). It faces a unique accounting challenge:
Scenario: User creates a receivable in EUR (e.g., €200 for room rent), then pays via Lightning Network in satoshis (225,033 sats).
Challenge: Record the payment while:
- Clearing the exact EUR receivable amount
- Recording the exact satoshi amount received
- Handling cases where users have both receivables (owe Castle) and payables (Castle owes them)
- Maintaining Beancount double-entry balance
Current Implementation
Transaction Example
; Step 1: Receivable Created
2025-11-12 * "room (200.00 EUR)" #receivable-entry
user-id: "375ec158"
source: "castle-api"
sats-amount: "225033"
Assets:Receivable:User-375ec158 200.00 EUR
sats-equivalent: "225033"
Income:Accommodation:Guests -200.00 EUR
sats-equivalent: "225033"
; Step 2: Lightning Payment Received
2025-11-12 * "Lightning payment settlement from user 375ec158"
#lightning-payment #net-settlement
user-id: "375ec158"
source: "lightning_payment"
payment-type: "net-settlement"
payment-hash: "8d080ec4cc4301715535004156085dd50c159185..."
Assets:Bitcoin:Lightning 225033 SATS @ 0.0008887585... EUR
payment-hash: "8d080ec4cc4301715535004156085dd50c159185..."
Assets:Receivable:User-375ec158 -200.00 EUR
sats-equivalent: "225033"
Liabilities:Payable:User-375ec158 0.00 EUR
Code Implementation
Location: beancount_format.py:739-760
# Build postings for net settlement
postings = [
{
"account": payment_account,
"amount": f"{abs(amount_sats)} SATS @@ {abs(net_fiat_amount):.2f} {fiat_currency}",
"meta": {"payment-hash": payment_hash} if payment_hash else {}
},
{
"account": receivable_account,
"amount": f"-{abs(total_receivable_fiat):.2f} {fiat_currency}",
"meta": {"sats-equivalent": str(abs(amount_sats))}
},
{
"account": payable_account,
"amount": f"{abs(total_payable_fiat):.2f} {fiat_currency}",
"meta": {}
}
]
Three-Posting Structure:
- Lightning Account: Records SATS received with
@@total price notation - Receivable Account: Clears EUR receivable with sats-equivalent metadata
- Payable Account: Clears any outstanding EUR payables (often 0.00)
Accounting Issues Identified
Issue 1: Zero-Amount Postings
Problem: The third posting often records 0.00 EUR when no payable exists.
Liabilities:Payable:User-375ec158 0.00 EUR
Why This Is Wrong:
- Zero-amount postings have no economic substance
- Clutters the journal with non-events
- Violates the principle of materiality (GAAP Concept Statement 2)
- Makes auditing more difficult (reviewers must verify why zero amounts exist)
Accounting Principle Violated:
"Transactions should only include postings that represent actual economic events or changes in account balances."
Impact: Low severity, but unprofessional presentation
Recommendation:
# Make payable posting conditional
postings = [
{"account": payment_account, "amount": ...},
{"account": receivable_account, "amount": ...}
]
# Only add payable posting if there's actually a payable
if total_payable_fiat > 0:
postings.append({
"account": payable_account,
"amount": f"{abs(total_payable_fiat):.2f} {fiat_currency}",
"meta": {}
})
Issue 2: Redundant Satoshi Tracking
Problem: Satoshis are tracked in TWO places in the same transaction:
-
Position Amount (via
@@notation):Assets:Bitcoin:Lightning 225033 SATS @@ 200.00 EUR -
Metadata (sats-equivalent):
Assets:Receivable:User-375ec158 -200.00 EUR sats-equivalent: "225033"
Why This Is Problematic:
- The
@@notation already records the exact satoshi amount - Beancount's price database stores this relationship
- Metadata becomes redundant for this specific posting
- Increases storage and potential for inconsistency
Technical Detail:
The @@ notation means "total price" and Beancount converts it to per-unit price:
; You write:
Assets:Bitcoin:Lightning 225033 SATS @@ 200.00 EUR
; Beancount stores:
Assets:Bitcoin:Lightning 225033 SATS @ 0.0008887585... EUR
; (where 200.00 / 225033 = 0.0008887585...)
Beancount can query this:
SELECT account, sum(convert(position, SATS))
WHERE account = 'Assets:Bitcoin:Lightning'
Recommendation:
Choose ONE approach consistently:
Option A - Use @ notation (Beancount standard):
Assets:Bitcoin:Lightning 225033 SATS @@ 200.00 EUR
payment-hash: "8d080ec4..."
Assets:Receivable:User-375ec158 -200.00 EUR
; No sats-equivalent needed here
Option B - Use EUR positions with metadata (Castle's current approach):
Assets:Bitcoin:Lightning 200.00 EUR
sats-received: "225033"
payment-hash: "8d080ec4..."
Assets:Receivable:User-375ec158 -200.00 EUR
sats-cleared: "225033"
Don't: Mix both in the same transaction (current implementation)
Issue 3: No Exchange Gain/Loss Recognition
Problem: When receivables are denominated in one currency (EUR) and paid in another (SATS), exchange rate fluctuations create gains or losses that should be recognized.
Example Scenario:
Day 1 - Receivable Created:
200 EUR = 225,033 SATS (rate: 1,125.165 sats/EUR)
Day 5 - Payment Received:
225,033 SATS = 199.50 EUR (rate: 1,127.682 sats/EUR)
Exchange rate moved unfavorably
Economic Reality: 0.50 EUR LOSS
Current Implementation: Forces balance by calculating the @ rate to make it exactly 200 EUR:
Assets:Bitcoin:Lightning 225033 SATS @ 0.000888... EUR ; = exactly 200.00 EUR
This hides the exchange variance by treating the payment as if it was worth exactly the receivable amount.
GAAP/IFRS Requirement:
Under both US GAAP (ASC 830) and IFRS (IAS 21), exchange gains and losses on monetary items (like receivables) should be recognized in the period they occur.
Proper Accounting Treatment:
2025-11-12 * "Lightning payment with exchange loss"
Assets:Bitcoin:Lightning 225033 SATS @ 0.000886... EUR
; Market rate at payment time = 199.50 EUR
Expenses:Foreign-Exchange-Loss 0.50 EUR
Assets:Receivable:User-375ec158 -200.00 EUR
Impact: Moderate severity - affects financial statement accuracy
Why This Matters:
- Tax reporting may require exchange gain/loss recognition
- Financial statements misstate true economic results
- Auditors would flag this as a compliance issue
- Cannot accurately calculate ROI or performance metrics
Issue 4: Semantic Misuse of Price Notation
Problem: The @ notation in Beancount represents acquisition cost, not settlement value.
Current Usage:
Assets:Bitcoin:Lightning 225033 SATS @ 0.000888... EUR
What this notation means in accounting: "We purchased 225,033 satoshis at a cost of 0.000888 EUR per satoshi"
What actually happened: "We received 225,033 satoshis as payment for a debt"
Economic Difference:
- Purchase: You exchange cash for an asset (buying Bitcoin)
- Payment Receipt: You receive an asset in settlement of a receivable
Accounting Substance vs. Form:
- Form: The transaction looks like a Bitcoin purchase
- Substance: The transaction is actually a receivable collection
GAAP Principle (ASC 105-10-05):
"Accounting should reflect the economic substance of transactions, not merely their legal form."
Why This Creates Issues:
- Cost Basis Tracking: For tax purposes, the "cost" of Bitcoin received as payment should be its fair market value at receipt, not the receivable amount
- Price Database Pollution: Beancount's price database now contains "prices" that aren't real market prices
- Auditor Confusion: An auditor reviewing this would question why purchase prices don't match market rates
Proper Accounting Approach:
; Approach 1: Record at fair market value
Assets:Bitcoin:Lightning 225033 SATS @ 0.000886... EUR
; Using actual market price at time of receipt
acquisition-type: "payment-received"
Revenue:Exchange-Gain 0.50 EUR
Assets:Receivable:User-375ec158 -200.00 EUR
; Approach 2: Don't use @ notation at all
Assets:Bitcoin:Lightning 200.00 EUR
sats-received: "225033"
fmv-at-receipt: "199.50 EUR"
Assets:Receivable:User-375ec158 -200.00 EUR
Issue 5: Misnamed Function and Incorrect Usage
Problem: Function is called format_net_settlement_entry, but it's used for simple payments that aren't true net settlements.
Example from User's Transaction:
- Receivable: 200.00 EUR
- Payable: 0.00 EUR
- Net: 200.00 EUR (this is just a payment, not a settlement)
Accounting Terminology:
- Payment: Settling a single obligation (receivable OR payable)
- Net Settlement: Offsetting multiple obligations (receivable AND payable)
When Net Settlement is Appropriate:
User owes Castle: 555.00 EUR (receivable)
Castle owes User: 38.00 EUR (payable)
Net amount due: 517.00 EUR (true settlement)
Proper three-posting entry:
Assets:Bitcoin:Lightning 565251 SATS @@ 517.00 EUR
Assets:Receivable:User -555.00 EUR
Liabilities:Payable:User 38.00 EUR
; Net: 517.00 = -555.00 + 38.00 ✓
When Two Postings Suffice:
User owes Castle: 200.00 EUR (receivable)
Castle owes User: 0.00 EUR (no payable)
Amount due: 200.00 EUR (simple payment)
Simpler two-posting entry:
Assets:Bitcoin:Lightning 225033 SATS @@ 200.00 EUR
Assets:Receivable:User -200.00 EUR
Best Practice: Use the simplest journal entry structure that accurately represents the transaction.
Recommendation:
- Rename function to
format_payment_entryorformat_receivable_payment_entry - Create separate
format_net_settlement_entryfor true netting scenarios - Use conditional logic to choose 2-posting vs 3-posting based on whether both receivables AND payables exist
Traditional Accounting Approaches
Approach 1: Record Bitcoin at Fair Market Value (Tax Compliant)
2025-11-12 * "Bitcoin payment from user 375ec158"
Assets:Bitcoin:Lightning 199.50 EUR
sats-received: "225033"
fmv-per-sat: "0.000886 EUR"
cost-basis: "199.50 EUR"
payment-hash: "8d080ec4..."
Revenue:Exchange-Gain 0.50 EUR
source: "cryptocurrency-receipt"
Assets:Receivable:User-375ec158 -200.00 EUR
Pros:
- ✅ Tax compliant (establishes cost basis)
- ✅ Recognizes exchange gain/loss
- ✅ Uses actual market rates
- ✅ Audit trail for cryptocurrency receipts
Cons:
- ❌ Requires real-time price feeds
- ❌ Creates taxable events
Approach 2: Simplified EUR-Only Ledger (No SATS Positions)
2025-11-12 * "Bitcoin payment from user 375ec158"
Assets:Bitcoin:Lightning 200.00 EUR
sats-received: "225033"
sats-rate: "1125.165"
payment-hash: "8d080ec4..."
Assets:Receivable:User-375ec158 -200.00 EUR
Pros:
- ✅ Simple and clean
- ✅ EUR positions match accounting reality
- ✅ SATS tracked in metadata for reference
- ✅ No artificial price notation
Cons:
- ❌ SATS not queryable via Beancount positions
- ❌ Requires metadata parsing for SATS balances
Approach 3: True Net Settlement (When Both Obligations Exist)
2025-11-12 * "Net settlement via Lightning"
; User owes 555 EUR, Castle owes 38 EUR, net: 517 EUR
Assets:Bitcoin:Lightning 517.00 EUR
sats-received: "565251"
Assets:Receivable:User-375ec158 -555.00 EUR
Liabilities:Payable:User-375ec158 38.00 EUR
When to Use: Only when both receivables and payables exist and you're truly netting them.
Recommendations
Priority 1: Immediate Fixes (Easy Wins)
1.1 Remove Zero-Amount Postings
File: beancount_format.py:739-760
Current Code:
postings = [
{...}, # Lightning
{...}, # Receivable
{ # Payable (always included, even if 0.00)
"account": payable_account,
"amount": f"{abs(total_payable_fiat):.2f} {fiat_currency}",
"meta": {}
}
]
Fixed Code:
postings = [
{
"account": payment_account,
"amount": f"{abs(amount_sats)} SATS @@ {abs(net_fiat_amount):.2f} {fiat_currency}",
"meta": {"payment-hash": payment_hash} if payment_hash else {}
},
{
"account": receivable_account,
"amount": f"-{abs(total_receivable_fiat):.2f} {fiat_currency}",
"meta": {"sats-equivalent": str(abs(amount_sats))}
}
]
# Only add payable posting if there's actually a payable to clear
if total_payable_fiat > 0:
postings.append({
"account": payable_account,
"amount": f"{abs(total_payable_fiat):.2f} {fiat_currency}",
"meta": {}
})
Impact: Cleaner journal, professional presentation, easier auditing
1.2 Choose One SATS Tracking Method
Decision Required: Select either position-based OR metadata-based satoshi tracking.
Option A - Keep Metadata Approach (recommended for Castle):
# In format_net_settlement_entry()
postings = [
{
"account": payment_account,
"amount": f"{abs(net_fiat_amount):.2f} {fiat_currency}", # EUR only
"meta": {
"sats-received": str(abs(amount_sats)),
"payment-hash": payment_hash
}
},
{
"account": receivable_account,
"amount": f"-{abs(total_receivable_fiat):.2f} {fiat_currency}",
"meta": {"sats-cleared": str(abs(amount_sats))}
}
]
Option B - Use Position-Based Tracking:
# Remove sats-equivalent metadata entirely
postings = [
{
"account": payment_account,
"amount": f"{abs(amount_sats)} SATS @@ {abs(net_fiat_amount):.2f} {fiat_currency}",
"meta": {"payment-hash": payment_hash}
},
{
"account": receivable_account,
"amount": f"-{abs(total_receivable_fiat):.2f} {fiat_currency}",
# No sats-equivalent needed - queryable via price database
}
]
Recommendation: Choose Option A (metadata) for consistency with Castle's architecture.
1.3 Rename Function for Clarity
File: beancount_format.py
Current: format_net_settlement_entry()
New: format_receivable_payment_entry() or format_payment_settlement_entry()
Rationale: More accurately describes what the function does (processes payments, not always net settlements)
Priority 2: Medium-Term Improvements (Compliance)
2.1 Add Exchange Gain/Loss Tracking
File: tasks.py:259-276 (get balance and calculate settlement)
New Logic:
# Get user's current balance
balance = await fava.get_user_balance(user_id)
fiat_balances = balance.get("fiat_balances", {})
total_fiat_balance = fiat_balances.get(fiat_currency, Decimal(0))
# Calculate expected fiat value of SATS payment at current market rate
market_rate = await get_current_sats_eur_rate() # New function needed
market_value = Decimal(amount_sats) * market_rate
# Calculate exchange variance
receivable_amount = abs(total_fiat_balance) if total_fiat_balance > 0 else Decimal(0)
exchange_variance = market_value - receivable_amount
# If variance is material (> 1 cent), create exchange gain/loss posting
if abs(exchange_variance) > Decimal("0.01"):
# Add exchange gain/loss to postings
if exchange_variance > 0:
# Gain: payment worth more than receivable
exchange_account = "Revenue:Foreign-Exchange-Gain"
else:
# Loss: payment worth less than receivable
exchange_account = "Expenses:Foreign-Exchange-Loss"
# Include in entry creation
exchange_posting = {
"account": exchange_account,
"amount": f"{abs(exchange_variance):.2f} {fiat_currency}",
"meta": {
"sats-amount": str(amount_sats),
"market-rate": str(market_rate),
"receivable-amount": str(receivable_amount)
}
}
Benefits:
- ✅ Tax compliance
- ✅ Accurate financial reporting
- ✅ Audit trail for cryptocurrency gains/losses
- ✅ Regulatory compliance (GAAP/IFRS)
2.2 Implement True Net Settlement vs. Simple Payment Logic
File: tasks.py or new payment_logic.py
async def create_payment_entry(
user_id: str,
amount_sats: int,
fiat_amount: Decimal,
fiat_currency: str,
payment_hash: str
):
"""
Create appropriate payment entry based on user's balance situation.
Uses 2-posting for simple payments, 3-posting for net settlements.
"""
# Get user balance
balance = await fava.get_user_balance(user_id)
fiat_balances = balance.get("fiat_balances", {})
total_balance = fiat_balances.get(fiat_currency, Decimal(0))
receivable_amount = Decimal(0)
payable_amount = Decimal(0)
if total_balance > 0:
receivable_amount = total_balance
elif total_balance < 0:
payable_amount = abs(total_balance)
# Determine entry type
if receivable_amount > 0 and payable_amount > 0:
# TRUE NET SETTLEMENT: Both obligations exist
return await format_net_settlement_entry(
user_id=user_id,
amount_sats=amount_sats,
receivable_amount=receivable_amount,
payable_amount=payable_amount,
fiat_amount=fiat_amount,
fiat_currency=fiat_currency,
payment_hash=payment_hash
)
elif receivable_amount > 0:
# SIMPLE RECEIVABLE PAYMENT: Only receivable exists
return await format_receivable_payment_entry(
user_id=user_id,
amount_sats=amount_sats,
receivable_amount=receivable_amount,
fiat_amount=fiat_amount,
fiat_currency=fiat_currency,
payment_hash=payment_hash
)
else:
# PAYABLE PAYMENT: Castle paying user (different flow)
return await format_payable_payment_entry(...)
Priority 3: Long-Term Architectural Decisions
3.1 Establish Primary Currency Hierarchy
Current Issue: Mixed approach (EUR positions with SATS metadata, but also SATS positions with @ notation)
Decision Required: Choose ONE of the following architectures:
Architecture A - EUR Primary, SATS Secondary (recommended):
; All positions in EUR, SATS in metadata
2025-11-12 * "Payment"
Assets:Bitcoin:Lightning 200.00 EUR
sats-received: "225033"
Assets:Receivable:User -200.00 EUR
sats-cleared: "225033"
Architecture B - SATS Primary, EUR Secondary:
; All positions in SATS, EUR in metadata
2025-11-12 * "Payment"
Assets:Bitcoin:Lightning 225033 SATS
eur-value: "200.00"
Assets:Receivable:User -225033 SATS
eur-cleared: "200.00"
Recommendation: Architecture A (EUR primary) because:
- Most receivables created in EUR
- Financial reporting requirements typically in fiat
- Tax obligations calculated in fiat
- Aligns with current Castle metadata approach
3.2 Consider Separate Ledger for Cryptocurrency Holdings
Advanced Approach: Separate cryptocurrency movements from fiat accounting
Main Ledger (EUR-denominated):
2025-11-12 * "Payment received from user"
Assets:Bitcoin-Custody:User-375ec158 200.00 EUR
Assets:Receivable:User-375ec158 -200.00 EUR
Cryptocurrency Sub-Ledger (SATS-denominated):
2025-11-12 * "Lightning payment received"
Assets:Bitcoin:Lightning:Castle 225033 SATS
Assets:Bitcoin:Custody:User-375ec 225033 SATS
Benefits:
- ✅ Clean separation of concerns
- ✅ Cryptocurrency movements tracked independently
- ✅ Fiat accounting unaffected by Bitcoin volatility
- ✅ Can generate separate financial statements
Drawbacks:
- ❌ Increased complexity
- ❌ Reconciliation between ledgers required
- ❌ Two sets of books to maintain
Code Files Requiring Changes
High Priority (Immediate Fixes)
-
beancount_format.py:739-760- Remove zero-amount postings
- Make payable posting conditional
-
beancount_format.py:692- Rename function to
format_receivable_payment_entry
- Rename function to
Medium Priority (Compliance)
-
tasks.py:235-310- Add exchange gain/loss calculation
- Implement payment vs. settlement logic
-
New file:
exchange_rates.py- Create
get_current_sats_eur_rate()function - Implement price feed integration
- Create
-
beancount_format.py- Create new
format_net_settlement_entry()for true netting - Create
format_receivable_payment_entry()for simple payments
- Create new
Testing Requirements
Test Case 1: Simple Receivable Payment (No Payable)
Setup:
- User has receivable: 200.00 EUR
- User has payable: 0.00 EUR
- User pays: 225,033 SATS
Expected Entry (after fixes):
2025-11-12 * "Lightning payment from user"
Assets:Bitcoin:Lightning 200.00 EUR
sats-received: "225033"
payment-hash: "8d080ec4..."
Assets:Receivable:User -200.00 EUR
sats-cleared: "225033"
Verify:
- ✅ Only 2 postings (no zero-amount payable)
- ✅ Entry balances
- ✅ SATS tracked in metadata
- ✅ User balance becomes 0 (both EUR and SATS)
Test Case 2: True Net Settlement
Setup:
- User has receivable: 555.00 EUR
- User has payable: 38.00 EUR
- Net owed: 517.00 EUR
- User pays: 565,251 SATS (worth 517.00 EUR)
Expected Entry:
2025-11-12 * "Net settlement via Lightning"
Assets:Bitcoin:Lightning 517.00 EUR
sats-received: "565251"
payment-hash: "abc123..."
Assets:Receivable:User -555.00 EUR
sats-portion: "565251"
Liabilities:Payable:User 38.00 EUR
Verify:
- ✅ 3 postings (receivable + payable cleared)
- ✅ Net amount = receivable - payable
- ✅ Both balances become 0
- ✅ Mathematically balanced
Test Case 3: Exchange Gain/Loss (Future)
Setup:
- User has receivable: 200.00 EUR (created at 1,125 sats/EUR)
- User pays: 225,033 SATS (now worth 199.50 EUR at market)
- Exchange loss: 0.50 EUR
Expected Entry (with exchange tracking):
2025-11-12 * "Lightning payment with exchange loss"
Assets:Bitcoin:Lightning 199.50 EUR
sats-received: "225033"
market-rate: "0.000886"
Expenses:Foreign-Exchange-Loss 0.50 EUR
Assets:Receivable:User -200.00 EUR
Verify:
- ✅ Bitcoin recorded at fair market value
- ✅ Exchange loss recognized
- ✅ Receivable cleared at book value
- ✅ Entry balances
Conclusion
Summary of Issues
| Issue | Severity | Accounting Impact | Recommended Action |
|---|---|---|---|
| Zero-amount postings | Low | Presentation only | Remove immediately |
| Redundant SATS tracking | Low | Storage/efficiency | Choose one method |
| No exchange gain/loss | High | Financial accuracy | Implement for compliance |
| Semantic misuse of @ | Medium | Audit clarity | Consider EUR-only positions |
| Misnamed function | Low | Code clarity | Rename function |
Professional Assessment
Is this "best practice" accounting? No, this implementation deviates from traditional accounting standards in several ways.
Is it acceptable for Castle's use case? Yes, with modifications, it's a reasonable pragmatic solution for a novel problem (cryptocurrency payments of fiat debts).
Critical improvements needed:
- ✅ Remove zero-amount postings (easy fix, professional presentation)
- ✅ Implement exchange gain/loss tracking (required for compliance)
- ✅ Separate payment vs. settlement logic (accuracy and clarity)
The fundamental challenge: Traditional accounting wasn't designed for this scenario. There is no established "standard" for recording cryptocurrency payments of fiat-denominated receivables. Castle's approach is functional, but should be refined to align better with accounting principles where possible.
Next Steps
- Week 1: Implement Priority 1 fixes (remove zero postings, rename function)
- Week 2-3: Design and implement exchange gain/loss tracking
- Week 4: Add payment vs. settlement logic
- Ongoing: Monitor regulatory guidance on cryptocurrency accounting
References
- FASB ASC 830: Foreign Currency Matters
- IAS 21: The Effects of Changes in Foreign Exchange Rates
- FASB Concept Statement No. 2: Qualitative Characteristics of Accounting Information
- ASC 105-10-05: Substance Over Form
- Beancount Documentation: http://furius.ca/beancount/doc/index
- Castle Extension:
docs/SATS-EQUIVALENT-METADATA.md - BQL Analysis:
docs/BQL-BALANCE-QUERIES.md
Document Version: 1.0 Last Updated: 2025-01-12 Next Review: After Priority 1 fixes implemented
This analysis was prepared for internal review and development planning. It represents a professional accounting assessment of the current implementation and should be used to guide improvements to Castle's payment recording system.