Skip to contents

Introduction

The multichainr package provides a high-level R interface to the MultiChain JSON-RPC API. This vignette demonstrates the lifecycle of managing both fungible assets (like currencies or loyalty points) and non-fungible tokens (NFTs).

To follow this guide, ensure you have the MultiChain binaries (multichaind and multichain-util) installed on your system.

library(multichainr)

# Set the path to your MultiChain binaries
mc_set_path(Sys.getenv("MULTICHAIN_PATH"))

1. Node Initialization

MultiChain operates as a permissioned blockchain. We start by initializing a new chain and launching the daemon.

chain_name <- "asset_demo_chain"

# Create the blockchain configuration
mc_node_init(chain_name)

# Start the node in the background
mc_node_start(chain_name)

# Allow the node a few seconds to initialize the wallet and network
Sys.sleep(3) 

# Connect to the local node
config <- mc_get_config(chain_name)
conn <- mc_connect(config)

2. Permissions and Addresses

By default, MultiChain is secure. Addresses must be granted specific permissions to issue or receive assets.

# Generate new wallet addresses
issuer_addr <- mc_get_new_address(conn)
recipient_addr <- mc_get_new_address(conn)

# Grant 'issue' and 'send' permissions to the issuer
mc_grant(conn, issuer_addr, "issue,send,receive")

# Grant 'receive' permissions to the recipient
mc_grant(conn, recipient_addr, "receive")

3. Fungible Assets

Fungible assets are divisible and interchangeable. We can create an “open” asset to allow the supply to be increased later.

# Define an asset named 'gold' with 2 decimal places (units = 0.01)
gold_params <- list(name = "gold", open = TRUE)

# Initial issuance of 1,000 units
mc_issue(conn, issuer_addr, gold_params, quantity = 1000, units = 0.01)

# Increase the total supply by an additional 500 units
mc_issue_more(conn, issuer_addr, "gold", 500)

# Verify the balance of the issuer
issuer_balances <- mc_get_address_balances(conn, issuer_addr)
print(issuer_balances)

4. Non-Fungible Tokens (NFTs)

In MultiChain 2.x, NFTs are managed as unique tokens within a non-fungible “Parent Asset.”

Creating the NFT Parent

To support individual tokens, the parent asset must be created with fungible = FALSE and an initial quantity of 0.

art_params <- list(
  name = "art", 
  fungible = FALSE, 
  open = TRUE
)

# Issue the parent container
mc_issue(conn, address = issuer_addr, name = art_params, quantity = 0, units = 1)

Issuing Unique Tokens

Once the parent exists, we can issue individual tokens (NFTs). Each token can include custom JSON metadata.

# Issue a unique token "painting_001" with specific metadata
mc_issue_token(conn,
               address = issuer_addr, 
               asset = "art", 
               token = "painting_001", 
               quantity = 1, 
               token_details = list(artist = "Leonardo da Vinci", year = 1503))

# Retrieve specific token metadata
token_info <- mc_get_token_info(conn, "art", "painting_001")
print(token_info)

5. Transfers and Multibalances

We can transfer assets using specific convenience functions or the general-purpose mc_send function for complex transactions (like NFTs).

# 1. Send 100 units of fungible 'gold'
mc_send_asset(conn, recipient_addr, "gold", 100)

# 2. Send the NFT 'painting_001'
# NFTs require a nested list structure specifying the parent and the token name
nft_transfer <- list(
  art = list(
    token = "painting_001",
    qty = 1
  )
)
mc_send(conn, recipient_addr, nft_transfer)

# 3. Inspect the recipient's token balances
# The output is a clean data frame with an 'address' column
recipient_tokens <- mc_get_token_balances(conn, recipient_addr)
print(recipient_tokens)

6. Node Shutdown and Cleanup

When the work is complete, it is important to stop the node and, if necessary, remove the data directory.

mc_node_stop(conn)
Sys.sleep(2)

# Determine data directory for cleanup
if (.Platform$OS.type == "windows") {
  base_dir <- file.path(Sys.getenv("APPDATA"), "MultiChain")
} else if (Sys.info()["sysname"] == "Darwin") {
  base_dir <- file.path(Sys.getenv("HOME"), "Library/Application Support/MultiChain")
} else {
  base_dir <- file.path(Sys.getenv("HOME"), ".multichain")
}

chain_dir <- file.path(base_dir, chain_name)
if (dir.exists(chain_dir)) unlink(chain_dir, recursive = TRUE)

Summary

In this vignette, we demonstrated how to:

  1. Configure permissions using mc_grant.
  2. Issue open fungible assets using mc_issue and mc_issue_more.
  3. Set up a non-fungible environment by setting fungible = FALSE.
  4. Issue and query unique tokens (NFTs) via mc_issue_token and mc_get_token_info.
  5. Perform multi-asset transfers and monitor balances.