> ## 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.

# ESOPLoan

> Self-contained loan object with dedicated suspense shares

## Overview

Each `ESOPLoan` object represents a debt obligation of the ESOP, with shares held in a **dedicated suspense account** as collateral. This self-contained design ensures accurate loan-by-loan accounting for leveraged ESOPs.

<Info>
  **Critical Concept:** Each loan directly owns its suspense shares. When Loan A is paid down, only Loan A's shares are released—never shares from Loan B.
</Info>

## Model Structure

```python theme={null}
class ESOPLoan(BaseModel):
    """
    A self-contained ESOP loan with dedicated suspense shares.
    """
    # Identification
    loan_id: str
    origination_date: date
    
    # Loan Terms
    original_principal: Decimal
    principal_balance: Decimal
    interest_rate: Decimal
    term_years: int
    payment_schedule: str  # 'amortizing' or 'balloon'
    
    # Collateral
    suspense_shares: Decimal  # Shares held for THIS loan only
    original_suspense_shares: Decimal
    
    # Metadata
    lender: str
    loan_purpose: str  # 'initial_esop_purchase', 'refinancing', etc.
```

## Why Loan-Specific Suspense Matters

<Tabs>
  <Tab title="❌ Wrong Approach">
    **Single Suspense Pool (Incorrect)**

    ```python theme={null}
    # BAD: All suspense shares in one pool
    trust = {
        "total_suspense_shares": 50_000,
        "loans": [
            {"id": "LOAN_A", "balance": 2_000_000},
            {"id": "LOAN_B", "balance": 1_500_000}
        ]
    }

    # Problem: When paying LOAN_A, which shares get released?
    # You can't tell! This violates ERISA requirements.
    ```

    **Why It Fails:**

    * Can't determine which shares collateralize which loan
    * Violates ERISA's specific collateral requirements
    * Creates audit and compliance risk
  </Tab>

  <Tab title="✅ Correct Approach">
    **Loan-Specific Suspense (Correct)**

    ```python theme={null}
    # GOOD: Each loan owns its shares
    loan_a = ESOPLoan(
        loan_id="LOAN_A",
        principal_balance=2_000_000,
        suspense_shares=30_000  # These shares belong to LOAN_A
    )

    loan_b = ESOPLoan(
        loan_id="LOAN_B",
        principal_balance=1_500_000,
        suspense_shares=20_000  # These shares belong to LOAN_B
    )

    # Clear: Paying LOAN_A releases LOAN_A's shares only
    ```

    **Why It Works:**

    * Clear collateral ownership
    * ERISA compliant
    * Accurate share release calculations
  </Tab>
</Tabs>

## Share Release Mechanics

When a loan payment is made, shares are released **proportionally** to the principal paid:

```python theme={null}
def calculate_share_release(
    loan: ESOPLoan,
    principal_payment: Decimal
) -> Decimal:
    """
    Calculate shares to release based on principal payment.
    """
    # Percentage of original loan being paid
    release_percentage = principal_payment / loan.original_principal
    
    # Release that percentage of original suspense shares
    shares_to_release = loan.original_suspense_shares * release_percentage
    
    return shares_to_release

# Example
loan = ESOPLoan(
    original_principal=3_000_000,
    principal_balance=2_400_000,
    original_suspense_shares=30_000,
    suspense_shares=30_000  # None released yet
)

# Pay $300K principal
shares_released = calculate_share_release(loan, 300_000)
# = 30,000 * (300,000 / 3,000,000)
# = 30,000 * 0.10
# = 3,000 shares

# Update loan
loan.principal_balance -= 300_000  # 2,400K → 2,100K
loan.suspense_shares -= 3_000      # 30,000 → 27,000
```

<Note>
  **ERISA Requirement:** Shares must be released proportionally as the loan is repaid. This prevents "back-loading" where all shares are released at the end.
</Note>

## Loan Types & Payment Schedules

