Skip to main content

Transfers

Transfers are the way of sending funds from one account to another. Each transfer on the M10 ledger is made up of multiple transfer steps. In each transfer step, there is a "from account" (the sender), a "to account" (the receiver), and an amount. In addition, each step contains a metadata field, which allows for unstructured data to be passed along with the transfer. Generally, this is formatted as protobufs. All steps are applied atomically — if one step fails all the steps fail.

Transfer Steps

As discussed above each transfer is made up of multiple "steps". This allows you to send to multiple accounts in a single atomic action. Fees are a great use case for this. Fees are usually paid out to an account other than the receiver's, and so need to be collected in each transfer. To collect fees, you would create a single transfer with two steps. One for the main transfer (i.e Alice to Bob), and one for the fee transfer (i.e Alice to fee account). If Alice lacks the funds to complete either transfer step, the entire transfer will fail.

Transfer Hops

Since M10 is a "hierarchical" ledger, transfers have some unique behavior. Let's imagine an account structure with two banks: Iron Bank and Tungsten Bank. Tungsten Bank has a single user Alice, and Iron Bank has one user named Chris. What happens if Alice tries to send $50 to Chris? The money that is in Alice's account isn't really USD; the money is a bank deposit. Banks, in many countries, may hold a smaller amount of funds than the total deposits their customers have. This is referred to as the fractional reserve model. But for customers of banks to transact with each other they must exchange real currency. The M10 ledger makes this process seamless. When Alice creates a new transfer step to Chris, the ledger does several different "hops" behind the scenes.

note

A "hop" is different than a TransferStep. A hop is an internal procedure the ledger does, where as a TransferStep is a way to bundle multiple transfers into a single operation. The relationship is as follows: Transfer -> Transfer Step -> Hop. Remember, you'll never have to create a "hop" with our API.

First Alice's money is sent to Tungsten bank. Then Tungsten Bank sends money from its holdings, through the root account, to the Iron Bank. The Iron Bank has now been credited with 50 dollars. Next, the Iron Bank will issue new Iron Bank M1 currency to Chris. In the ledger each of these "hops" is done automatically; if any one of them fails the entire transfer fails. You will notice here that no new money is created, and everything is kept balanced. Through this system, the M10 ledger is able to support fractional reserve banking seamlessly.



Initiate and Commit

caution

This is an advanced topic, and to best understand it you should read the Role and Role Binding API docs first.

There are many situations where you may want to interact with an external system to perform validation of a transfer. For instance, if a bank wishes to charge fees per transfer, they need a way to validate that. Or imagine if you want to only send someone funds after they have completed some actions, like moving money into an escrow account. M10 solves these use cases through our initiate and commit system. Readers who know about two-phase commit protocols will find this familiar.

We introduce two new transaction types, InitiateTransfer and CommitTransfer. InititateTransfer will debit every hop in the transfer, ensuring that no balances drop below zero. CommitTransfer performs the credit side of the operation. The true power of this system comes when combined with our RBAC system. In the example where a bank wishes to enforce fees on an account, they would only grant the user Initiate permissions on their account. Then the bank would hold Commit permissions on the account. The bank could then observe initiate transfers, and validate them for correct fees. If a fee is incorrect they would issue CommitTransfer, with a new_state of rejected. If the fee is correct they would do the same with a new_state of accepted.

When a transfer is "accepted", a credit is performed on each of the receiving accounts. But when a transfer is "rejected" the debit done in "initiated" is rolled-back.



Model

API Calls

Create a single transfer

  • Rust
  • TS
  • Dart
  • CLI
M10 REPLFOO

Create a multi-transfer

  • Rust
  • TS
  • Dart
  • CLI
M10 REPLFOO

Transfer with metadata

  • Rust
  • TS
  • Dart
  • CLI
M10 REPLFOO

Initiate & Commit

  • Rust
  • TS
  • Dart
  • CLI
M10 REPLFOO

Get

  • Rust
  • TS
  • Dart
  • CLI
M10 REPLFOO

List

  • Rust
  • TS
  • Dart
  • CLI
M10 REPLFOO

Observe

  • Rust
  • TS
  • Dart
  • CLI
M10 REPLFOO