Unveiling the Power of Low Code Centralised Ledger

Moloy
Technology @ Funding Societies | Modalku
6 min readDec 28, 2023

Introduction

In the ever-evolving world of finance and banking, the need for efficient and reliable systems to manage transactions is paramount. One such system that has proven to be a game-changer is the Centralised Ledger. This blog helps to explain how we have implemented Ledger to keep track of transactions across multiple product segments.

Understanding the Ledger

A ledger, in its simplest form, is a book or collection of accounts where transactions are recorded. Each account has an opening balance, records transactions as either Debits (DR) or Credits (CR), and maintains a closing balance. In this context, we are developing a Centralised Ledger, a double-entry ledger system that receives entries from various channels and banking partners and every financial transaction affects at least two accounts, with one account debited and the other credited. This system ensures that the accounting equation remains balanced.

The double-entry ledger system is a bookkeeping method that records each financial transaction as equal debits and credits. This system ensures that the accounting equation (Assets = Liabilities + Equity) remains balanced. Debits represent the left side of an account, while Credits represent the right side.

Why an In-House Ledger?

While open-source ledger solutions are available, they often support only basic use-cases. For instance, we tried numary, but it did not support a double-entry ledger system. Moreover, we needed a ledger system that could support multiple countries, which is often costly and not always possible with external partners. Also we needed a ledger system which can power our balance queries for customer (SME’s here) as well as record the general ledger(GL) account balances. Therefore, we decided to design our ledger completely from company perspective, maintaining all accounts in the our book. This approach allows us to support SME-specific balance queries and transaction history, making ledger highly customised to our needs.

Ledger Account Categories

Account categories are classifications used to organise financial transactions in a ledger. Proper categorisation ensures accurate financial reporting and facilitates decision-making processes.

  • Assets
  • Liabilities
  • Equity
  • Revenue
  • Expenses

Account Types

  • Small and Medium sized Enterprise account (SME)
  • General Ledger account (GL)

SME Accounts represent users or borrowers and are used to send/receive funds.

On the other hand, General Ledger Accounts (GL Accounts) capture detailed financial information and are used to classify and track transactions within each account category.

Why Ledger design is Low Code

In our Ledger, we have Dynamic Rule Templates for various Transaction Flows. These templates precisely derive the Ledger Entries with the correct direction of money movement (Debit/Credit) to avoid any Accounting Error. We strictly follow the accounting principle Debit what comes in and Credit what goes out for ledger entries.

Dynamic Rule Template makes our ledger design a low code system, transactions for new payment types can be recorded by just adding the corresponding rule for it. No code change is required.

So each time a new feature is added like supporting Card Transactions, no code change is required in ledger service. We can support new features like Card Transactions by adding a new rule template and referring the rule_id in subsequent Card Transaction payment requests. This will generate the Transaction Postings as per the rule template given.

Ledger Data Store

We have used DynamoDB as our ledger store and have two main tables.

  1. Ledger Entries
  2. Ledger Rules (Dynamic Rule Template)

Ledger entries table follows Single-Table Design with DynamoDB Transaction support and holds entries for Account, GLAccount, Transaction and TransactionPosting.

We will need to add new rules which will translate to TransactionPosting when a new transaction is received. The Transactionand Transaction Posting are always immutable entries whereas Account and GL Account gets updated to maintain balance correctness.

Why DynamoDB

  • As a serverless offering, AWS DynamoDB ensures scalability and reduces maintenance, aligning with our agile infrastructure needs.
  • This is going to serve as centralised store where the volume of transactions will grow fast with onboarding of new SME and new Transaction flows over the time. DynamoDB has the capability to serve the required scale at an ease.

Why Single-Table Design

  • Single-Table Design is the most popular choice as it allows data to be pre-joined as Item Collection with a Partition key and multiple heterogenous items can be retrieved in a single request unlike making multiple serial requests to fetch required data which results in consuming more Network I/O requests in a waterfall fashion.
  • It also helps to achieve strong consistency as every READ and WRITE operation can retrieve or update multiple related items (Transaction, Transaction Posting and Account details) at once.

Access Patterns

By adopting single-table design techniques and designing efficient partition and sort keys, we are able to support multiple access patterns. Few of those patterns are like below:

  1. Get Account: Retrieve complete account details including balance.
  2. Get Transaction and Transaction Postings: Retrieve list of Transactions and Transaction Posting details for an account for a month or day or some specific time range.
  3. Get all GL Accounts: Retrieve all GL account details including balance.
  4. Get all GL Account details for a category: Retrieve GL account details for specific category.
  5. Get all Transaction details: Retrieve all transaction details (Transaction, Postings, Accounts) for a particular day or time range.

Money Withdraw Flow in Ledger

If we consider a $100 transaction of type Withdraw, below snippet explains in details how the transaction postings are generated from the dynamic rule template. Let us consider a $10 fee for withdrawal (amount configured in transaction level)

Rule Template

[
{
"account": {
"property_type": "static",
"value": "Payables GL A/C",
"expr": false
},
"type": {
"property_type": "static",
"value": "Debit",
"expr": false
},
"amount": {
"property_type": "dynamic",
"value": "amount + fee",
"expr": true
},
"source": {
"property_type": "dynamic",
"value": "from_account",
"expr": false
}
},
{
"account": {
"property_type": "static",
"value": "Fee GL A/c",
"expr": false
},
"type": {
"property_type": "static",
"value": "Credit",
"expr": false
},
"amount": {
"property_type": "dynamic",
"value": "fee",
"expr": false
},
"source": {
"property_type": "dynamic",
"value": "fee_account",
"expr": false
}
},
{
"account": {
"property_type": "static",
"value": "Casa GL A/c",
"expr": false
},
"type": {
"property_type": "static",
"value": "Credit",
"expr": false
},
"amount": {
"property_type": "dynamic",
"value": "amount",
"expr": false
},
"source": {
"property_type": "dynamic",
"value": "from_account",
"expr": false
}
}
]

Transaction Payload

{
"transaction_definition": "<rule_id>",
"transaction_type": "Withdraw",
"transaction_id": "<tran_id>",
"amount": 100,
"fee": 10,
"currency": "SGD",
"from_account": "<account_id>",
"fee_account": "<account_id>",
"request_token": "<token>"
}

Transaction Postings generated in Ledger

Conclusion

The Centralised Ledger is a powerful tool in modern banking, offering a robust and efficient system for managing transactions. Its dynamic rule template makes it a low-code application, making it easy to integrate with other services. As we continue to integrate it with other payment verticals, we look forward to exploring its full potential and bringing more efficiency and accuracy to our banking operations.

--

--