--- title: "Atomic Swaps and Raw Transactions" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Atomic Swaps and Raw Transactions} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE ) ``` ## Introduction In a MultiChain network, atomic swaps are performed using a sequence of "raw exchange" commands. This process involves locking a transaction output (UTXO), creating a partial transaction offer, and having a counterparty complete and broadcast that transaction. ```{r setup} library(multichainr) # Set the path to your MultiChain binaries mc_set_path(Sys.getenv("MULTICHAIN_PATH")) ``` ## 1. Node Initialization We start by setting up our environment and a temporary blockchain. ```{r init} chain_name <- "swap_demo_chain" # Create and start the node mc_node_init(chain_name) mc_node_start(chain_name) # Wait for the node to initialize Sys.sleep(3) # Connect to the local node config <- mc_get_config(chain_name) conn <- mc_connect(config) ``` ## 2. Preparing the Trade To demonstrate a swap, we need two participants and two different assets. ```{r prepare_trade} # Create addresses for two traders trader_a <- mc_get_new_address(conn) trader_b <- mc_get_new_address(conn) # Grant necessary permissions mc_grant(conn, trader_a, "receive,send,issue") mc_grant(conn, trader_b, "receive,send,issue") # Issue 'AssetA' to Trader A and 'AssetB' to Trader B mc_issue(conn, trader_a, "AssetA", 100) mc_issue(conn, trader_b, "AssetB", 100) # Verify balances print(mc_get_address_balances(conn, trader_a)) print(mc_get_address_balances(conn, trader_b)) ``` ## 3. Step 1: Trader A Creates an Offer Trader A wants to exchange **10 units of AssetA** for **5 units of AssetB**. First, Trader A must "lock" their AssetA to prepare it for the exchange. ```{r create_offer} # 1. Prepare and lock the output (10 AssetA) # This creates a specific UTXO that can only be spent in an exchange lock_res <- mc_prepare_lock_unspent_from(conn, from_address = trader_a, amounts = list(AssetA = 10)) # 2. Create the raw exchange offer # Trader A specifies what they are giving (lock_res) and what they want (5 AssetB) offer_hex <- mc_create_raw_exchange(conn, txid = lock_res$txid, vout = lock_res$vout, amounts = list(AssetB = 5)) # The 'offer_hex' is a partial transaction string that Trader A can send # to Trader B via any communication channel (email, chat, etc.) print(offer_hex) ``` ## 4. Step 2: Trader B Completes the Swap Trader B receives the `offer_hex`, inspects it, and decides to accept it by providing the requested **5 units of AssetB**. ```{r complete_swap} # 1. Trader B inspects the offer to ensure it is fair decoded_offer <- mc_decode_raw_exchange(conn, offer_hex) print(decoded_offer) # 2. Trader B completes the exchange using their own funds # This requires providing an output of 5 AssetB # Here, we let MultiChain automatically find the best UTXO for Trader B complete_res <- mc_prepare_lock_unspent_from(conn, from_address = trader_b, amounts = list(AssetB = 5)) final_tx_hex <- mc_complete_raw_exchange(conn, tx_hex = offer_hex, txid = complete_res$txid, vout = complete_res$vout, amounts = list(AssetA = 10)) ``` ## 5. Step 3: Broadcasting the Transaction The exchange is now a fully formed raw transaction. It must be broadcast to the network to be included in a block. ```{r broadcast} # Broadcast the finalized transaction swap_txid <- mc_send_raw_transaction(conn, final_tx_hex) # Confirm the swap by checking balances # Trader A should have +5 AssetB, Trader B should have +10 AssetA Sys.sleep(1) # Wait for mempool processing print(mc_get_address_balances(conn, trader_a)) print(mc_get_address_balances(conn, trader_b)) ``` ## 6. Cleanup Finally, we stop the node and remove the temporary data directory. ```{r cleanup} mc_node_stop(conn) Sys.sleep(2) 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. **Prepare Locked Outputs**: Using `mc_prepare_lock_unspent_from` to set aside specific assets for trade. 2. **Create Offers**: Generating a partial transaction hex with `mc_create_raw_exchange`. 3. **Audit Offers**: Using `mc_decode_raw_exchange` to verify the contents of a trade before signing. 4. **Complete and Finalize**: Combining multiple parties' inputs into a single transaction with `mc_complete_raw_exchange`. 5. **Execution**: Broadcasting raw hex to the blockchain using `mc_send_raw_transaction`.