The aim of this document is to describe the relationship between loan-manager and the loan smart contract backing the loan account. The single source of truth for the loan is the loan account in the TM. The loan-manager provides a REST API that controls the account and sends Kafka messages on various events.

Opening of the loan

The loan account is opened by the loan-manager using the TM Core API. This is implemented in openLoan activity of the OpenLoanWorkflow. At the loan opening, the following smart contract parameters are filled.

  • loan_start_date - Start of the loan contract terms.

  • principal - The agreed amount the customer will borrow from the bank.

  • fixed_interest_rate - The fixed annual rate of the loan.

  • emi - The agreed equated monthly installment.

  • total_term - The agreed length of the loan (in months).

  • deposit_account - The account to which the principal borrowed amount will be transferred.

  • first_installment_due_date - Due date of the first installment.

  • early_repayment - Contains all performed early repayments causing installment plan recalculation.

  • initial_fee - Initial fee for this loan account.

The installment plan in the smart contract is calculated independently from the loan-manager based on the parameters and incoming postings. The logic is described at https://safibank.atlassian.net/wiki/spaces/ITArch/pages/217842595/Loan+smart+contract+documentation#Installment-plan-calculation.

The installment plan is generated in the loan-manager too and it is stored in the database for caching purposes. Both the smart contract and loan-manager use the same logic to calculate the installment plan.

The database schema is shown at Personal loan database entities.

Auto deduction

When the loan installment is due, the Kafka event is generated as described in https://safibank.atlassian.net/wiki/spaces/ITArch/pages/217842595/Loan+smart+contract+documentation#Due-date-schedule.

The Kafka event contains the following properties.

  • account_id - the loan account id.

  • request_id - the idempotency key to be used to send the TM posting.

  • installment

    • number - Number of the due installment.

    • interest - Remaining interest to be paid using auto deduction.

    • principal - Remaining principal to be paid using auto deduction.

    • total - Total installment amount to be paid using auto deduction.

The loan-manager listens to this event using receiveWorkflowOperationRequest that calls handleAutomaticInstallmentDeduction. Both methods are in TMWorkflowInstanceCreateListener class. If the message contains a non-zero installment amount, the posting transferring money from the main account to the loan account is emitted using TM Postings Streaming API.

Sending an early repayment or prepayment

Both the early repayment and the prepayment are controlled using the RepayLoanWorkflow. The workflow ensures the effect of the repayment is the same as was presented to the customer. If there is a difference the repayment is rejected.

For all the repayments the posting is sent to the TM using the Postings Streaming API.

The transaction type is always LOAN_REPAYMENT and the repayment type is PREPAYMENT or EARLY_REPAYMENT according to the performed operation.

In the case of early repayment, the smart contract parameter early_repayment is changed to mark the exact amount of the repayment. If the installment amount is changed, it is marked using the emi parameter value. Since the parameters are append only, the change of the value introduces a new entry to the parameter time series. Both of the parameters are changed to allow further installment plan calculations inside the smart contract. The workflow then waits for the incoming postings and processes them to update the loan summary and installment plan.

Posting processed by TM

The postings are received using PostingApiListener. Based on the incoming posting type, the handler is selected and the posting is processed using it. If the handler for the posting does not exist, the posting is ignored.

The handlers wait for the confirmation of the postings sent by the service and listen on all other relevant postings to allow their further processing.

For loan purposes, the following types of postings are processed.

  • User repayment - All the repayments from the main account or pocket account to the loan account.

  • Principal repayment - The principal repayment for normal or early repayment.

  • Interest repayment - The interest repayment for normal or early repayment.

The replies for user repayments are used by the loan-service early repayment workflows to determine if the payment was successful and if the workflow can continue. They are also added to the database and assigned to the particular installment, however they are not use for any recalculation of the installment plan.

The principal and interest repayments postings are used to update the paid installment amount in all the installments and in the loan summary. The TM is still the source of truth, but the value is synced to the loan-manager because of caching.

The early and normal repayment postings are processed the same way, however, the data flow is different. The early repayment postings are processed by the early repayment workflows and the normal postings are directly written into the database. The early repayment is processed using the workflow to ensure the right order of all operations.

Prepayment event handling

Whenever the prepayment amount for the loan changes, the loan smart contract emits a Kafka message. This is read by TMWorkflowInstanceCreateListener and processed by handlePrepaymentChangeEvent method of PersonalLoansEventHandlerService class.

The whole prepayment amount is stored to the database in the loan summary entity and it is distributed to all unpaid installments.

The distribution of the prepayment amount to the installments can change after the repayment is done and the prepayment amount change event is not sent. This can happen e.g. after the early repayment. Because of this, the distribution of prepayment amount to the installments is recalculated on each incoming posting too.

Due and overdue balance change

The due and overdue loan amounts in the loan-manager database are updated using TM balance change events. The loan-manager listens for them using BalanceEventListener and processes the events in the handleBalanceChangeEvent method of PersonalLoansEventHandlerService class.

The loan summary due and overdue amounts are always updated to the current TM balances and the amounts are distributed to the unpaid installments.

The distribution the the installments has to be implemented.

Handling loan account closure

The closure of the account is initiated by the smart contract when the total outstanding debt goes down to the zero by sending a Kafka event.

The loan-manager listens for this event using handleLoanFullyRepaid method in TMWorkflowInstanceCreateListener class. When the event is received the CloseLoanWorkflow is initiated. The workflow is described at https://safibank.atlassian.net/wiki/spaces/ITArch/pages/222200333/Personal+loan+high-level+functionality#Closing-a-loan. After the workflow is finished, the loan is marked as closed in the database.