The aim of this document is to provide high-level documentation of the loan smart contract. It gives an overall picture of the operations done in the smart contract. It does not focus on technical or financial details.
For the installment plan calculation and more detailed financial flow, details see Loan installment plan calculation.
For the posting listing see Personal loan postings.
For the debt manager postings sequences with the examples see https://safibank.atlassian.net/wiki/spaces/ITArch/pages/114819318/Debt+Manager+Documentation#Debt-manager-postings.1.
The deployment of smart contracts is described at Deployment of smart contracts.
Installment plan calculation
In the smart contract, we often need the loan installment plan. It is used mainly for the allocation of overdue payments and for getting the right installment number for various postings.
Since it is not recommended to store the installment plan directly as a TM parameter, we have to calculate it using the parameters that are available in the TM.
The early repayments and associated changes of the EMI are handled using time series of emi
and early_repayment
parameters.
The installment plan calculation is located in loan/features/installment_plan.py
in the smart contract source code directory. The calculation itself is done by get_installments
method, the assignment of already paid amounts is done by get_installments_with_paid_amounts
and the current installment number is calculated by get_installment_by_remaining_principal
method.
Schedules
There are three schedules in the smart contract - interest accruing, due date, and overdue date schedules. All the schedules are planned using execution_schedules
hook and executed by the execution_schedules
hook.
Interest accruing
The schedule runs every day at 00:00:01
local Philippines time.
It calculates the daily interest rate and increases the ACCRUED_INTEREST
address accordingly.
Due date schedule
The schedule runs on the loan due date at 00:01:00
local Philippines time.
On this schedule, the accrued interest is rounded to two decimal places and transferred to the INTEREST_DUE
address. Using the installment plan the current installment principal amount is got and it is transferred to the PRINCIPAL_DUE
address.
If there is a nonzero prepaid amount, it is used to pay the due amounts.
As the last step, the Kafka event with the remaining due amounts is emitted. It is used by the service to perform an auto deduction.
Overdue date schedule
The schedule runs on the loan due date at 23:59:00
local Philippines time.
The schedule checks if there is a nonzero due interest and principal. If there is any, it transfers due amounts to the overdue addresses.
The debt manager postings are posted to deduct the debt immediately after there are enough funds on the main and pocket accounts.
Incoming transactions
There are multiple types of transactions that are accepted by the smart contract. All the others are rejected. The rejections are implemented in pre_posting_code
hook and the following logic in post_posting_code
hook.
Regular and debt repayment
The regular payments are initiated by the loan-manager and the debt payments are initiated by the debt manager. They are the same from the view of the smart contract.
The payment is rejected if it is greater than the outstanding payments amount.
The overdue installments are repaid first. The smart contract goes through all overdue installments and it repays the installment followed by the principal until the whole repayment is used or the overdue installments are completely paid.
If the repayment is not fully used, the due installment is paid in the same order - the interest at first followed by the principal.
If the all planned installments are fully paid, the Kafka event message is sent to notify the service about loan closure.
The implementation is done in handle_regular_repayment
method in loan/features/repayment.py
.
Early repayment
The early repayment can be performed on the loan where are no outstanding payments only.
The already accrued interest is collected, rounded and moved to the interest due. The principal is transferred to the principal due so the sum of the interest due and the principal due equals the amount of the early repayment.
The installment plan parameters are not updated here. The installment plan is always calculated based on the parameters set up by the loan-manager as the account instance parameters.
If the loan is fully paid after the early repayment, the Kafka event message is sent to notify the service about loan closure.
The prepayment amount is not touched by the early repayment except the situation when the early repayment together with the prepayment is enough to repay to whole loan. In that situation the loan is fully repaid.
The implementation is done in handle_early_repayment
method in loan/features/repayment.py
.
Prepayment
The prepayment can be performed on the loan where are no outstanding payments only. The incoming funds are moved to the PREPAID
address and the Kafka message with the new prepayment amount is emitted.
The implementation is done in handle_prepayment
method in loan/features/repayment.py
.
Debug postings
The debug postings are used to bypass the restrictions and allows to send arbitrary postings the loan. The main purpose of these postings is to allow fix of the loan in inconsistent state and to perform various debug scenarios.
This postings are allowed when the debug mode is enabled by the global parameter only.
Account opening
After the loan opening, the principal is transferred to the deposit account - the customer’s main account.
If there is an opening fee it is deducted from the deposit account. Since the opening fee is always smaller than the principal, this operation cannot fail.
The implementation is done in post_activate_code
hook.
Account closing
Before closing the account the total outstanding debt is checked and it is rejected if there is an outstanding debt. The marked paid interest is moved to the internal bank account.
The implementation is done in close_code
hook.
Loan account addresses
Address | Value | Description |
---|---|---|
PRINCIPAL | Positive | The remaining principal do be paid. The sum of all future installment principals. It is partially moved to the PRINCIPAL_DUE on the due date. |
PRINCIPAL_DUE | Positive | The principal of current unpaid installment. The value stays here for the due day only. It is moved to the PRINCIPAL_OVERDUE after one day. |
PRINCIPAL_OVERDUE | Positive | The sum of all overdue installments principal. |
ACCRUED_INTEREST | Positive | The accrued interest. It is fully moved to the INTEREST_DUE on the due date. |
INTEREST_DUE | Positive | The interest of current unpaid installment. The value stays here for the due day only. It is moved to the INTEREST_OVERDUE after one day. |
INTEREST_OVERDUE | Positive | The sum of all overdue installments interest. |
INTEREST_PAID | Negative | The total value of the already paid interest. |
INTERNAL_CONTRA | Positive | The contra address for the interest accruing. It is the target on interest accruing and source on interest paying. |
PREPAID | Negative | The total prepaid amount. It is used on due date to pay the loan. |
DEFAULT | Negative | The default address for all incoming postings. It should be zero after the incoming postings are processed. |