> ## Documentation Index
> Fetch the complete documentation index at: https://village-docs.villagelabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ESOPTrust

> The central accounting hub for all ESOP assets and liabilities

## Overview

The `ESOPTrust` is the **central accounting hub** for all plan assets and liabilities. It represents the legal entity that holds company stock and cash on behalf of plan participants.

<Tip>
  **New in v0.2:** Enhanced multi-loan support with dedicated suspense share tracking per loan!
</Tip>

<Info>
  All ESOP assets are owned by the trust, not by individual participants directly. The trust allocates shares and cash to individual participant accounts according to plan rules.
</Info>

## Model Structure

```python theme={null}
class ESOPTrust(BaseModel):
    """
    The ESOP Trust: Central hub for all plan assets.
    """
    # Identification
    trust_id: str
    plan_name: str
    trust_established_date: date
    
    # Cash Management
    cash_ledger: TrustCashLedger
    
    # Share Management
    total_shares_outstanding: Decimal
    allocated_shares: Decimal
    unallocated_shares: Decimal
    
    # Debt Management
    loans: List[ESOPLoan] = []
    
    # Metadata
    current_year: int
    last_valuation_date: date
    current_share_price: Decimal
```

## Key Properties

<AccordionGroup>
  <Accordion title="Cash Ledger" icon="wallet">
    The `TrustCashLedger` manages all trust cash, segregated by source:

    ```python theme={null}
    trust.cash_ledger = TrustCashLedger(
        participant_cash_accounts=125_000,
        unallocated_company_contributions=50_000,
        unallocated_forfeiture_cash=25_000
    )

    # Total cash available
    total_cash = trust.cash_ledger.total_cash()  # 200,000
    ```

    **See:** [TrustCashLedger Details](/models/trust-cash-ledger)
  </Accordion>

  <Accordion title="Share Pools" icon="shapes">
    Shares are categorized by their allocation status:

    ```python theme={null}
    # Shares credited to individual participant accounts
    trust.allocated_shares = 45_000

    # Shares owned by trust but not yet allocated
    trust.unallocated_shares = 5_000

    # Shares held as collateral for loans (in suspense)
    trust.total_suspense_shares() = 30_000  # Sum across all loans

    # Total shares must always balance
    assert trust.total_shares_outstanding == (
        trust.allocated_shares + 
        trust.unallocated_shares + 
        trust.total_suspense_shares()
    )  # 45,000 + 5,000 + 30,000 = 80,000 ✓
    ```

    <Warning>
      **Share Conservation Law:** Total shares must always equal the sum of allocated, unallocated, and suspense shares. The engine validates this after every processing step.
    </Warning>
  </Accordion>

  <Accordion title="ESOP Loans" icon="file-invoice-dollar">
    The trust can have multiple loans, each with dedicated suspense shares:

    ```python theme={null}
    trust.loans = [
        ESOPLoan(
            loan_id="LOAN_2020",
            principal_balance=1_500_000,
            interest_rate=0.065,
            suspense_shares=15_000
        ),
        ESOPLoan(
            loan_id="LOAN_2023",
            principal_balance=1_200_000,
            interest_rate=0.070,
            suspense_shares=15_000
        )
    ]

    # Total suspense shares across all loans
    total_suspense = trust.total_suspense_shares()  # 30,000
    ```

    **See:** [ESOPLoan Details](/models/esop-loan)
  </Accordion>
</AccordionGroup>

## Methods & Operations

### Core Methods

