How Cardano UTxO Transactions work — From Theory to Practice

1. Introduction

The goal of this guide is to explain how blockchain transactions work with the UTxO model. The tutorial begins with a short theoretical introduction and ends with a practical example.

This tutorial is propaedeutic to understand how to mint Tokens and NFTs in the Cardano ecosystem.

Cardano uses more or less the same transaction model of Bitcoin, the UTxO model. UTxO stands for Unspent Transaction Output.

In Cardano, every transaction has one or more inputs and one or more Outputs. It’s important to consider that the sum of inputs has to be equal to the outputs (fees included), and the transaction inputs are the output of another one. If we look at image1, at the TX1, there are 1000 ADAs as input, and the sum of outputs is 100 ADAs+ 200 ADAs+ 700 ADAs(fees included).

In the UTxO model, the amount of money available for a wallet is represented by the sum sent as output to a wallet and not yet spent with another transaction. From the image below, the unspent money is represented by the piggy bank shape.

As we can see from the picture, in this article, we want to create an address with cardano-cli and send a part of the funds to two addresses handled from a Daedalus wallet.

In this example, transactions will be executed just with ADAs, the Cardano native currency, but can also be performed with native assets, such as tokens or NFTs.

Image 1 — UTxO Example

The image represents what has just been We’reexplained and the transactions that we’ll perform in the practical example.

Let’s explain better the steps of the image.

  1. TX0 — from faucet wallet: using the Faucet web service, we will send 1000 tADAs to an address generated with cardano-cli. The rest of this transaction will come back to the wallet handled by Faucet.
  2. TX1 — from the cardano-cli wallet: once the 1000 tADAs from Faucet are available from the cardano-cli wallet, it’s time to do our custom transaction. In the example:
  • 100 tADAs will be to a Daedalus wallet
  • 200 tADAs will be sent to another Daedalus wallet
  • 700 tADAs minus the fees will be sent back to the cardano-cli wallet, like the rest.

1.1 Prerequisite for the practical example

  • Install Daedalus Testnet
  • The tutorial is based on macOS but can be easily adapted to Linux or Windows.
  • To better understand some commands would be better to know the basics of cryptography, like Asymmetric encryption.
  • Understand the basics of bash as variables, stdin, and stdout.

1.2 Macro-steps to submit transactions

The following are the macro-steps we’re going to do in the practical example:

  1. Create a Verification key (public key), Signing Key (private key), and an address from the public key.
  2. Build a transaction to an address without fees.
  3. Calculating fees.
  4. Build the same transaction again with fees.
  5. Signing the transaction.
  6. Submit the transaction into the blockchain.

2. Practical Example

2.1 Setting up the Cardano CLI (Command Line Interface)

Daedalus allows the computer to run a Cardano Node to interact with the blockchain through a User Interface and a command-line interface, the cardano-cli. The communication is permitted thanks to a socket file.

To get the path of the socket file, be sure Daedalus is running and lunch this command:

ps -ef | grep cardano-node

When you generate the output below, get the path similar to the last highlighted line.