<Tabs>
  <Tab title="Amortizing Loan">
    Equal principal + interest payments each year.

    ```python theme={null}
    loan = ESOPLoan(
        original_principal=3_000_000,
        interest_rate=0.065,
        term_years=10,
        payment_schedule='amortizing'
    )

    # Calculate annual payment (simplified)
    annual_payment = calculate_amortizing_payment(
        principal=3_000_000,
        rate=0.065,
        years=10
    )  # ≈ $415,000/year

    # Each year: consistent payment, increasing principal portion
    ```
  </Tab>

  <Tab title="Interest-Only with Balloon">
    Interest-only payments with principal due at maturity.

    ```python theme={null}
    loan = ESOPLoan(
        original_principal=3_000_000,
        interest_rate=0.065,
        term_years=10,
        payment_schedule='balloon'
    )

    # Years 1-9: Interest only
    annual_interest = 3_000_000 * 0.065  # $195,000

    # Year 10: Interest + full principal
    final_payment = 195_000 + 3_000_000  # $3,195,000

    # Share release: All at once in year 10
    ```

    <Warning>
      **Risk:** Balloon payments create large share releases and cash needs in final year. Plan carefully!
    </Warning>
  </Tab>

  <Tab title="Custom Schedule">
    Flexible payment structure.

    ```python theme={null}
    loan = ESOPLoan(
        original_principal=3_000_000,
        interest_rate=0.065,
        payment_schedule='custom',
        payment_stream=[
            # Year 1: Lower payment
            {"year": 1, "principal": 150_000, "interest": 195_000},
            # Year 2: Higher payment
            {"year": 2, "principal": 400_000, "interest": 185_000},
            # ...
        ]
    )
    ```
  </Tab>
</Tabs>

## Methods & Operations

<Tabs>
  <Tab title="Process Payment">
    ```python theme={null}
    def process_payment(
        self,
        principal_payment: Decimal,
        interest_payment: Decimal
    ) -> LoanPaymentResult:
        """
        Process a loan payment and release shares.
        """
        # Calculate share release
        release_pct = principal_payment / self.original_principal
        shares_to_release = self.original_suspense_shares * release_pct
        
        # Validate
        if shares_to_release > self.suspense_shares:
            raise ValueError("Cannot release more shares than in suspense")
        
        # Update loan state
        self.principal_balance -= principal_payment
        self.suspense_shares -= shares_to_release
        
        return LoanPaymentResult(
            principal_paid=principal_payment,
            interest_paid=interest_payment,
            shares_released=shares_to_release,
            remaining_balance=self.principal_balance,
            remaining_suspense=self.suspense_shares
        )
    ```
  </Tab>

  <Tab title="Calculate Payment">
    ```python theme={null}
    def calculate_annual_payment(self, year: int) -> Tuple[Decimal, Decimal]:
        """
        Calculate principal and interest for a given year.
        """
        if self.payment_schedule == 'amortizing':
            # Standard amortization formula
            annual_payment = calculate_pmt(
                rate=self.interest_rate,
                nper=self.term_years,
                pv=self.original_principal
            )
            
            interest = self.principal_balance * self.interest_rate
            principal = annual_payment - interest
            
            return (principal, interest)
        
        elif self.payment_schedule == 'balloon':
            interest = self.principal_balance * self.interest_rate
            
            # Principal due in final year only
            if year == self.term_years:
                principal = self.principal_balance
            else:
                principal = Decimal(0)
            
            return (principal, interest)
    ```
  </Tab>

  <Tab title="Status Check">
    ```python theme={null}
    def loan_status(self) -> Dict:
        """
        Get current loan status and metrics.
        """
        percent_paid = (
            (self.original_principal - self.principal_balance) / 
            self.original_principal
        )
        
        shares_released_count = (
            self.original_suspense_shares - self.suspense_shares
        )
        
        return {
            "loan_id": self.loan_id,
            "balance": self.principal_balance,
            "percent_paid": percent_paid,
            "suspense_shares": self.suspense_shares,
            "shares_released_to_date": shares_released_count,
            "fully_paid": self.principal_balance == 0
        }
    ```
  </Tab>