<Tabs>
  <Tab title="Share Calculations">
    ```python theme={null}
    # Total suspense shares across all loans
    def total_suspense_shares(self) -> Decimal:
        return sum(loan.suspense_shares for loan in self.loans)

    # Total market value of trust assets
    def total_asset_value(self) -> Decimal:
        share_value = self.total_shares_outstanding * self.current_share_price
        cash_value = self.cash_ledger.total_cash()
        return share_value + cash_value

    # Shares available for immediate allocation
    def allocable_share_pool(self) -> Decimal:
        return self.unallocated_shares
    ```
  </Tab>

  <Tab title="Cash Operations">
    ```python theme={null}
    # Process a share repurchase
    def repurchase_shares(
        self,
        participant_id: str,
        shares: Decimal,
        cash_sources: List[str]
    ) -> RepurchaseTransaction:
        repurchase_amount = shares * self.current_share_price
        
        # Draw cash from specified sources (waterfall)
        cash_drawn = self.cash_ledger.draw_cash(
            amount=repurchase_amount,
            sources=cash_sources
        )
        
        # Remove shares from circulation
        self.allocated_shares -= shares
        self.total_shares_outstanding -= shares
        
        return RepurchaseTransaction(...)

    # Receive company contribution
    def receive_contribution(
        self,
        cash_amount: Decimal,
        stock_shares: Decimal = 0
    ):
        self.cash_ledger.unallocated_company_contributions += cash_amount
        self.unallocated_shares += stock_shares
        self.total_shares_outstanding += stock_shares
    ```
  </Tab>

  <Tab title="Loan Management">
    ```python theme={null}
    # Process annual loan payment and release shares
    def process_loan_payment(
        self,
        loan_id: str,
        principal_payment: Decimal,
        interest_payment: Decimal
    ) -> Decimal:
        loan = self.get_loan(loan_id)
        
        # Calculate shares to release
        release_percentage = principal_payment / loan.original_principal
        shares_to_release = loan.suspense_shares * release_percentage
        
        # Release shares from suspense
        loan.suspense_shares -= shares_to_release
        loan.principal_balance -= principal_payment
        
        # Add to allocable pool
        self.unallocated_shares += shares_to_release
        
        # Pay interest from cash
        self.cash_ledger.unallocated_company_contributions -= interest_payment
        
        return shares_to_release
    ```
  </Tab>

  <Tab title="Validation">
    ```python theme={null}
    # Validate trust state consistency
    def validate(self) -> List[ValidationError]:
        errors = []
        
        # Check share conservation
        total_calculated = (
            self.allocated_shares + 
            self.unallocated_shares + 
            self.total_suspense_shares()
        )
        if total_calculated != self.total_shares_outstanding:
            errors.append(ValidationError(
                "Share conservation violated",
                f"Expected {self.total_shares_outstanding}, got {total_calculated}"
            ))
        
        # Check cash non-negativity
        if self.cash_ledger.total_cash() < 0:
            errors.append(ValidationError(
                "Negative cash balance",
                f"Total cash: {self.cash_ledger.total_cash()}"
            ))
        
        # Check loan balances
        for loan in self.loans:
            if loan.principal_balance < 0:
                errors.append(ValidationError(
                    f"Negative loan balance: {loan.loan_id}"
                ))
        
        return errors
    ```
  </Tab>
</Tabs>

## Lifecycle Example

Here's how an `ESOPTrust` evolves during a simulation year:

<Steps>
  <Step title="Year Start State">
    ```python theme={null}
    trust = ESOPTrust(
        allocated_shares=45_000,
        unallocated_shares=5_000,
        loans=[ESOPLoan(suspense_shares=30_000, ...)],
        cash_ledger=TrustCashLedger(
            unallocated_contributions=50_000,
            ...
        )
    )
    ```
  </Step>

  <Step title="Company Contribution">
    ```python theme={null}
    # Company contributes $500K
    trust.receive_contribution(cash_amount=500_000)

    # Cash ledger updated:
    # unallocated_contributions: 50,000 → 550,000
    ```
  </Step>

  <Step title="Loan Payment & Share Release">
    ```python theme={null}
    # Pay loan, release shares
    shares_released = trust.process_loan_payment(
        loan_id="LOAN_2020",
        principal_payment=200_000,
        interest_payment=100_000
    )

    # Results:
    # - Suspense shares: 30,000 → 28,000
    # - Unallocated shares: 5,000 → 7,000
    # - Cash: 550,000 → 450,000 (interest paid)
    ```
  </Step>

  <Step title="Allocate Shares">
    ```python theme={null}
    # Allocate released shares to participants
    trust.allocate_shares(shares=7_000, formula='pro_rata')

    # Results:
    # - Allocated shares: 45,000 → 52,000
    # - Unallocated shares: 7,000 → 0
    ```
  </Step>

  <Step title="Process Repurchases">
    ```python theme={null}
    # Repurchase from terminated participant
    trust.repurchase_shares(
        participant_id="EMP042",
        shares=850,
        cash_sources=[
            'unallocated_contributions',
            'unallocated_forfeitures',
            'participant_cash'
        ]
    )

    # Results:
    # - Allocated shares: 52,000 → 51,150
    # - Total shares outstanding: 80,000 → 79,150
    # - Cash: 450,000 → 365,000 (assuming $100/share)
    ```
  </Step>

  <Step title="Year End Snapshot">
    ```python theme={null}
    snapshot = trust.create_snapshot(year=2025)
    # Immutable record saved to database
    ```
  </Step>
