Skip to main content

Quickstart

This guide steps through how to use the DRM SDK & Command-Line Interface (CLI) to create a new digital currency called "My Bucks" with the currency code MYB.

To better understand how the DRM Platform serves as an API for the interaction between all network members you'll step through the entire process:

  • As the Central Bank
    • Create digital currency
    • Create two bank issuance accounts
    • Issue funds
  • As the Commercial Bank
    • As Bank One, create Alice's account and inssue funds
    • As Bank Two, create Bob's account
  • As Alice, send digital currency to Bob
  • As Bob, confirm receipt of funds
info

Before getting started, you'll need a root issuance account issued to you by DRM and the associated private key. You'll also need the latest SDK version from Github. The REPL provided throughout this guide already has these provided for your easy exploration.

Before we start

Depending on which SDK or terminal interface you're using, modify the following required code to match your environment:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

As the Central Bank

You start as the central bank to create and issue a new digital currency. Then you onboard commercial banks and create accounts for them before finally issuing money to them.


Create digital currency

Create central bank key pair

You need your central bank key pair in the PKCS8 format. To generate a new key-pair, enter the following command:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Output

You should see something like this:

created key pair file: "central-bank.pkcs8"
public key is:
"hOJIkyqJ7/dUStWzcgj+afT1dBvJKczPvl5q70MpMaY="

Create the root account

Create the root account for the new digital currency associated with the central bank public key:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO
Root Account Limit Warning

The system supports a maximum of 256 root accounts. Once you reach this limit, you cannot create additional root accounts. This is a hard limit - make sure to plan account creation carefully to avoid hitting this ceiling unexpectedly.

Output

You should see something like:

1a000000000000000000000000000000

Create the role and role-binding

The central bank must be given permission to create issuance accounts for banks. We do that by creating a role with the appropriate permissions that is then associated with the central bank's public key.

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Create issuance accounts for two banks

The process for creating bank keys and issuance accounts is similar to the steps for the central bank. Using the public keys for Bank One and Bank Two, we create issuance accounts for their commercial use and grant them permissions via new roles and role bindings.

Bank One

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Bank Two

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Issue funds - Bank One

To issue funds to Bank One from the central bank, we create a transfer from the root account to Bank One's account:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Transfer information

We retrieve information about the transfer by using the transaction ID (tx_id) from the output:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Output

You should see something like this:

(
tx_id: 129630000,
context_id: [],
timestamp: "2023-08-25 10:39:55.210130",
steps: [
(
from: "0c000000000000000000000000000000",
to: "0c800000000000000000000000000002",
amount: 100000,
metadata: [
Memo((plaintext:"Funds")),
],
),
],
success: true,
state: Accepted,
)

Check the balance

In the Central Bank root account, after the transfer, notice the change in the issuance.balance field:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Output

You should see something like this:

(
id: 0c000000000000000000000000000000,
balance: 0,
frozen: false,
code: "MYB",
decimals: 2,
balance_limit: 18446744073709551615,
issuance: Some((
balance: 100000,
issuance_accounts: 2,
holding_accounts: 0,
)),
)

As the Commercial Bank

After a bank has been onboarded, the bank can use the API to create and manage accounts for their customers. Here we will use the API as two different commercial banks titled:

  • "Bank One"
  • "Bank Two"

Each of these banks have a new customer that we will create accounts for, and deposit funds to.


Bank One - find my issuance account

Let's use the SDK to find Bank One's issuance account that was just created by the Central Bank. We can list all accounts by owner. Since we only created one account in this tutorial, we will get one account returned, which is Bank One's issuance account.

The following code creates a new ListAccountsRequest filtering by our public_key as the owner. It then signs the request using our private key and submits the request to the ledger.

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Output

You should see something like this:

[
(
id: "0c800000000000000000000000000002",
owner: "i+VZtoZhwLhfMZ2Etv23029ulURf1yz4Gb6RaqSGS9Y=",
name: "Bank One MYB",
public_name: "Bank One MYB Issuance Account",
profile_image_url: "",
),
]

Bank One - create Alice's customer account

Now we will create a new child account for a customer named Alice under Bank One's issuance account. Alice needs her own key pair to sign transactions with, so first we generate her key (normally, Alice would generate her key pair herself in a client app):

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Create role and role-binding for Bank One

Bank One doesn't yet have any roles that we can use to assign permissions. Therefore, we create a customer role and a role-binding where we use Alice as a subject:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Create an account for Alice in Bank One

Now we can create an account for Alice:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Bank One - issue funds to Alice's customer account

Alice's new account has a balance of zero, so we will issue funds from her bank (Bank One) to Alice's new account:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Bank Two - create Bob's customer account

