'Interest Accrued' contract flow
Overviews the contract workflow for how and when InterestAccrued is updated
Prior advised reading and definitions: 'finance view' of how accrued interest is calculated in our contracts.
The term 'InterestAccrued' is the Interest owed by a Borrower but not yet repaid to the Line of Credit contract and made available for withdrawal by a Lender.
Steps 2 - 5 below deal with calculating calculating accrued interest in order to update
InterestAccrued
for a single credit position id as either a direct result of the external function request (step 1) or indirectly as a result of another action such as a change in the balance on a credit line id.Step 1 is an external function that updates the accrued interest for all credit position ids in a Line of Credit facility
This external function loops over all credit position ids and calls related internal functions during which InterestRateCredit.sol is called with the id data and then i
nterestAccrued
is updated. function accrueInterest() external override returns(bool) {
uint256 len = ids.length;
bytes32 id;
for (uint256 i; i < len; ++i) {
id = ids[i];
Credit memory credit = credits[id];
credits[id] = _accrue(credit, id);
}
return true;
}
This internal function runs within step 1 or otherwise at any time the balance on a credit line changes or the interest rates are changed by mutual consent between a Borrower and a Lender.
function _accrue(Credit memory credit, bytes32 id) internal returns (Credit memory) {
if (!credit.isOpen) {
return credit;
}
return CreditLib.accrue(credit, id, address(interestRate));
}
Called by
_accrue()
in step 2 above any time the balance on a credit position changes or the interest rates are changed by mutual consent between a Borrower and a Lender.It returns an updated token denominated
interestAccrued
for a single id.It does so by adding the new amount of interest to accrue to the prior amount of
interestAccrued
recorded.This new amount of interest to accrue is called
accruedToken
and is calculated in InterestRateCredit.sol (see steps 4 and 5 below).function accrue(
ILineOfCredit.Credit memory credit,
bytes32 id,
address interest
) public returns (ILineOfCredit.Credit memory) {
unchecked {
// interest will almost always be less than deposit
// low risk of overflow unless extremely high interest rate
// get token demoninated interest accrued
uint256 accruedToken = IInterestRateCredit(interest).accrueInterest(id, credit.principal, credit.deposit);
// update credit line balance
credit.interestAccrued += accruedToken;
emit InterestAccrued(id, accruedToken);
return credit;
}
}
}
This is the main function for calculating the amount by which
interestAccrued
should be updated for a single credit position id, callable indirectly by _accrue()
in LineOfCredit.sol (step 2 above) and then subsequently directly by accrue()
in CreditLib.sol (step 3)function accrueInterest(
bytes32 id,
uint256 drawnBalance,
uint256 facilityBalance
) external override onlyLineContract returns (uint256) {
return _accrueInterest(id, drawnBalance, facilityBalance);
}
Finally, this is where the amount by which
interestAccrued should be updated
is calculated per credit position id. function _accrueInterest(bytes32 id, uint256 drawnBalance, uint256 facilityBalance) internal returns (uint256) {
Rate memory rate = rates[id];
uint256 timespan = block.timestamp - rate.lastAccrued;
// update last timestamp in storage
rates[id].lastAccrued = block.timestamp;
return (_calculateInterestOwed(rate.dRate, drawnBalance, timespan) +
_calculateInterestOwed(rate.fRate, (facilityBalance - drawnBalance), timespan));
}
function _calculateInterestOwed(
uint256 bpsRate,
uint256 balance,
uint256 timespan
) internal pure returns (uint256) {
return (bpsRate * balance * timespan) / INTEREST_DENOMINATOR;
}
last updated Dec 29 2022
Last modified 1mo ago