</Steps>

## Relationship to Other Models

```mermaid theme={null}
graph TD
    TRUST[ESOPTrust] --> CASH[TrustCashLedger]
    TRUST --> LOANS[ESOPLoans]
    TRUST --> PARTICIPANTS[Participants]
    
    LOANS --> LOAN1[Loan 1: suspense_shares]
    LOANS --> LOAN2[Loan 2: suspense_shares]
    
    PARTICIPANTS --> P1[Participant 1: allocated_shares]
    PARTICIPANTS --> P2[Participant 2: allocated_shares]
    
    TRUST -.validates.-> CONSERVATION[Share Conservation]
    CONSERVATION -.ensures.-> SUM[allocated + unallocated + suspense = total]
    
    style TRUST fill:#29371F,color:#fff
```

## Real-World Example

A typical ESOP Trust state:

```python theme={null}
acme_esop = ESOPTrust(
    trust_id="TRUST_ACME_001",
    plan_name="Acme Corporation ESOP",
    trust_established_date=date(2020, 1, 1),
    
    # Cash (segregated by source)
    cash_ledger=TrustCashLedger(
        participant_cash_accounts=125_000,
        unallocated_company_contributions=200_000,
        unallocated_forfeiture_cash=35_000
    ),  # Total: $360,000
    
    # Shares
    total_shares_outstanding=100_000,
    allocated_shares=68_000,      # Credited to 150 participants
    unallocated_shares=2_000,     # Available for next allocation
    
    # Loans
    loans=[
        ESOPLoan(
            loan_id="LOAN_2020_INITIAL",
            principal_balance=1_800_000,
            interest_rate=0.065,
            original_principal=3_000_000,
            suspense_shares=30_000
        )
    ],
    
    # Valuation
    current_year=2025,
    last_valuation_date=date(2024, 12, 31),
    current_share_price=Decimal("110.50")
)

# Validate state
errors = acme_esop.validate()
assert len(errors) == 0  # ✓ Consistent state

# Calculate metrics
print(f"Total asset value: ${acme_esop.total_asset_value():,.2f}")
# Output: Total asset value: $11,410,000
#   (100,000 shares * $110.50 + $360,000 cash)

print(f"Shares in suspense: {acme_esop.total_suspense_shares():,.0f}")
# Output: Shares in suspense: 30,000

print(f"Percentage allocated: {acme_esop.allocated_shares / acme_esop.total_shares_outstanding:.1%}")
# Output: Percentage allocated: 68.0%
```

## Best Practices

<CardGroup cols={2}>
  <Card title="Always Validate" icon="shield-check">
    Call `trust.validate()` after any state-modifying operation
  </Card>

  <Card title="Preserve History" icon="clock">
    Create snapshots before and after major operations
  </Card>

  <Card title="Use Methods" icon="code">
    Use provided methods rather than directly modifying attributes
  </Card>

  <Card title="Document Assumptions" icon="file-lines">
    Log rationale for any manual adjustments
  </Card>
</CardGroup>

## Next Steps

<CardGroup cols={3}>
  <Card title="TrustCashLedger" icon="wallet" href="/models/trust-cash-ledger">
    Cash segregation details
  </Card>

  <Card title="ESOPLoan" icon="file-invoice-dollar" href="/models/esop-loan">
    Loan structure and mechanics
  </Card>

  <Card title="Simulation Core" icon="gears" href="/architecture/simulation-core">
    How trust state evolves during processing
  </Card>
</CardGroup>
