Skip to main content

Interest Payment & Dividends

The Interest Payment contract (InterestPayment.sol) provides a comprehensive solution for both interest-based payment schedules for loans backed by RestrictedLockupTokens and dividend distribution functionality for equity-like payments. This unified contract replaces the deprecated Dividends contract while maintaining backward compatibility through the IDividends interface. Administrative permissions are enforced via a pre-deployed external AccessControl contract referenced by the token and payment modules.

Key Features

Interest Payment Features

  • Configurable interest accrual start and end timestamps
  • Ability to create multiple payment periods with different interest rates
  • Admin can fund interest payments and force claim interest on behalf of token holders
  • Token holders can claim interest based on their ownership during specific periods
  • Support for principal amount funding and claiming at maturity
  • Comprehensive admin controls for managing interest distributions

Dividend Distribution Features

  • Snapshot-based distributions: Dividends are distributed based on token holdings at specific timestamps
  • Multiple token support: Distribute any ERC-20 token (USDC, DAI, etc.) as dividends
  • Proportional allocation: Dividends are allocated proportionally to token ownership at snapshot time
  • Batch operations: Efficient batch claiming and funding operations for multiple snapshots
  • Flexible funding: Multiple dividend rounds can be funded for the same snapshot timestamp
  • Audit trail: Complete tracking of funded, claimed, and unclaimed dividend amounts per snapshot
  • Integration with SnapshotPeriods: Leverages the same snapshot system used for interest calculations

How It Works

Interest payments are distributed to recipients based on their proportional ownership of the RestrictedLockupToken at specific time periods and the configured interest rates for each period. The contract keeps track of token ownership through the SnapshotPeriods contract, which records token balances at different timestamps. Interest rates can be set differently for each payment period, allowing for flexible interest payment schedules. Role checks (e.g., Transfer Admin, Contract Admin) are routed to the external AccessControl contract.

  1. Anyone funds the interest payment contract with a payment token (e.g., USDC) by calling fundInterest().
  2. Transfer Admin creates payment periods using createPaymentPeriod(), defining the start and end timestamps, interest rate, and interest rate period duration for the period.
  3. Token holders can claim their interest by calling claimInterest(amount) or claimInterestForPeriod(periodIdx, amount) with an optional amount cap.
  4. The contract calculates the amount of interest due based on the token holder's time-weighted ownership and the configured interest rate for each period.
  5. Interest is transferred to the token holder from the contract.

Principal Amount Management

The contract also supports principal amount management with partial operations:

  1. Transfer Admin can fund principal amounts using fundPrincipal().
  2. Token holders can claim their principal at maturity by calling claimPrincipal(amount):
    • amount = 0: Claims all available principal for the token holder
    • amount > 0: Claims exactly the specified amount (must be divisible by principalAmountPerToken)
  3. Transfer Admin can reclaim unused principal using reclaimPrincipal(amount):
    • amount = 0: Reclaims all unused principal
    • amount > 0: Reclaims exactly the specified amount
  4. The principal amount per token is set during contract deployment.

This diagram illustrates the principal funding and claiming process:

  1. Approve Funding: The Transfer Admin first approves the Interest Payment contract to spend payment tokens (like USDC) from their account.

  2. Fund Principal: The Transfer Admin calls fundPrincipal() with the amount to fund, which must be divisible by restrictedToken.totalSupply().

  3. Wait for Maturity: Principal can only be claimed after reaching the maturity date (defined by interestAccrualEndTimestamp).

  4. Token Holder Approval: To claim principal, the token holder must first approve the Interest Payment contract to transfer their security tokens.

  5. Claim Principal: The token holder calls claimPrincipal(amount), where:

    • amount = 0: Claims all available principal for their tokens
    • amount > 0: Claims the specific amount (must be divisible by principalAmountPerToken)
  6. Token Burn: The corresponding security tokens are burned from the token holder, effectively redeeming them.

  7. Principal Payment: The requested principal amount in payment tokens is transferred to the token holder.

This process allows token holders to redeem their security tokens for the principal amount at maturity, similar to how a bond works in traditional finance.