501 78957 78943   0 11:12AM ??        16:53.43 cardano-node run --socket-path cardano-node.socket --shutdown-ipc 3 --topology /Applications/Daedalus --database-path chain --port 56510 --config /Applications/Daedalus
501 78958 78943 0 11:12AM ?? 32:49.67 cardano-wallet serve --shutdown-handler --port 56511 --database
/Users/valeriomellini/Library/Application Support/Daedalus Testnet/wallets --tls-ca-cert
/Users/valeriomellini/Library/Application Support/Daedalus Testnet/tls/server/ca.crt --tls-sv-cert
/Users/valeriomellini/Library/Application Support/Daedalus Testnet/tls/server/server.crt --tls-sv-key
/Users/valeriomellini/Library/Application Support/Daedalus Testnet/tls/server/server.key --token-metadata-server[]( --sync-tolerance 300s --testnet /Applications/Daedalus --node-socket
Users/valeriomellini/Library/Application Support/Daedalus Testnet/cardano-node.socket

We’re ready to set two environment variables; the first one points to the socket file and the second to the cardano-cli executable. If you use Windows or Linux, you’ll have different paths but the same approach.

export CARDANO_NODE_SOCKET_PATH="/Users/$(YOUR_USER)/Library/Application Support/Daedalus Testnet/cardano-node.socket"export PATH=$PATH:"/Applications/Daedalus"

To be sure that all is going to work, we should run the following command successfully:

cardano-cli query tip --testnet-magic 1097911063

The testnet-magic parameter identifies a specific testnet network environment. Now an output example if everything works correctly:

"hash": "6781b5c5d6f857e96cf854f4452859914fc299c7e7d0041f96c776329be89471",
"block": 2910987,
"slot": 37243969,
"syncProgress": "100.00",
"era": "Alonzo",
"epoch": 156

Setting some environment variables that we’ll need later.

export magicnumber=1097911063
export fee=0

2.2 Creation of verification/signing key

To create a verification and signing key, run this command:

cardano-cli address key-gen --verification-key-file payment.vkey --signing-key-file payment.skey

The verification key is saved as payment.vkey, and the signing key is held as payment.skey

2.3 Generation of the address

The verification key generates the address with the following command:

cardano-cli address build --payment-verification-key-file payment.vkey --out-file payment.addr --testnet-magic=$magicnumber

For simplicity, we save the address in an environment variable.

export address=$(< payment.addr)

If we try to execute this command on the address just created, we can see any UTxO.

cardano-cli query utxo --address $(< payment.addr) --testnet-magic=$magicnumber
Image 2 — From the terminal on the right, we can’t see any transaction yet on that address

2.4 Sending funds to the address

Now we can send tADAs to the address just created. The service used to send test ADAs is Faucet.

After sending ADAs, we can see check the new UTxO record on the address.

cardano-cli query utxo --address $(< payment.addr) --testnet-magic=$magicnumber
Image 3 — As we can see, there are 1000000000 Lovelace (1000 tADAs ) on the address just created.

Now we can save the hash and the index of the transaction in two environment variables:

export txhash=4c2ccae6d631084a7e74be44356c2fdd0adc3614e7452d47cebfae58fc17cae3
export txix=0
export amount=1000000000

2.5 Submitting a transaction from cardano-cli

As I wrote before, to submit a transaction with cardano-cli, we have to consider the following steps:

  1. Creating a transaction to an address without fees
  2. Calculating fees
  3. Complete the same transaction again with fees
  4. Signing the transaction
  5. Submitting the transaction into the blockchain.

2.5.1 Performing a transaction to an address without fees

First of all, we need two addresses to generate the two transactions we want to execute. I want to take them from the Daedalus interface.

Image 4 — Daedalus addresses

For simplicity, we want to save the address in two environment variables.

export addr_tx2=addr_test1qqv27gskhx32en6ua7f7m6enay4e9s5ekmq9l9gqgee6gkn7ymxyum62ndw5jcu4kl9myq2z00hp8vv4adxysauyv8qs9wwy8k
export addr_tx3=addr_test1qq4z657494prfsu80sghq2y0jqdx8qz2c938txcag4pnr8r7ymxyum62ndw5jcu4kl9myq2z00hp8vv4adxysauyv8qspx5a4z

As I wrote before, I want to send 100 tADAs at the first address and 200 tADAs at the second.

Run the following commands to build a raw transaction with cardano-cli.

export rest=$(expr $amount - 200000000 - 100000000 - $fee)cardano-cli transaction build-raw \
--fee $fee \
--tx-in $txhash#$txix \
--tx-out $addr_tx2+100000000 \
--tx-out $addr_tx3+200000000 \
--tx-out $address+$rest \
--out-file matx.raw

Now explain line by line:

  • — fee: this parameter must include the fee cost to submit the transaction
  • — tx-in: this parameter must include the transaction data necessary to get the tADAs
  • — tx-out: represent the transaction output. In this example, The first two represent the output to the Daedalus address. The last — tx-out means the rest that is sent to the sender wallet. IT’S VERY IMPORTANT THAT SUM OF tADAs REMAINS UNCHANGED, SO REST = INPUTS — OUTPUTS — FEES
  • — out-file: the transaction result that should be signed and sent to the blockchain.

2.5.2 Calculating fees

First of all, it’s necessary to download the protocol parameters.

cardano-cli query protocol-parameters --testnet-magic=$magicnumber --out-file protocol.json

Now that we have the protocol.json file and transaction output, we can update the $fee variable.

export fee=$(cardano-cli transaction calculate-min-fee --tx-body-file matx.raw --tx-in-count 1 --tx-out-count 3 --witness-count 1 --testnet-magic=$magicnumber --protocol-params-file protocol.json | cut -d " " -f1)
  • — tx-in-count must represent the number of inputs in the transaction. In this case, 1.
  • — tx-out-count must represent the number of outputs in the transaction. In this case, 3.
  • — tx-body-file: this parameter it’s necessary to retrieve the transaction file.
  • — protocol-params-file: this parameter it’s necessary to retrieve the transaction file.
  • — witness-count: witnesses are the number of signing keys used to sign the transaction.

After the price of the fee is known, it’s possible to update the $rest variable repeating this instruction:

export rest=$(expr $amount - 200000000 - 100000000 - $fee)
Image 5 — fees and rest calculation

2.5.3 Create the same transaction again with fees

Now that we get all data, it’s possible to repeat the transaction instruction.

cardano-cli transaction build-raw \
--fee $fee \
--tx-in $txhash#$txix \
--tx-out $addr_tx2+100000000 \
--tx-out $addr_tx3+200000000 \
--tx-out $address+$rest \
--out-file matx.raw

2.5.4 Signing the transaction

We are ready to sign the transaction with the payment signing key.

cardano-cli transaction sign  \
--signing-key-file payment.skey \
--testnet-magic $magicnumber --tx-body-file matx.raw \
--out-file matx.signed

2.5.5 Submit the transaction on the blockchain

Finally, we’re able to send the submitted transaction to the blockchain with this command.

cardano-cli transaction submit --tx-file matx.signed --testnet-magic $magicnumber
Image 6— Transaction submission

And after few seconds, we can see the outcome of the transactions as expected; the Daedalus balance is updated.

Image 7— Balance updated

If something isn’t clear, don’t hesitate to write me in a comment below.

I take advance of this blog to share my experience with the blockchains, decentralized economy, particularly Cardano.