Rates

Interest rate primitives — compounding, discounting, log returns, APR↔APY conversions, and closed-form / iterative yield calculations. Built on top of DeFiMath's exp, ln, expm1, and log1p.

Contract: Rates.sol

Functions

FunctionGasDescription
compoundInterest467Continuous compounding: P · e^(r·t)
presentValue519Discounting: FV · e^(−r·t)
logReturn591ln(currentPrice / previousPrice)
continuousToDiscrete509e^apr − 1 (APR → APY)
discreteToContinuous590ln(1 + apy) (APY → APR)
yieldToMaturity736Zero-coupon YTM (closed form)
internalRateOfReturn17k–49kIRR via Newton-Raphson (scales with cashflow count)

npm install defimath-lib

Conventions

  • Continuous compounding throughout. All rate inputs are interpreted as continuous APRs unless the function name says otherwise.
  • principal, futureValue, priceuint128, 18-decimal fixed-point (1e18 = 1.0).
  • rate, apr, apy — annualized as 18-decimal fixed-point. APR/APY conversions take int256 (signed).
  • timeInterval, timeToMaturityuint32, seconds.
  • internalRateOfReturn takes parallel cashflows[] and times[] arrays plus an initial guess for Newton-Raphson.
  • All functions are internal pure.

Quick example

solidity
import "defimath-lib/contracts/finance/Rates.sol";

// Continuous compounding: how much does principal grow in 1 year at 5%?
uint256 fv = DeFiMathRates.compoundInterest(1_000e18, 0.05e18, 365 days);

// Discount a future cashflow back to today.
uint256 pv = DeFiMathRates.presentValue(fv, 0.05e18, 365 days);

// Convert continuous APR (5%) to effective APY.
int256 apy = DeFiMathRates.continuousToDiscrete(int256(0.05e18));

Important notes

  • compoundInterest and presentValue are exact inverses. Round-tripping a value through both reconstructs the original up to the underlying exp precision (~5e-14).
  • APR ↔ APY both use precision-preserving primitives. continuousToDiscrete uses expm1; discreteToContinuous uses log1p. Safe to call with small rates without precision loss.
  • yieldToMaturity is closed-form and cheap; internalRateOfReturn is iterative. Use YTM for zero-coupon bonds (a single ln). Use IRR for arbitrary cashflow schedules — but expect 17k–49k gas depending on cashflow count, and supply a reasonable guess to stay within the iteration budget.
  • IRR can fail to converge. Pathological cashflow sets (no real IRR, or multiple sign changes) revert with NoConvergenceError. The solver caps at 50 Newton-Raphson iterations.

Limits & errors

ConstantValue
MIN_PRINCIPAL1e-6 (smallest allowed principal / future value)
MAX_PRINCIPAL1e15 (largest allowed principal / future value)
MAX_TIME_INTERVAL2 years (63,072,000 seconds)
MAX_RATE400% annual (4e18)
MAX_CASHFLOWS1024 (IRR gas-bomb guard)
IRR_MAX_ITER50 (Newton-Raphson iteration cap)
IRR_TOLERANCE~1e-8 convergence threshold
ErrorTrigger
PrincipalLowerBoundErrorprincipal ≤ MIN_PRINCIPAL
PrincipalUpperBoundErrorprincipal ≥ MAX_PRINCIPAL
RateUpperBoundErrorrate ≥ MAX_RATE
RateLowerBoundErrorSigned-rate conversions below allowed minimum
TimeIntervalUpperBoundErrortimeInterval ≥ MAX_TIME_INTERVAL
PriceLowerBoundErrorlogReturn when a price is below minimum
PriceUpperBoundErrorlogReturn when a price exceeds maximum
ArrayLengthMismatchErrorinternalRateOfReturn when cashflows[] and times[] differ in length
ArrayLengthOutOfBoundsErrorCashflow array too short or too long
NoConvergenceErrorinternalRateOfReturn fails to converge
InvalidBondPriceErroryieldToMaturity when price ≥ face value