Dividend Distribution Functionality

The InterestPayment contract also provides comprehensive dividend distribution capabilities through the IDividends interface. This allows the same contract to handle both debt-like interest payments and equity-like dividend distributions.

How Dividend Distribution Works

Dividends are distributed based on historical token ownership at specific timestamps (snapshots). This approach ensures fair distribution regardless of when dividends are actually funded or claimed.

Key Dividend Operations

Funding Dividends

// Fund dividends for a specific snapshot timestamp
interestPayment.fundDividend(
dividendTokenAddress, // e.g., USDC contract address
dividendAmount, // Total amount to distribute (must be divisible by total supply)
snapshotTimestamp // Historical timestamp for ownership calculation
);

Requirements:

  • Dividend amount must be evenly divisible by the total token supply at the snapshot
  • Snapshot timestamp must be valid (within the contract's operational range)
  • Caller must have Transfer Admin role
  • Dividend token must be a valid ERC-20 contract

Claiming Dividends

// Individual claim
interestPayment.claimDividend(dividendTokenAddress, snapshotTimestamp);

// Batch claim across multiple snapshots
uint256[] memory timestamps = [timestamp1, timestamp2, timestamp3];
interestPayment.batchClaimDividend(dividendTokenAddress, timestamps);

Querying Dividend Information

// Check unclaimed dividend amount for an address
uint256 unclaimed = interestPayment.unclaimedBalanceAt(
dividendTokenAddress,
holderAddress,
snapshotTimestamp
);

// Check total dividend amount available to claim (claimed + unclaimed)
uint256 totalAwarded = interestPayment.totalAwardedBalanceAt(
dividendTokenAddress,
holderAddress,
snapshotTimestamp
);

// Check how much dividend funding is available for a snapshot
uint256 totalFunds = interestPayment.tokensAt(dividendTokenAddress, snapshotTimestamp);

Dividend Allocation Logic

Dividends are allocated proportionally based on token ownership at the snapshot timestamp:

Holder's Dividend = (Holder's Token Balance at Snapshot / Total Supply at Snapshot) × Total Dividend Amount

Example:

  • Total supply at snapshot: 1,000,000 tokens
  • Holder owns: 50,000 tokens (5%)
  • Total dividend funded: 100,000 USDC
  • Holder's share: 5,000 USDC

Multiple Dividend Rounds

The system supports multiple dividend distributions for the same snapshot:

// Initial dividend funding
interestPayment.fundDividend(usdcAddress, 100000e6, snapshotTimestamp);

// Additional dividend funding for same snapshot
interestPayment.fundDividend(usdcAddress, 50000e6, snapshotTimestamp);

// Total available dividends: 150,000 USDC

Integration with Interest Payments

The unified contract design allows sophisticated scenarios:

  1. Quarterly Dividends: Regular dividend distributions based on quarterly snapshots
  2. Interest + Dividends: Simultaneous debt service payments and equity distributions
  3. Special Distributions: One-time dividend payments for specific events
  4. Multi-Token Distributions: Different dividend tokens (USDC, DAI, etc.) for different purposes

Example: Complete Dividend Cycle

// 1. End of quarter - snapshot timestamp is recorded automatically
uint256 quarterEndTimestamp = block.timestamp;

// 2. Company profits are calculated off-chain
uint256 quarterlyProfits = 500000e6; // 500,000 USDC

// 3. Admin funds dividend distribution
usdcToken.approve(interestPaymentAddress, quarterlyProfits);
interestPayment.fundDividend(usdcAddress, quarterlyProfits, quarterEndTimestamp);

// 4. Token holders claim their dividends
interestPayment.claimDividend(usdcAddress, quarterEndTimestamp);

This dividend functionality transforms the InterestPayment contract into a comprehensive tool for both debt and equity token management.

Advanced Administrative Functions

The Interest Payment contract provides several advanced administrative functions to adjust the terms of the interest and principal payments after deployment:

Extending Maturity (shiftInterestAccrualEnd)

