Skip to main content

The Non-Fungible Cash Problem

In traditional accounting, all cash is fungible—any dollar can be used for any purpose. But ESOP trust cash is different. The source of cash determines how it can be legally used.
Using restricted cash for the wrong purpose can result in ERISA violations, DOL audits, and plan disqualification.

Model Structure

The TrustCashLedger segregates cash by source, each with different usage rules:
class TrustCashLedger(BaseModel):
    """
    Non-fungible cash ledger tracking cash by source.
    """
    # Individual participant cash balances
    participant_cash_accounts: Decimal = Field(ge=0)
    
    # Company contributions not yet allocated
    unallocated_company_contributions: Decimal = Field(ge=0)
    
    # Forfeitures not yet reallocated or used
    unallocated_forfeiture_cash: Decimal = Field(ge=0)
    
    def total_cash(self) -> Decimal:
        return (
            self.participant_cash_accounts +
            self.unallocated_company_contributions +
            self.unallocated_forfeiture_cash
        )

Cash Sources Explained

What It Is: The sum of all cash held in individual employee accounts.How It Gets There:
  • Cash dividends on ESOP shares
  • Proceeds from diversification elections
  • Forfeitures reallocated as cash
Usage Restrictions:
  • ✅ Can be used for distributions to that participant
  • ✅ Can fund repurchases per plan document
  • ❌ Cannot be used for plan expenses
  • ❌ Cannot be used for other participants
# Example: Participant has $5,000 cash in account
# Can be distributed to participant on termination
# Or used to repurchase their shares (per plan rules)
What It Is: Company contributions that have been received but not yet credited to individual participants.How It Gets There:
  • Annual company cash contributions
  • Loan proceeds (for leveraged ESOPs)
Usage Restrictions:
  • ✅ Can be used for share purchases
  • ✅ Can fund repurchases (per plan document)
  • ✅ Can be allocated to participants
  • ✅ Flexible use per cash_usage_policy
# Most flexible cash source
# Temporary holding account before allocation
Timing Gap: There’s often a delay between when a contribution is made and when shares are allocated. This account bridges that gap.
What It Is: Cash from the non-vested accounts of terminated participants.How It Gets There:
  • Terminated participant had non-vested shares
  • Shares sold, proceeds held here
Usage Restrictions:
  • ✅ Can reduce company contributions (most common)
  • ✅ Can be reallocated to remaining participants
  • ✅ Can fund administrative expenses (if plan allows)
  • ⚠️ Usage strictly governed by plan document
# Example: Employee terminates with 40% vesting
# Non-vested 60% becomes forfeiture
# Shares sold → cash held here
Highly Restricted: Plan document specifies exactly how forfeitures can be used. Deviation can cause plan disqualification.

The Funding Waterfall

When the trust needs cash (e.g., for repurchases), it draws from sources in a specific order defined by PlanRules.cash_usage_policy:
# Example cash_usage_policy
cash_usage_policy = [
    "unallocated_company_contributions",  # Draw from here first
    "unallocated_forfeiture_cash",        # Then here
    "participant_cash_accounts"           # Last resort
]

# Process a $500,000 repurchase
ledger = TrustCashLedger(
    participant_cash_accounts=150_000,
    unallocated_contributions=200_000,
    unallocated_forfeitures=100_000
)

result = ledger.draw_cash(
    amount=500_000,
    sources=cash_usage_policy
)

# Execution:
# 1. Draw $200K from unallocated_contributions → $300K remaining
# 2. Draw $100K from unallocated_forfeitures → $200K remaining
# 3. Draw $200K from participant_cash → $0 remaining ✓

Methods & Operations

def draw_cash(
    self,
    amount: Decimal,
    sources: List[str]
) -> CashDrawResult:
    """
    Draw cash following the waterfall sequence.
    """
    remaining_need = amount
    transactions = []
    
    for source in sources:
        if remaining_need <= 0:
            break
        
        available = getattr(self, source)
        amount_to_draw = min(available, remaining_need)
        
        if amount_to_draw > 0:
            # Deduct from source
            setattr(self, source, available - amount_to_draw)
            remaining_need -= amount_to_draw
            
            transactions.append(
                CashTransaction(
                    source=source,
                    amount=amount_to_draw
                )
            )
    
    return CashDrawResult(
        requested=amount,
        drawn=amount - remaining_need,
        shortfall=remaining_need,
        transactions=transactions
    )

Real-World Example

Here’s a complete annual cycle showing cash flow through the ledger:
1

Year Start

ledger = TrustCashLedger(
    participant_cash=125_000,
    unallocated_contributions=50_000,
    unallocated_forfeitures=25_000
)
# Total: $200,000
2

Company Contribution

ledger.deposit_cash(
    amount=500_000,
    source="unallocated_company_contributions"
)
# unallocated_contributions: 50K → 550K
3

Forfeiture Reallocation

# Reallocate forfeitures to participants
ledger.transfer(
    amount=25_000,
    from_source="unallocated_forfeiture_cash",
    to_source="participant_cash_accounts"
)
# forfeitures: 25K → 0
# participant_cash: 125K → 150K
4

Repurchase Obligation

# Need $400K for terminated participants
result = ledger.draw_cash(
    amount=400_000,
    sources=[
        "unallocated_company_contributions",
        "unallocated_forfeiture_cash",
        "participant_cash_accounts"
    ]
)

# Execution:
# Draw $400K from unallocated_contributions
# unallocated_contributions: 550K → 150K
5

Year End

ledger = TrustCashLedger(
    participant_cash=150_000,
    unallocated_contributions=150_000,
    unallocated_forfeitures=0
)
# Total: $300,000

Why This Matters

Legal Compliance

Proper segregation ensures ERISA compliance and prevents DOL issues

Audit Trail

Clear source tracking makes audits straightforward

Planning Accuracy

Knowing what cash is available for what purpose improves forecasting

Fiduciary Protection

Demonstrates prudent management of plan assets

Common Mistakes to Avoid

Don’t:
  • ❌ Use participant cash for other participants
  • ❌ Use forfeiture cash without checking plan rules
  • ❌ Ignore the cash_usage_policy waterfall
  • ❌ Allow negative balances in any account
Do:
  • ✅ Follow the plan document’s cash usage rules
  • ✅ Validate after every cash operation
  • ✅ Log all cash movements
  • ✅ Review cash sources before making decisions

Next Steps