Skip to main content

Multi-Debit, Multi-Credit Transfers

TigerBeetle is designed for maximum performance. In order to keep it lean, the database only supports simple transfers with a single debit and a single credit.

However, you'll probably run into cases where you want transactions with multiple debits and/or credits. For example, you might have a transfer where you want to extract fees and/or taxes.

Read on to see how to implement one-to-many and many-to-many transfers!

Note that all of these examples use the Linked Transfers flag (flags.linked) to ensure that all of the transfers succeed or fail together.

One-to-Many Transfers

Transactions that involve multiple debits and a single credit OR a single debit and multiple credits are relatively straightforward.

You can use multiple linked transfers as depicted below.

Single Debit, Multiple Credits

This example debits a single account and credits multiple accounts. It uses the following accounts:

  • A source account A, on the USD ledger.
  • Three destination accounts X, Y, and Z, on the USD ledger.
LedgerDebit AccountCredit AccountAmountflags.linked
USDAX10000true
USDAY50true
USDAZ10false

Multiple Debits, Single Credit

This example debits multiple accounts and credits a single account. It uses the following accounts:

  • Three source accounts A, B, and C on the USD ledger.
  • A destination account X on the USD ledger.
LedgerDebit AccountCredit AccountAmountflags.linked
USDAX10000true
USDBX50true
USDCX10false

Multiple Debits, Single Credit, Balancing debits

This example debits multiple accounts and credits a single account. The total amount to transfer to the credit account is known (in this case, 100), but the balances of the individual debit accounts are not known. That is, each debit account should contribute as much as possible (in order of precedence) up to the target, cumulative transfer amount.

It uses the following accounts:

IdLedgerDebit AccountCredit AccountAmountFlags
1USDSETUPLIMIT100linked
2USDASETUP100linked, balancing_debit, balancing_credit
3USDBSETUP100linked, balancing_debit, balancing_credit
4USDCSETUP100linked, balancing_debit, balancing_credit
5USDSETUPX100linked
6USDLIMITSETUP100balancing_credit

If the cumulative credit balance of A + B + C is less than 100, the chain will fail (transfer 6 will return exceeds_credits).

Many-to-Many Transfers

Transactions with multiple debits and multiple credits are a bit more involved (but you got this!).

This is where the accounting concept of a Control Account comes in handy. We can use this as an intermediary account, as illustrated below.

In this example, we'll use the following accounts:

  • Two source accounts A and B on the USD ledger.
  • Three destination accounts X, Y, and Z, on the USD ledger.
  • A compound entry control account Control on the USD ledger.
LedgerDebit AccountCredit AccountAmountflags.linked
USDAControl10000true
USDBControl50true
USDControlX9000true
USDControlY1000true
USDControlZ50false

Here, we use two transfers to debit accounts A and B and credit the Control account, and another three transfers to credit accounts X, Y, and Z.

If you looked closely at this example, you may have noticed that we could have debited B and credited Z directly because the amounts happened to line up. That is true!

For a little more extreme performance, you might consider implementing logic to circumvent the control account where possible, to reduce the number of transfers to implement a compound journal entry.

However, if you're just getting started, you can avoid premature optimizations (we've all been there!). You may find it easier to program these compound journal entries always using a control account -- and you can then come back to squeeze this performance out later!