The shiftInterestAccrualEnd(timestamp) function allows the Contract Admin or Transfer Admin to extend the maturity date by updating the interestAccrualEndTimestamp. This is particularly useful when:

  • The original maturity date needs to be extended due to business requirements
  • The loan or bond term is being renegotiated
  • Regulatory requirements necessitate a modification to the maturity date

The new timestamp must be greater than the current interestAccrualEndTimestamp, ensuring that maturity can only be extended, not reduced.

Managing Interest for Payment Periods

Creating Payment Periods (createPaymentPeriod)

When creating payment periods with createPaymentPeriod(startTimestamp, endTimestamp, interestRate, interestRatePeriodDuration), the following requirements must be met:

  • Periods must be created sequentially, with no gaps between them
  • The end timestamp of one period must be the start timestamp of the next period
  • The first period must start at interestAccrualStartTimestamp
  • Each period's end timestamp must be a multiple of interestRatePeriodSeconds from the start timestamp, except for the final period which may end at interestAccrualEndTimestamp
  • Periods cannot be created for timestamps before interestAccrualStartTimestamp or after interestAccrualEndTimestamp
  • Interest rates cannot exceed maxInterestRate if set (0 means no limit)

This sequential creation ensures continuous tracking of token ownership across the entire interest accrual timeframe. Interest is calculated dynamically based on the rate and time-weighted token ownership rather than fixed amounts.

Updating Interest Rate for a Period (updateInterestRateForPeriod)

The updateInterestRateForPeriod(periodIdx, interestRate, interestRatePeriodDuration) function allows the Transfer Admin to modify the interest rate for a specific payment period before it starts. This enables:

  • Correcting interest rate configurations
  • Adjusting rates due to changing market conditions
  • Setting interest rate to zero for periods where no interest should accrue

Important: Interest rates can only be updated before the period starts (i.e., before block.timestamp > period.startTimestamp). The new rate cannot exceed maxInterestRate if set.

Setting a period's interest rate to zero effectively means that no token holder will accrue interest during that period, regardless of their token ownership. This can be useful for:

  • Implementing grace periods
  • Reflecting periods of non-performance
  • Handling special situations where interest payments should be suspended

Managing Maximum Interest Rate (setMaxInterestRate)

The setMaxInterestRate(maxInterestRate) function allows the Contract Admin to set a maximum interest rate cap. When set to 0, there is no limit on interest rates. This provides:

  • Protection against accidentally setting excessively high interest rates
  • Governance control over maximum borrowing costs
  • Flexibility to adjust rate caps as market conditions change

These administrative functions provide considerable flexibility in managing the lifecycle of interest-bearing security tokens, allowing adjustments to both principal and interest terms while maintaining the integrity of the payment system.

Reclaiming Interest and Principal

In cases where interest or principal funds need to be reclaimed, administrators can use several functions to reclaim unused funds. This is often necessary in scenarios such as contract migration, correction of funding errors, or legal compliance requirements.

Reclaiming Interest

The Interest Payment contract provides multiple ways to reclaim interest:

  1. Setup: Contract Admin sets the reclaimer address that will receive all reclaimed funds
  2. Pause: Transfer Admin pauses payment for the specific period being reclaimed
  3. Reclaim Options:
    • reclaimInterest(wallet, paymentPeriodIdx): Reclaims unclaimed interest from a specific wallet for a period
    • reclaimInterestForAllRecipients(paymentPeriodIdx): Reclaims all unclaimed interest for an entire period
    • reclaimTotalInterest(amount): Reclaims a specific amount of unused interest
  4. Unpause: Transfer Admin unpauses payment for the period after reclaiming is complete

Reclaiming Principal

The principal amount can also be reclaimed if needed:

  1. Setup: Contract Admin sets the reclaimer address that will receive reclaimed funds
  2. Pause: Transfer Admin pauses the entire contract
  3. Reclaim: Transfer Admin reclaims all unused principal funds
  4. Unpause: Transfer Admin unpauses the contract after reclaiming is complete

