Simple transactions
Simple transactions
Cardano transactions involve consuming one or more Unspent Transaction Outputs (UTXOs) and generating one or more new UTXOs. The most basic transaction type involves transferring ada from one address to another. It is essential to ensure that all transactions are 'well-balanced', meaning that the sum of outputs and transaction fees equals the sum of inputs. This balance ensures the integrity and validity of the transaction. Unbalanced transactions are rejected by the local node.
Creating a transaction using the CLI follows a three-step process:
- Build: construct the transaction with relevant details
- Sign: authenticate the transaction with appropriate signatures
- Submit: send the signed transaction to the network for processing.
You'll find commands for these tasks under cardano-cli conway transaction
cardano-cli conway transaction
Usage: cardano-cli conway transaction
( build-raw
| build
| build-estimate
| sign
| witness
| assemble
| submit
| policyid
| calculate-min-fee
| calculate-min-required-utxo
| hash-script-data
| txid
)
Transaction commands.
cardano-cli
provides several options for constructing transactions: transaction build-raw
, transaction build
, and build-estimate
. The key difference between these methods lies in their offline and online capabilities, as well as the degree of manual or automatic processing involved.
- The
build-raw
command enables offline transaction building, eliminating the need for a connection to a running node. However, this method requires manual calculation of fees and balancing the transaction. - The
build
command automatically calculates fees and balances the transaction, but it necessitates a connection to a running node - The
build-estimate
command is a command that is useful for estimating the size and fee of a transaction when the CLI is not connected to the node. This command automatically balances a transaction related to the script one would like to execute.
When building a transaction, it's essential to specify the following elements:
- Inputs: one or multiple Unspent Transaction Outputs (UTXOs) being utilized
- Outputs: the addresses where the funds will be sent, including the amount in lovelace for each recipient and any change that needs to be returned to yourself
- Transaction fee: the fee paid for the transaction to be processed on the chain.
Building transactions with the build-raw
command
To create a transaction using build-raw
, you will need the protocol parameters. These parameters are necessary for calculating the transaction fee at a later stage. Querying the protocol parameters requires a running node:
cardano-cli conway query protocol-parameters --out-file pparams.json
You also need to know the inputs (UTXOs) you will use. A UTXO is identified by its transaction hash (TxHash
) and transaction index (TxIx
) with the syntax TxHash#TxIx
. You can only use UTXOs controlled by your payment.skey
.
To query the UTXOs associated to your payment.addr
, run:
cardano-cli conway query utxo --address $(< payment.addr)
TxHash TxIx Amount
--------------------------------------------------------------------------------------
e29e96a012c2443d59f2e53c156503a857c2f27c069ae003dab8125594038891 0 9994790937 lovelace + TxOutDatumNone
In this example, the address has one UTXO associated with it. It holds 9,994,790,937 lovelace (9,994.790937 ada).
Assume you want to send 1,000,000 lovelace (1,000 ada) from payment.addr
to a payment2.addr
. This transaction will have one input and two outputs:
- The single input is the UTXO that the transaction will consume, in this case
e29e96a012c2443d59f2e53c156503a857c2f27c069ae003dab8125594038891#0
- The first output corresponds to the 1000 ada we are sending to
payment2.addr
- The second output corresponds to the change of the transaction. We are sending the difference (8994790937 lovelace) to
payment.addr
.
At this stage, you do not need to worry about the transaction fees. Save the transaction body in the tx.draft
file:
cardano-cli conway transaction build-raw \
--tx-in e29e96a012c2443d59f2e53c156503a857c2f27c069ae003dab8125594038891#0 \
--tx-out addr_test1vzuztsedkqanfm7elu9nshfr4gh2gl0aj4djmayav2t7x8ch3pg30+1000000000 \
--tx-out addr_test1qp39w0fa0ccdc4gmg87puydf2kxt5mgt0vteq4a22ktrcssg7ysmx64l90xa0k4z25wpuejngya833qeu9cdxvveynfscsskf5+8994790937 \
--fee 0 \
--protocol-params-file pparams.json \
--out-file tx.draft
cardano-cli
can handle the nesting of commands. For example, you can use cat
within cardano-cli
to read the addresses directly from the file.
cardano-cli conway transaction build-raw \
--tx-in e29e96a012c2443d59f2e53c156503a857c2f27c069ae003dab8125594038891#0 \
--tx-out "$(< payment2.addr)+1000000000" \
--tx-out "$(< payment.addr)+8994790937" \
--fee 0 \
--protocol-params-file pparams.json \
--out-file tx.draft
Let's explore the created tx.draft
file. It is a text envelope. The 'type' field says that it is an Unwitnessed Babbage era transaction. 'Unwitnessed' means that it has not been signed yet. The "cborHex" field encodes all transaction details:
cat tx.draft
{
"type": "Unwitnessed Tx BabbageEra",
"description": "Ledger Cddl Format",
"cborHex": "84a30081825820e29e96a012c2443d59f2e53c156503a857c2f27c069ae003dab812559403889100018282581d60b825c32db03b34efd9ff0b385d23aa2ea47dfd955b2df49d6297e31f1a3b9aca008258390062573d3d7e30dc551b41fc1e11a9558cba6d0b7b179057aa55963c4208f121b36abf2bcdd7daa2551c1e6653413a78c419e170d3319924d31b0000000218219e190200a0f5f6"
}
Use the transaction view
command to show the transaction body in a human-readable format:
cardano-cli debug transaction view --tx-body-file tx.draft
{
"auxiliary scripts": null,
"certificates": null,
"collateral inputs": [],
"era": "Babbage",
"fee": "0 Lovelace",
"inputs": [
"e29e96a012c2443d59f2e53c156503a857c2f27c069ae003dab8125594038891#0"
],
"metadata": null,
"mint": null,
"outputs": [
{
"address": "addr_test1vzuztsedkqanfm7elu9nshfr4gh2gl0aj4djmayav2t7x8ch3pg30",
"address era": "Shelley",
"amount": {
"lovelace": 1000000000
},
"network": "Testnet",
"payment credential key hash": "b825c32db03b34efd9ff0b385d23aa2ea47dfd955b2df49d6297e31f",
"reference script": null,
"stake reference": null
},
{
"address": "addr_test1qp39w0fa0ccdc4gmg87puydf2kxt5mgt0vteq4a22ktrcssg7ysmx64l90xa0k4z25wpuejngya833qeu9cdxvveynfscsskf5",
"address era": "Shelley",
"amount": {
"lovelace": 8994790937
},
"network": "Testnet",
"payment credential key hash": "62573d3d7e30dc551b41fc1e11a9558cba6d0b7b179057aa55963c42",
"reference script": null,
"stake reference": {
"stake credential key hash": "08f121b36abf2bcdd7daa2551c1e6653413a78c419e170d3319924d3"
}
}
],
"reference inputs": [],
"required signers (payment key hashes needed for scripts)": null,
"return collateral": null,
"total collateral": null,
"update proposal": null,
"validity range": {
"lower bound": null,
"upper bound": null
},
"withdrawals": null,
"witnesses": []
}
Calculating transaction fees and balancing a transaction
In Cardano, transaction fees are deterministic, meaning that you can know in advance how much a transaction will cost.
To process a transaction on the network, it must include fees specified within the transaction body. To calculate the exact cost, use the transaction calculate-min-fee
command, which takes tx.draft
and pparams.json
files as inputs. Within this command, specify details like the total number of inputs, outputs, and the required number of signatures. In this case, only one witness, the payment.skey
signature, is needed:
cardano-cli conway transaction calculate-min-fee \
--tx-body-file tx.draft \
--protocol-params-file pparams.json \
--witness-count 1
Running the command returns the fee that needs to be paid:
173993 Lovelace
With this, recalculate the change that needs to go to payment.addr
with a simple operation: Change = originalBalance - amountSent - Fee
:
echo $((9994790937 - 1000000000 - 173993))
8994616944
Re-run transaction build-raw
, include the fee, and adjust the change (the second tx-out). This completes the transaction body, and conventionally, it is saved into the tx.raw
file.
cardano-cli conway transaction build-raw \
--tx-in e29e96a012c2443d59f2e53c156503a857c2f27c069ae003dab8125594038891#0 \
--tx-out $(< payment2.addr)+1000000000 \
--tx-out $(< payment.addr)+8994616944 \
--fee 173993 \
--protocol-params-file pparams.json \
--out-file tx.raw
Signing the transaction
Sign the transaction with the transaction sign
command. You must sign with the payment.skey
that controls the UTXO you are trying to spend. This time, we produce the tx.signed
file:
cardano-cli conway transaction sign \
--tx-body-file tx.raw \
--signing-key-file payment.skey \
--testnet-magic 2 \
--out-file tx.signed
Inspecting tx.signed
with transaction view
reveals that the "witnesses"
field is no longer empty; it now contains the signature.
cardano-cli debug transaction view --tx-file tx.signed
{
"auxiliary scripts": null,
"certificates": null,
"collateral inputs": [],
"era": "Babbage",
"fee": "173993 Lovelace",
"inputs": [
"e29e96a012c2443d59f2e53c156503a857c2f27c069ae003dab8125594038891#0"
],
"metadata": null,
"mint": null,
"outputs": [
{
"address": "addr_test1vzuztsedkqanfm7elu9nshfr4gh2gl0aj4djmayav2t7x8ch3pg30",
"address era": "Shelley",
"amount": {
"lovelace": 1000000000
},
"network": "Testnet",
"payment credential key hash": "b825c32db03b34efd9ff0b385d23aa2ea47dfd955b2df49d6297e31f",
"reference script": null,
"stake reference": null
},
{
"address": "addr_test1qp39w0fa0ccdc4gmg87puydf2kxt5mgt0vteq4a22ktrcssg7ysmx64l90xa0k4z25wpuejngya833qeu9cdxvveynfscsskf5",
"address era": "Shelley",
"amount": {
"lovelace": 8994616944
},
"network": "Testnet",
"payment credential key hash": "62573d3d7e30dc551b41fc1e11a9558cba6d0b7b179057aa55963c42",
"reference script": null,
"stake reference": {
"stake credential key hash": "08f121b36abf2bcdd7daa2551c1e6653413a78c419e170d3319924d3"
}
}
],
"reference inputs": [],
"required signers (payment key hashes needed for scripts)": null,
"return collateral": null,
"total collateral": null,
"update proposal": null,
"validity range": {
"lower bound": null,
"upper bound": null
},
"withdrawals": null,
"witnesses": [
{
"key": "VKey (VerKeyEd25519DSIGN \"8e090717d4c91437d3b8c467acc850197485913efdbfb48114a4d6cf0ca2dc02\")",
"signature": "SignedDSIGN (SigEd25519DSIGN \"897d4774e3da7a9ff92cbfb36ba03443bad0473a449cd65a4855e4e167e6800267d6b38ba836cab05420c3c5a781855ea92e0266be511e96217dd91050abcb06\")"
}
]
}
Submitting the transaction
Submitting the transaction means sending it to the blockchain for processing by the stake pools and eventual inclusion in a block. While building and signing a transaction can be done without a running node, submitting the transaction requires an active connection to a running node. Use the tx.signed
file:
cardano-cli conway transaction submit \
--tx-file tx.signed
Transaction successfully submitted.
Building transactions with the build
command
Using the build
command for transaction construction simplifies the process significantly. However, it requires an active connection to the node to obtain the protocol parameters in real time. These parameters are then used to automatically calculate the fee to be paid. Additionally, the build
command offers the --change-address
flag, which automatically balances the transaction by sending the change to the specified address.
For example, let's send 500 ada (500000000 lovelace) to the payment2.addr
.
First, query the UTXOs of the input address:
cardano-cli query utxo --address $(< payment.addr)
TxHash TxIx Amount
--------------------------------------------------------------------------------------
c57f25ebf9cf1487b13deeb8449215c499f3d61c2836d84ab92a73b0bbaadd38 1 8994616944 lovelace + TxOutDatumNone
Build the transaction:
cardano-cli conway transaction build \
--tx-in c57f25ebf9cf1487b13deeb8449215c499f3d61c2836d84ab92a73b0bbaadd38#1 \
--tx-out $(< payment2.addr)+500000000 \
--change-address $(< payment.addr) \
--out-file tx.raw
Running this command returns the cost of the transaction fee:
Estimated transaction fee: Lovelace 167041
Inspecting tx.raw
with transaction view
reveals that the transaction body already includes the fee, and the transaction is already balanced.
cardano-cli debug transaction view --tx-file tx.raw
{
"auxiliary scripts": null,
"certificates": null,
"collateral inputs": [],
"era": "Babbage",
"fee": "167041 Lovelace",
"inputs": [
"c57f25ebf9cf1487b13deeb8449215c499f3d61c2836d84ab92a73b0bbaadd38#1"
],
"metadata": null,
"mint": null,
"outputs": [
{
"address": "addr_test1vzuztsedkqanfm7elu9nshfr4gh2gl0aj4djmayav2t7x8ch3pg30",
"address era": "Shelley",
"amount": {
"lovelace": 500000000
},
"network": "Testnet",
"payment credential key hash": "b825c32db03b34efd9ff0b385d23aa2ea47dfd955b2df49d6297e31f",
"reference script": null,
"stake reference": null
},
{
"address": "addr_test1qp39w0fa0ccdc4gmg87puydf2kxt5mgt0vteq4a22ktrcssg7ysmx64l90xa0k4z25wpuejngya833qeu9cdxvveynfscsskf5",
"address era": "Shelley",
"amount": {
"lovelace": 8494449903
},
"network": "Testnet",
"payment credential key hash": "62573d3d7e30dc551b41fc1e11a9558cba6d0b7b179057aa55963c42",
"reference script": null,
"stake reference": {
"stake credential key hash": "08f121b36abf2bcdd7daa2551c1e6653413a78c419e170d3319924d3"
}
}
],
"reference inputs": [],
"required signers (payment key hashes needed for scripts)": null,
"return collateral": null,
"total collateral": null,
"update proposal": null,
"validity range": {
"lower bound": null,
"upper bound": null
},
"withdrawals": null,
"witnesses": []
}
Signing the transaction
As previously, sign the transaction with the payment.skey
:
cardano-cli conway transaction sign \
--tx-body-file tx.raw \
--signing-key-file payment.skey \
--out-file tx.signed
Submitting the transaction
cardano-cli conway transaction submit \
--tx-file tx.signed
Transaction successfully submitted.
You can parse cardano-cli
JSON outputs with jq
to create programmatic workflows. For example, you can parse the output of query utxo
to obtain the first UTXO associated with the payment address and use it as input (--tx-in
) in transaction build
:
cardano-cli conway transaction build \
--tx-in $(cardano-cli query utxo --address $(< payment.addr) --output-json | jq -r 'keys[0]') \
--tx-out $(< payment.addr)+500000000 \
--change-address $(< payment.addr) \
--out-file tx.raw