</Tabs>

## Multi-Loan Example

Here's a complete example with two loans:

```python theme={null}
# Loan 1: Original ESOP loan from 2020
loan_2020 = ESOPLoan(
    loan_id="LOAN_2020_INITIAL",
    origination_date=date(2020, 1, 1),
    original_principal=3_000_000,
    principal_balance=2_100_000,  # Some paid down
    interest_rate=0.065,
    term_years=10,
    payment_schedule='amortizing',
    original_suspense_shares=30_000,
    suspense_shares=21_000,  # 9,000 released so far
    lender="Local Bank",
    loan_purpose="initial_esop_purchase"
)

# Loan 2: Refinancing loan from 2023
loan_2023 = ESOPLoan(
    loan_id="LOAN_2023_REFI",
    origination_date=date(2023, 6, 1),
    original_principal=2_000_000,
    principal_balance=1_900_000,
    interest_rate=0.070,
    term_years=8,
    payment_schedule='amortizing',
    original_suspense_shares=15_000,
    suspense_shares=14_250,  # 750 released so far
    lender="Regional Credit Union",
    loan_purpose="refinancing"
)

# Process payments for year 2025
result_1 = loan_2020.process_payment(
    principal_payment=300_000,
    interest_payment=136_500
)
# Releases: 30,000 * (300,000 / 3,000,000) = 3,000 shares

result_2 = loan_2023.process_payment(
    principal_payment=200_000,
    interest_payment=133_000
)
# Releases: 15,000 * (200,000 / 2,000,000) = 1,500 shares

# Total shares released in 2025: 4,500
# Total debt payment: $769,500 ($500K principal + $269.5K interest)
```

## Integration with ESOPTrust

The `ESOPTrust` aggregates all loans:

```python theme={null}
trust = ESOPTrust(
    loans=[loan_2020, loan_2023],
    ...
)

# Total suspense shares across all loans
total_suspense = trust.total_suspense_shares()
# = 21,000 + 14,250 = 35,250

# Total debt outstanding
total_debt = sum(loan.principal_balance for loan in trust.loans)
# = 2,100,000 + 1,900,000 = 4,000,000

# Process all loan payments for the year
for loan in trust.loans:
    principal, interest = loan.calculate_annual_payment(current_year)
    result = loan.process_payment(principal, interest)
    trust.unallocated_shares += result.shares_released
```

## Best Practices

<CardGroup cols={2}>
  <Card title="Track Original Values" icon="clock">
    Always store `original_principal` and `original_suspense_shares` for accurate release calculations
  </Card>

  <Card title="Validate Releases" icon="shield-check">
    Ensure released shares never exceed suspense shares
  </Card>

  <Card title="Document Purpose" icon="file-lines">
    Record why each loan was taken (purchase, refinancing, expansion)
  </Card>

  <Card title="Monitor Ratios" icon="chart-line">
    Track debt-to-equity and ensure sustainable debt levels
  </Card>
</CardGroup>

## Common Issues

<AccordionGroup>
  <Accordion title="Cross-Loan Share Release" icon="triangle-exclamation">
    **Problem:** Accidentally releasing shares from Loan B when paying Loan A.

    **Solution:** Each loan owns its shares. Never aggregate suspense shares.
  </Accordion>

  <Accordion title="Rounding Errors" icon="calculator">
    **Problem:** Share releases don't add up due to rounding.

    **Solution:** Use high-precision decimals and track cumulative releases.
  </Accordion>

  <Accordion title="Balloon Payment Shock" icon="bomb">
    **Problem:** Large balloon payment creates cash crisis.

    **Solution:** Model balloon loans carefully and plan cash reserves.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Share Pool Calculation" icon="shapes" href="/simulation/step-2-share-pool">
    See how loan share releases feed into allocation
  </Card>

  <Card title="ESOPTrust" icon="building-columns" href="/models/esop-trust">
    How loans fit into the trust structure
  </Card>
</CardGroup>