Important Considerations

  • A valid reclaimer address must be set before any reclaiming can occur
  • Pausing before reclaiming prevents users from claiming during the reclaim process
  • Unpausing after reclaiming allows normal operations to resume
  • Only Transfer Admin can reclaim funds, while Contract Admin can set the reclaimer address
  • Reclaimed funds are transferred directly to the reclaimer address

Early Repayment

The Interest Payment contract supports early repayment functionality, allowing Contract Admin or Transfer Admin to trigger an early maturity event. This feature is useful in scenarios such as:

  • Refinancing debt at a lower interest rate
  • Restructuring financial obligations
  • Implementing callable bonds that can be paid off before maturity
  • Responding to changes in market conditions

The earlyRepayment(timestamp) function performs two key actions:

  1. Sets the interest accrual end timestamp to the specified timestamp, effectively stopping any further interest accrual
  2. Pauses payment after the specified timestamp to provide administrative control over final payments

When early repayment is triggered:

  • Interest stops accruing at the specified timestamp, freezing the total interest amount
  • Token holders can still claim their accrued interest up to the repayment timestamp
  • Principal becomes available for claiming immediately (assuming it has been funded)
  • The EarlyRepayment event is emitted, recording the admin address and timestamp

This feature provides important flexibility in managing debt instruments represented by the token, allowing administrators to respond to changing financial conditions while preserving token holders' rights to receive their accrued interest and principal.

Force Claiming Interest

The Interest Payment contract provides administrative functions to force claim interest on behalf of wallet addresses. This is particularly useful in scenarios such as:

  • Processing interest distributions for wallets that may not have the means to claim independently
  • Managing automated distributions for institutional or managed accounts
  • Handling special settlement cases requiring administrative intervention
  • Distributing interest from paused payment periods for specific wallets

Two administrative force claim functions are available:

Force Claim for Specific Period (forceClaimForPeriod)

The forceClaimForPeriod(wallet, periodIdx, amount) function allows the Transfer Admin to force claim interest for a specific wallet from a specific payment period:

  • If the amount parameter is set to 0, all available interest for that wallet and period will be claimed
  • If the amount parameter is greater than 0, only that amount will be claimed (up to the available claimable amount)
  • This function works even for paused payment periods, providing administrative override capability
  • The ForceClaimed event is emitted with details of the transfer admin, recipient wallet, amount, and period index

Force Claim Across All Periods (forceClaim)

The forceClaim(wallet, amount) function allows the Transfer Admin to force claim interest for a specific wallet across all eligible payment periods:

  • Similar to forceClaimForPeriod, if amount is 0, all available interest is claimed
  • If amount is greater than 0, the function will claim up to that amount, potentially across multiple periods
  • The function processes periods sequentially, and will stop once the specified amount is reached
  • This function also works for paused payment periods
  • The ForceClaimed event is emitted for each period from which interest is claimed

Admin Functions

