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.
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.
# BAD: All suspense shares in one pooltrust = { "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
Loan-Specific Suspense (Correct)
Copy
Ask AI
# GOOD: Each loan owns its sharesloan_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
When a loan payment is made, shares are released proportionally to the principal paid:
Copy
Ask AI
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# Exampleloan = 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 principalshares_released = calculate_share_release(loan, 300_000)# = 30,000 * (300,000 / 3,000,000)# = 30,000 * 0.10# = 3,000 shares# Update loanloan.principal_balance -= 300_000 # 2,400K → 2,100Kloan.suspense_shares -= 3_000 # 30,000 → 27,000
ERISA Requirement: Shares must be released proportionally as the loan is repaid. This prevents “back-loading” where all shares are released at the end.
Interest-only payments with principal due at maturity.
Copy
Ask AI
loan = ESOPLoan( original_principal=3_000_000, interest_rate=0.065, term_years=10, payment_schedule='balloon')# Years 1-9: Interest onlyannual_interest = 3_000_000 * 0.065 # $195,000# Year 10: Interest + full principalfinal_payment = 195_000 + 3_000_000 # $3,195,000# Share release: All at once in year 10
Risk: Balloon payments create large share releases and cash needs in final year. Plan carefully!
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 )
Copy
Ask AI
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)
trust = ESOPTrust( loans=[loan_2020, loan_2023], ...)# Total suspense shares across all loanstotal_suspense = trust.total_suspense_shares()# = 21,000 + 14,250 = 35,250# Total debt outstandingtotal_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 yearfor loan in trust.loans: principal, interest = loan.calculate_annual_payment(current_year) result = loan.process_payment(principal, interest) trust.unallocated_shares += result.shares_released