--- title: "Managing Assets and Tokens" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Managing Assets and Tokens} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE ) ``` ## 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. ```{r setup} 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. ```{r init} 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. ```{r addresses} # 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. ```{r fungible} # 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`. ```{r nft_parent} 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. ```{r issue_tokens} # 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). ```{r transfers} # 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. ```{r cleanup} 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.