The Interest Payment contract has several admin functions for managing interest payments:

  • createPaymentPeriod(startTimestamp, endTimestamp, interestRate, interestRatePeriodDuration): Creates a new payment period with specified interest rate.
  • updateInterestRateForPeriod(periodIdx, interestRate, interestRatePeriodDuration): Updates the interest rate for a specific period before it starts.
  • setMaxInterestRate(maxInterestRate): Sets the maximum allowed interest rate (Contract Admin only).
  • fundInterest(amount): Funds the contract with interest payment tokens.
  • claimInterest(amount): Allows token holders to claim interest across all payment periods, with optional amount cap (0 for all available).
  • claimInterestForPeriod(periodIdx, amount): Enables token holders to claim interest for a specific payment period, with optional amount cap.
  • batchClaimInterestForPeriods(periodIdxs[], amount): Allows token holders to claim interest for multiple payment periods in a single transaction, with optional amount cap.
  • reclaimInterest(wallet, amount): Reclaims unclaimed interest from a wallet across all periods, with optional amount cap.
  • reclaimInterestForPeriod(wallet, paymentPeriodIdx, amount): Reclaims unclaimed interest from a wallet for a specific period, with optional amount cap.
  • batchReclaimInterest(wallet, periodIdxs[], amount): Reclaims unclaimed interest from a wallet for multiple periods, with optional amount cap.
  • reclaimInterestForAllRecipients(paymentPeriodIdx): Reclaims all unclaimed interest for a period.
  • reclaimTotalInterest(amount): Reclaims a specific amount of unused interest.
  • pausePaymentPeriod(periodIdx) and unpausePaymentPeriod(periodIdx): Pauses or unpauses claiming for a specific period.
  • pausePaymentAfter(timestamp): Pauses claiming after the given timestamp.
  • unpausePaymentAfter(): Unpause claiming.
  • pause(isPaused): Pauses or unpauses the entire contract.
  • shiftInterestAccrualEnd(timestamp): Updates the end timestamp for interest accrual for all payment periods. This allows the Transfer Admin to extend the maturity day.
  • setReclaimerAddress(reclaimerAddress): Sets the address that is authorized to receive reclaimed interest. This address must be set before any reclaim operations can be performed.
  • fundPrincipal(amount): Transfers principal payment tokens to the contract for distribution to token holders at maturity.
  • claimPrincipal(amount): Allows token holders to claim their principal amount at maturity based on their token holdings. Amount parameter: 0 = claim all available, >0 = claim specific amount.
  • reclaimPrincipal(amount): Enables the Transfer Admin to reclaim unclaimed principal amounts from the contract. Amount parameter: 0 = reclaim all available, >0 = reclaim specific amount.
  • earlyRepayment(timestamp): Allows the Contract Admin or Transfer Admin to trigger early repayment of the loan at a specific timestamp. If timestamp is 0, uses current block timestamp.
  • forceClaim(wallet, amount): Allows Transfer Admin to force claim interest for a specific wallet across all payment periods, with optional amount cap (0 for all available).
  • forceClaimForPeriod(wallet, periodIdx, amount): Enables Transfer Admin to force claim interest for a specific wallet and payment period, with optional amount cap (0 for all available).

Interest Accrual and Calculation

The contract provides several view functions to check accrued interest:

  • totalAccruedInterest(): Returns the total accrued interest at the current time.
  • totalAccruedInterestAt(timestamp): Returns the total accrued interest at a specific timestamp.
  • accruedInterest(account): Returns the accrued interest for a specific account.
  • accruedInterestAt(account, timestamp): Returns the accrued interest for a specific account at a specific timestamp.
  • accruedInterestForPeriod(account, periodIdx): Returns the accrued interest for a specific account in a specific payment period.
  • paymentPeriodsCount(): Returns the total number of payment periods that have been created.
  • periodTotalInterest(periodIdx): Returns the total interest amount that was accrued during a specific payment period.
  • periodTotalClaimedInterest(periodIdx): Returns the total amount of interest that has been claimed by token holders for a specific payment period.
  • periodTotalReclaimedInterest(periodIdx): Returns the total amount of interest that has been reclaimed by the admin for a specific payment period.
  • periodAvailableInterest(periodIdx): Returns the amount of interest that is still available to be claimed for a specific payment period.
  • periodDuration(periodIdx): Returns the duration (in seconds) of a specific payment period.
  • periodStartTimestamp(periodIdx): Returns the start timestamp of a specific payment period.
  • periodEndTimestamp(periodIdx): Returns the end timestamp of a specific payment period.
  • unclaimedAmountAt(receiver, timestamp): Returns the amount of unclaimed interest for a specific receiver at a given timestamp.
  • unclaimedAmountForPeriod(receiver, periodIdx): Returns the amount of unclaimed interest for a specific receiver in a specific payment period.
  • claimedAmountForPeriod(receiver, periodIdx): Returns the amount of interest that has been claimed by a specific receiver in a specific payment period.
  • reclaimedAmountForPeriod(receiver, periodIdx): Returns the amount of interest that has been reclaimed from a specific receiver in a specific payment period.
  • usedAmountForPeriod(receiver, periodIdx): Returns the total amount of interest that has been either claimed or reclaimed for a specific receiver in a specific payment period.
  • accountTotalClaimedAmount(receiver): Returns the total amount of interest that has been claimed by a specific receiver across all payment periods.
  • accountTotalReclaimedAmount(receiver): Returns the total amount of interest that has been reclaimed from a specific receiver across all payment periods.
  • totalInterestAmountFunded(): Returns the total amount of interest that has been funded to the contract.
  • totalInterestAmountClaimed(): Returns the total amount of interest that has been claimed by all token holders.
  • totalInterestAmountReclaimed(): Returns the total amount of interest that has been reclaimed by admins.
  • totalInterestAmountUnused(): Returns the total amount of interest that remains unused in the contract.
  • nearestInterestPaymentTimestampAt(timestamp): Returns the nearest interest payment timestamp at a given timestamp (rounded to period boundaries).
  • findPaymentPeriodIndex(startTimestamp, endTimestamp): Finds the index of a payment period that covers the specified time range.
  • paymentPeriodPaused(periodIdx): Returns whether a specific payment period is paused.
  • fundedPrincipalAmount(): Returns the total amount of principal that has been funded to the contract.
  • reclaimPrincipalAmount(): Returns the total amount of principal that has been reclaimed by the admin.
  • claimedPrincipalAmount(): Returns the total amount of principal that has been claimed by token holders.
  • totalAvailablePrincipalAmount(): Returns the total amount of principal that is still available to be claimed.
  • availablePrincipalAmount(account): Returns the amount of principal that is available to be claimed by a specific account.