To setup Bob as a customer of Bank Two, we go through the same process as for Alice at Bank One:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Create roles and role-binding for Bank Two

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Create account for Bob in Bank Two

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

As Alice, send digital currency to Bob

Now that Alice and Bob have accounts on the ledger and appropriate permissions, they can use the API (or one of the SDKs or the CLI) to send and receive "My Bucks" to each other.

The hierarchical ledger tree of accounts enables a double-entry accounting system, creating atomic transactions that all participants in the activity can observe and respond to.


Check current balance

First we check Alice's account balance (it should be 1000 MYB, since we previously issued that from Bank One into Alice's account):

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Output

You should see something like the following, which includes balance: 100000 (the two last digits are the two decimals):

(
id: "0c800000000000000000000000000003",
balance: 100000,
frozen: false,
code: "MYB",
decimals: 2,
balance_limit: 18446744073709551615,
issuance: None,
)

Transfer funds to Bob

Since Alice has funds in her account, she can transfer 100 MYB to Bob:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Look up recent transfers to confirm delivery

The following code gets a list of transfers. We filter the output by account.

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

There are other filter options as well:

Filter optionDescription
-m, --min-tx-id <MIN_TX_ID>Set minimum transaction ID [default: 0]
-x, --max-tx-id <MAX_TX_ID>Set maximum transaction ID
-a, --account <ACCOUNT>Set account filter
-c, --context-id <CONTEXT_ID>Set contextID filter
-l, --limit <LIMIT>Set limit of results [default: 20]

For more filter details, see the Create transfer endpoint.

The purpose of the context_id is to provide a unique identifier that links together multiple transactions that are part of a larger, multi-legged operation, particularly across different ledgers. This is crucial for scenarios like foreign exchange transfers where a single user action results in separate transactions on different ledgers (e.g., USD ledger and EUR ledger).

The context_id allows:

  • Tracking related transactions - It provides a way to tie together the various legs of a multi-ledger transfer, enabling tracking of the entire operation’s status and progress. This is important for users to be able to see the complete picture of their transfer, even if parts of it are happening on different ledgers.
  • Simplified remote lookup and authorization - It acts as a shared secret, enabling users involved in a multi-ledger transfer to look up the status of remote transactions without needing to have direct access or authorization to the remote ledger. This allows users to verify that all parts of their transfer have been completed successfully.
  • Resolution of ambiguity in transaction matching - In cases where multiple similar transactions occur (e.g., multiple transfers of the same amount to the same account), the context_id helps disambiguate which transactions are related to a specific user’s initial request.

In essence, the context_id provides the glue that holds together the different pieces of a complex, distributed transaction and enables a coherent view of the entire operation.

Output

The output of the above request returns the transfers made by Alice with the most recent transaction at the top:

[
(
tx_id: 133930000,
context_id: [],
timestamp: "2023-08-25 10:42:42.786861",
steps: [
(
from: "0c800000000000000000000000000003",
to: "0c800001000000000000000000000003",
amount: 10000,
metadata: [Memo((plaintext:"groceries"))],
),
],
success: true,
state: Accepted,
),
(
tx_id: 132160000,
context_id: [],
timestamp: "2023-08-25 10:41:53.310156",
steps: [
(
from: "0c800000000000000000000000000002",
to: "0c800000000000000000000000000003",
amount: 10000,
metadata: [Memo((plaintext:"Funds"))],
),
],
success: true,
state: Accepted,
),
]

Check Alice's balance to confirm debit of funds

You can make sure there was a debit of Alice's funds, and you can check that with the following code:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Output

You should see something like the following where the balance field is less than before:

(
id: "0c800000000000000000000000000003",
balance: 90000,
frozen: false,
code: "MYB",
decimals: 2,
balance_limit: 18446744073709551615,
issuance: None,
)

As Bob, confirm receipt of funds

The following code checks Bob's balance to confirm credit of Alice's funds:

  • CLI
  • TypeScript
  • Rust
M10 REPLFOO

Output

You should see something like the following with balance: 10000:

(
id: "0c800001000000000000000000000003",
balance: 10000,
frozen: false,
code: "MYB",
decimals: 2,
balance_limit: 18446744073709551615,
issuance: None,
)

Now that you've taken the first steps in exploring the fundamental functions of the DRM platform, it's time to venture further and try the following:

  • Request transaction and account information using the different keys you've created.
  • Consider which personas can see which activities.

A key area of mastery that will enhance your understanding and utilization of the DRM platform is understanding how RBAC and the ledger hierarchy influence access and how they model the compliance requirements in financial services.