Interest is accrued based on configurable interest rates and calculated using the formula:

interest = (time-weighted ownership * interestRatePerSecond * principalAmountPerToken) / PRECISION_FACTORS

Where:

  • time-weighted ownership = token balance × time period duration
  • interestRatePerSecond = (interestRate × INTEREST_RATE_PRECISION_FACTOR) / interestRatePeriodDuration
  • INTEREST_RATE_PRECISION_FACTOR = 1,000,000,000 for precision in interest rate calculations
  • BIPS_PRECISION = 10,000 for basis points calculations

The interest rate is specified in basis points (bips) where 10,000 bips = 100%. For example, a 5% annual interest rate would be specified as 500 bips.

Amount Parameter Behavior

All claiming and reclaiming functions support an amount parameter that allows users to specify how much they want to claim or reclaim:

  • amount = 0: Claims/reclaims all available funds
  • amount > 0: Claims/reclaims up to the specified amount, capped at available funds
  • If the specified amount exceeds available funds, the transaction will revert with InterestPayment_NotEnoughFundsToClaim

This provides fine-grained control over fund movements and enables partial claiming/reclaiming scenarios.

Principal Amount Parameter Behavior

Principal claiming and reclaiming functions also support an amount parameter for precise control:

For claimPrincipal(amount):

  • amount = 0: Claims all available principal for the token holder's current balance
  • amount > 0: Claims exactly the specified amount, with requirements:
    • Amount must not exceed the holder's available principal (tokenBalance × principalAmountPerToken)
    • Amount must be divisible by principalAmountPerToken to ensure exact token-to-principal conversion
    • Corresponding tokens are transferred: tokensToTransfer = amount / principalAmountPerToken

For reclaimPrincipal(amount):

  • amount = 0: Reclaims all unused principal from the contract
  • amount > 0: Reclaims exactly the specified amount, capped at available unused principal

This enables use cases such as:

  • Partial redemption of token positions
  • Staged principal withdrawals
  • Precise fund management for complex financial instruments

Error Handling

Administrative Errors

  • InterestPayment_InvalidRestrictedLockupTokenAddress: Thrown when attempting to deploy with an invalid token address
  • InterestPayment_InvalidTransferAdminAddress: Thrown when an invalid transfer admin address is provided
  • InterestPayment_InvalidPaymentPeriodSeconds: Thrown when payment period is set to zero
  • InterestPayment_InvalidReclaimerAddress: Thrown when attempting to set a zero address as reclaimer
  • InterestPayment_InvalidTimestamp: Thrown when providing an invalid timestamp for payment pausing
  • InterestPayment_InvalidPaymentToken: Thrown when payment token address is invalid
  • InterestPayment_InterestRateGreaterThanMaxInterestRate: Thrown when trying to set interest rate above max rate
  • InterestPayment_PeriodAlreadyStarted: Thrown when trying to update interest rate after period has started
  • InterestPayment_InterestRateNotChanged: Thrown when trying to update interest rate to the same value
  • InterestPayment_MaxInterestRateNotChanged: Thrown when trying to set max interest rate to the same value

Configuration Errors

  • InterestPayment_InvalidInterestAccrualStartTimestamp: Thrown when start timestamp is set to zero
  • InterestPayment_InvalidInterestAccrualEndTimestamp: Thrown when end timestamp is set to zero
  • InterestPayment_InvalidInterestAccrualPeriod: Thrown when start timestamp is greater than or equal to end timestamp
  • InterestPayment_CannotUnpauseAfterMaturity: Thrown when attempting to unpause payments after maturity
  • InterestPayment_PaymentNotPausedAfter: Thrown when trying to unpause when not paused

Period Management Errors

  • InterestPayment_InvalidPeriod: Thrown when referencing a non-existent period
  • InterestPayment_StartTimestampGreaterThanEndTimestamp: Thrown when creating a period with start after end
  • InterestPayment_StartTimestampBeforeAccrualStartTimestamp: Thrown when period starts before overall interest accrual start
  • InterestPayment_EndTimestampGreaterThanAccrualEndTimestamp: Thrown when period ends after overall interest accrual end
  • InterestPayment_NoPaymentPeriods: Thrown when attempting to claim interest when no payment periods have been created
  • InterestPayment_PeriodDurationNotMultipleOfInterestRatePeriod: Thrown when a payment period's duration does not align with the configured interest rate period. For example, if the interest rate period is set to 1 day (86400 seconds), then all payment periods must start and end at the same time of day. If interest accrual begins at 2025-01-01 12:00:00, then valid period boundaries would be 2025-01-01 12:00:00 to 2025-01-02 12:00:00, 2025-01-02 12:00:00 to 2025-01-03 12:00:00, etc. This ensures consistent interest accrual calculations across all periods.
  • InterestPayment_PeriodAlreadyExists: Thrown when attempting to create a duplicate period
  • InterestPayment_PeriodNotNext: Thrown when attempting to create a payment period that does not immediately follow the previous period. For example, if the last payment period ends at 2025-02-14 12:00:00, the next period must start at exactly that timestamp. Creating a period starting at 2025-02-24 12:00:00 would fail because it creates a gap in the payment schedule. This ensures continuous, sequential payment periods without any gaps in the interest accrual timeline.
  • InterestPayment_InvalidTotalAccruedInterest: Thrown when setting accrued interest below already claimed/reclaimed amount
  • InterestPayment_PaymentPeriodPaused: Thrown when attempting to claim from a paused period

Funding and Claiming Errors

  • InterestPayment_InvalidAmount: Thrown when attempting to fund with zero amount
  • InterestPayment_TokenSupplyIsZero: Thrown when token supply is zero during principal funding
  • InterestPayment_PrincipalAmountNotDivisibleByTokenSupply: Thrown when principal amount isn't divisible by token supply
  • InterestPayment_InvalidToken: Thrown when using an invalid token for payment
  • InterestPayment_InvalidFeeApplied: Thrown when token transfer results in unexpected balance
  • InterestPayment_NoFundsToClaim: Thrown when attempting to claim with no available funds
  • InterestPayment_NotEnoughFundsToClaim: Thrown when attempting to force claim more than available
  • InterestPayment_InvalidUnclaimedAmount: Thrown when unclaimed calculation produces invalid result
  • InterestPayment_NotEnoughFundedPrincipal: Thrown when attempting to claim more principal than available
  • InterestPayment_MaturityNotReached: Thrown when attempting to claim principal before maturity

These errors help ensure the contract operates correctly and provide clear feedback when operations cannot be completed. They enhance security by preventing invalid state changes and offer better debugging information than generic reverts.