Create Stakepool on Testnet
How to create a stakepool on Testnet

1. Install Cabal, GHC and Set PATH

Update packages and install Ubuntu dependencies:
1
sudo apt-get update -y
2
sudo apt-get upgrade -y
3
GETPKG_LIST="aptitude autoconf bc build-essential curl g++ git gnupg htop jq libffi-dev libgmp-dev libncursesw5 libpq-dev libsystemd-dev libssl-dev libtinfo-dev libtinfo-dev libtool make pkg-config rsync secure-delete tcptraceroute tmux wget zlib1g-dev"
4
sudo apt-get -y install ${GETPKG_LIST}
Copied!
Install Libsodium:
1
mkdir $HOME/git
2
cd $HOME/git
3
git clone https://github.com/input-output-hk/libsodium
4
cd libsodium
5
git checkout 66f017f1
6
./autogen.sh
7
./configure
8
make
9
sudo make install
Copied!
Install Cabal:
1
cd
2
wget https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz
3
tar -xf cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz
4
rm cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz cabal.sig
5
mkdir -p $HOME/.local/bin
6
mv cabal $HOME/.local/bin/
Copied!
Install GHC:
1
wget https://downloads.haskell.org/~ghc/8.6.5/ghc-8.6.5-x86_64-deb9-linux.tar.xz
2
tar -xf ghc-8.6.5-x86_64-deb9-linux.tar.xz
3
rm ghc-8.6.5-x86_64-deb9-linux.tar.xz
4
cd ghc-8.6.5
5
./configure
6
sudo make install
Copied!
Update PATH to include Cabal and GHC and add exports. Your node's location will be in $NODE_HOME. The cluster configuration is set by $NODE_CONFIG and $NODE_BUILD_NUM.
1
echo PATH="$HOME/.local/bin:$PATH" >> $HOME/.bashrc
2
echo export LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH" >> $HOME/.bashrc
3
echo export NODE_HOME=$HOME/cardano-my-node >> $HOME/.bashrc
4
echo export NODE_CONFIG=testnet>> $HOME/.bashrc
5
echo export NODE_BUILD_NUM=$(curl https://hydra.iohk.io/job/Cardano/iohk-nix/cardano-deployment/latest-finished/download/1/index.html | grep -e "build" | sed 's/.*build\/\([0-9]*\)\/download.*/\1/g') >> $HOME/.bashrc
6
source $HOME/.bashrc
Copied!
Update cabal and verify the correct versions were installed successfully.
1
cabal update
2
cabal -V
3
ghc -V
Copied!

9. Generate block producer keys

Testnet ADA do not have value and to ease the build all commands are assumed to be run on BP (Block Producer) node. Do not do this on your production stake pool.
The block-producer node requires you to create 3 keys as defined in the Shelley ledger specs:
  1. 1.
    stake pool cold key (node.cert)
  2. 2.
    stake pool hot key (kes.skey)
  3. 3.
    stake pool VRF key (vrf.skey)
First, make a KES key pair.
1
cd $NODE_HOME
2
cardano-cli shelley node key-gen-KES \
3
--verification-key-file kes.vkey \
4
--signing-key-file kes.skey
Copied!
KES (key evolving signature) keys are created to secure your stake pool against hackers who might compromise your keys.
On mainnet, you will need to regenerate the KES key every 90 days.
Cold keys must be generated and stored on your air-gapped offline machine. The cold keys are the files stored in $HOME/cold-keys.
1
mkdir $HOME/cold-keys
2
pushd $HOME/cold-keys
Copied!
Make a set of cold keys and create the cold counter file.
on Airgap
1
cardano-cli shelley node key-gen \
2
--cold-verification-key-file node.vkey \
3
--cold-signing-key-file node.skey \
4
--operational-certificate-issue-counter node.counter
Copied!
Be sure to back up your all your keys to another secure storage device. Make multiple copies.
BP
1
pushd +1
2
slotsPerKESPeriod=$(cat $NODE_HOME/${NODE_CONFIG}-shelley-genesis.json | jq -r '.slotsPerKESPeriod')
3
echo slotsPerKESPeriod: ${slotsPerKESPeriod}
Copied!
Before continuing, your node must be fully synchronized to the blockchain. Otherwise, you won't calculate the latest KES period.
Your node is synchronized when the epoch and slot# is equal to that found on a block explorer https://explorer.cardano-testnet.iohkdev.io/en/browse-blocks
1
slotNo=$(cardano-cli shelley query tip --testnet-magic 1097911063| jq -r '.slotNo')
2
echo slotNo: ${slotNo}
Copied!
Find the kesPeriod by dividing the slot tip number by the slotsPerKESPeriod.
1
kesPeriod=$((${slotNo} / ${slotsPerKESPeriod}))
2
echo kesPeriod: ${kesPeriod}
3
startKesPeriod=$(( ${kesPeriod} - 1 ))
4
echo startKesPeriod: ${startKesPeriod}
Copied!
With this calculation, you can generate a operational certificate for your pool.
Copy kes.vkey to your cold environment.
Change the startKesPeriod value accordingly.
Stake pool operators must provide an operational certificate to verify that the pool has the authority to run. The certificate includes the operator’s signature, and includes key information about the pool (addresses, keys, etc.). Operational certificates represent the link between the operator’s offline key and their operational key.
1
cardano-cli shelley node issue-op-cert \
2
--kes-verification-key-file kes.vkey \
3
--cold-signing-key-file $HOME/cold-keys/node.skey \
4
--operational-certificate-issue-counter $HOME/cold-keys/node.counter \
5
--kes-period $startKesPeriod \
6
--out-file node.cert
Copied!
Copy node.cert to your hot environment.
Make a VRF key pair
Open a new terminal window and stop your BP node by running the following:
1
killall cardano-node
Copied!
Update your BP startup script with the new KES, VRF and Operation Certificate.
1
cat > $NODE_HOME/startBlockProducingNode.sh << EOF
2
DIRECTORY=\$NODE_HOME
3
PORT=9000
4
HOSTADDR=0.0.0.0
5
TOPOLOGY=\${DIRECTORY}/${NODE_CONFIG}-topology.json
6
DB_PATH=\${DIRECTORY}/db
7
SOCKET_PATH=\${DIRECTORY}/db/socket
8
CONFIG=\${DIRECTORY}/${NODE_CONFIG}-config.json
9
KES=\${DIRECTORY}/kes.skey
10
VRF=\${DIRECTORY}/vrf.skey
11
CERT=\${DIRECTORY}/node.cert
12
cardano-node run --topology \${TOPOLOGY} --database-path \${DB_PATH} --socket-path \${SOCKET_PATH} --host-addr \${HOSTADDR} --port \${PORT} --config \${CONFIG} --shelley-kes-key \${KES} --shelley-vrf-key \${VRF} --shelley-operational-certificate \${CERT}
13
EOF
Copied!
To operate a stake pool, you need the KES, VRF key and Operational Certificate. Cold keys generate new operational certificates periodically.
Now start your block producer node.
1
cd $NODE_HOME
2
./startBlockProducingNode.sh
Copied!

10. Setup payment and stake keys

To create our transaction we will need the protocol parameters, so let’s query the parameters and save them in params.json
1
cardano-cli shelley query protocol-parameters \
2
--testnet-magic 1097911063 \
3
--out-file params.json
Copied!
Payment keys are used to send and receive payments and stake keys are used to manage stake delegations.
Create a new payment key pair: payment.skey & payment.vkey
1
###
2
### On BP node machine,
3
###
4
cd $NODE_HOME
5
cardano-cli shelley address key-gen \
6
--verification-key-file payment.vkey \
7
--signing-key-file payment.skey
Copied!
Create a new stake address key pair: stake.skey & stake.vkey.
1
###
2
### On air-gapped offline machine,
3
###
4
cardano-cli shelley stake-address key-gen \
5
--verification-key-file stake.vkey \
6
--signing-key-file stake.skey
Copied!
Create your stake address from the stake address verification key and store it in stake.addr
1
###
2
### On air-gapped offline machine,
3
###
4
cardano-cli shelley stake-address build \
5
--stake-verification-key-file stake.vkey \
6
--out-file stake.addr \
7
--testnet-magic 1097911063
Copied!
Build a payment address for the payment key payment.vkey which will delegate to the stake address, stake.vkey
1
###
2
### On air-gapped offline machine,
3
###
4
cardano-cli shelley address build \
5
--payment-verification-key-file payment.vkey \
6
--stake-verification-key-file stake.vkey \
7
--out-file payment.addr \
8
--testnet-magic 1097911063
Copied!
Next step is to fund your payment address. Fill in the form below with your payment.addr
Before continuing, your nodes must be fully synchronized to the blockchain. Otherwise, you won't see your funds.
After funding your account, check your payment address balance.
1
cardano-cli shelley query utxo \
2
--address $(cat payment.addr) \
3
--testnet-magic 1097911063
Copied!
You should see output similar to this. This is your unspent transaction output (UXTO).
1
TxHash TxIx Lovelace
2
----------------------------------------------------------------------------------------
3
c69b3e652fa237875a2c13593c3585dcd87f29233d746dd6697159c4fba17e83 0 997820683
Copied!

11. Register your stake address

Create a certificate, stake.cert, using the stake.vkey
1
cardano-cli shelley stake-address registration-certificate \
2
--stake-verification-key-file stake.vkey \
3
--out-file stake.cert
Copied!
You need to find the tip of the blockchain to set the ttl parameter properly.
1
currentSlot=$(cardano-cli shelley query tip --testnet-magic 1097911063 | jq -r '.slotNo')
2
echo Current Slot: $currentSlot
Copied!
Find your balance and UTXOs.
1
cardano-cli shelley query utxo \
2
--address $(cat payment.addr) \
3
--testnet-magic 1097911063 > fullUtxo.out
4
5
tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out
6
7
cat balance.out
8
9
tx_in=""
10
total_balance=0
11
while read -r utxo; do
12
in_addr=$(awk '{ print $1 }' <<< "${utxo}")
13
idx=$(awk '{ print $2 }' <<< "${utxo}")
14
utxo_balance=$(awk '{ print $3 }' <<< "${utxo}")
15
total_balance=$((${total_balance}+${utxo_balance}))
16
echo TxHash: ${in_addr}#${idx}
17
echo ADA: ${utxo_balance}
18
tx_in="${tx_in} --tx-in ${in_addr}#${idx}"
19
done < balance.out
20
txcnt=$(cat balance.out | wc -l)
21
echo Total ADA balance: ${total_balance}
22
echo Number of UTXOs: ${txcnt}
Copied!
Find the keyDeposit value.
1
keyDeposit=$(cat $NODE_HOME/params.json | jq -r '.keyDeposit')
2
echo keyDeposit: $keyDeposit
Copied!
Registration of a stake address certificate (keyDeposit) costs 2000000 lovelace.
Run the build-raw transaction command
The ttl value must be greater than the current tip. In this example, we use current slot + 10000.
1
cardano-cli shelley transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+0 \
4
--ttl $(( ${currentSlot} + 10000)) \
5
--fee 0 \
6
--out-file tx.tmp \
7
--certificate stake.cert
Copied!
Calculate the current minimum fee:
1
fee=$(cardano-cli shelley transaction calculate-min-fee \
2
--tx-body-file tx.tmp \
3
--tx-in-count ${txcnt} \
4
--tx-out-count 1 \
5
--testnet-magic 1097911063 \
6
--witness-count 2 \
7
--byron-witness-count 0 \
8
--protocol-params-file params.json | awk '{ print $1 }')
9
echo fee: $fee
Copied!
Ensure your balance is greater than cost of fee + keyDeposit or this will not work.
Calculate your change output.
1
txOut=$((${total_balance}-${keyDeposit}-${fee}))
2
echo Change Output: ${txOut}
Copied!
Build your transaction which will register your stake address.
1
cardano-cli shelley transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+${txOut} \
4
--ttl $(( ${currentSlot} + 10000)) \
5
--fee ${fee} \
6
--certificate-file stake.cert \
7
--out-file tx.raw
Copied!
Sign the transaction with both the payment and stake secret keys.
1
cardano-cli shelley transaction sign \
2
--tx-body-file tx.raw \
3
--signing-key-file payment.skey \
4
--signing-key-file stake.skey \
5
--testnet-magic 1097911063 \
6
--out-file tx.signed
Copied!
Sign transaction.
1
cardano-cli shelley transaction submit \
2
--tx-file tx.signed \
3
--testnet-magic 1097911063
Copied!

12. Register your stakepool

Create your pool's metadata with a JSON file. Update with your pool information.
ticker must be between 3-5 characters in length. Characters must be A-Z and 0-9 only. description cannot exceed 255 characters in length.
1
cat > poolMetaData.json << EOF
2
{
3
"name": "MyPoolName",
4
"description": "My pool description",
5
"ticker": "MPN",
6
"homepage": "https://myadapoolnamerocks.com"
7
}
8
EOF
Copied!
Calculate the hash of your metadata file.
1
cardano-cli shelley stake-pool metadata-hash --pool-metadata-file poolMetaData.json > poolMetaDataHash.txt
Copied!
Now upload your poolMetaData.json to your website or a public website such as https://pages.github.com/
Find the minimum pool cost.
1
minPoolCost=$(cat $NODE_HOME/params.json | jq -r .minPoolCost)
2
echo minPoolCost: ${minPoolCost}
Copied!
minPoolCost is 340000000 lovelace or 340 ADA. Therefore, your --pool-cost must be at a minimum this amount.
1
cardano-cli shelley stake-pool registration-certificate \
2
--cold-verification-key-file $HOME/cold-keys/node.vkey \
3
--vrf-verification-key-file vrf.vkey \
4
--pool-pledge 100000000000 \
5
--pool-cost 340000000 \
6
--pool-margin 0.01 \
7
--pool-reward-account-verification-key-file stake.vkey \
8
--pool-owner-stake-verification-key-file stake.vkey \
9
--testnet-magic 1097911063 \
10
--pool-relay-ipv4 81.108.149.100 \
11
--pool-relay-port 9001 \
12
--metadata-url <url where you uplaoded poolMetaData.json> \
13
--metadata-hash $(cat poolMetaDataHash.txt) \
14
--out-file pool.cert
Copied!
Pledge stake to your stake pool.
1
cardano-cli shelley stake-address delegation-certificate \
2
--stake-verification-key-file stake.vkey \
3
--cold-verification-key-file $HOME/cold-keys/node.vkey \
4
--out-file deleg.cert
Copied!
You need to find the tip of the blockchain to set the ttl parameter properly.
1
currentSlot=$(cardano-cli shelley query tip --testnet-magic 1097911063 | jq -r '.slotNo')
2
echo Current Slot: $currentSlot
Copied!
Find your balance and UTXOs.
1
cardano-cli shelley query utxo \
2
--address $(cat payment.addr) \
3
--testnet-magic 1097911063 > fullUtxo.out
4
5
tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out
6
7
cat balance.out
8
9
tx_in=""
10
total_balance=0
11
while read -r utxo; do
12
in_addr=$(awk '{ print $1 }' <<< "${utxo}")
13
idx=$(awk '{ print $2 }' <<< "${utxo}")
14
utxo_balance=$(awk '{ print $3 }' <<< "${utxo}")
15
total_balance=$((${total_balance}+${utxo_balance}))
16
echo TxHash: ${in_addr}#${idx}
17
echo ADA: ${utxo_balance}
18
tx_in="${tx_in} --tx-in ${in_addr}#${idx}"
19
done < balance.out
20
txcnt=$(cat balance.out | wc -l)
21
echo Total ADA balance: ${total_balance}
22
echo Number of UTXOs: ${txcnt}
Copied!
Find the keyDeposit value.
1
poolDeposit=$(cat $NODE_HOME/params.json | jq -r '.poolDeposit')
2
echo poolDeposit: $poolDeposit
Copied!
Registration of a stake address certificate (keyDeposit) costs 500000000 lovelace.
Run the build-raw transaction command
The ttl value must be greater than the current tip. In this example, we use current slot + 10000.
1
cardano-cli shelley transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+$(( ${total_balance} - ${poolDeposit})) \
4
--ttl $(( ${currentSlot} + 10000)) \
5
--fee 0 \
6
--certificate-file pool.cert \
7
--certificate-file deleg.cert \
8
--out-file tx.tmp
Copied!
Calculate the current minimum fee:
1
fee=$(cardano-cli shelley transaction calculate-min-fee \
2
--tx-body-file tx.tmp \
3
--tx-in-count ${txcnt} \
4
--tx-out-count 1 \
5
--testnet-magic 1097911063 \
6
--witness-count 3 \
7
--byron-witness-count 0 \
8
--protocol-params-file params.json | awk '{ print $1 }')
9
echo fee: $fee
Copied!
Ensure your balance is greater than cost of fee + minPoolCost or this will not work.
Calculate your change output.
1
txOut=$((${total_balance}-${poolDeposit}-${fee}))
2
echo txOut: ${txOut}
Copied!
Build your transaction:
1
cardano-cli shelley transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+${txOut} \
4
--ttl $(( ${currentSlot} + 10000)) \
5
--fee ${fee} \
6
--certificate-file pool.cert \
7
--certificate-file deleg.cert \
8
--out-file tx.raw
Copied!
Sign the transaction with both the payment and stake secret keys.
1
cardano-cli shelley transaction sign \
2
--tx-body-file tx.raw \
3
--signing-key-file payment.skey \
4
--signing-key-file $HOME/cold-keys/node.skey \
5
--signing-key-file stake.skey \
6
--testnet-magic 1097911063 \
7
--out-file tx.signed
Copied!
Sign transaction.
1
cardano-cli shelley transaction submit \
2
--tx-file tx.signed \
3
--testnet-magic 1097911063
Copied!

14. Configure your topology files

Shelley has been launched without peer-to-peer (p2p) node discovery so that means we will need to manually add trusted nodes in order to configure our topology. This is a critical step as skipping this step will result in your minted blocks being orphaned by the rest of the network.
Publishing your Relay Node with topologyUpdater.sh
This code has been taken from github and all credit to the developer. https://gist.github.com/gufmar/7e1bc16f8df62af953567a373d6a8f72
Create the topologyUpdater.sh script which publishes your node information to a topology fetch list.
1
###
2
### On relaynode1
3
###
4
cat > $NODE_HOME/topologyUpdater.sh << EOF
5
#!/bin/bash
6
# shellcheck disable=SC2086,SC2034
7
8
USERNAME=$(whoami)
9
CNODE_PORT=9001 # must match your relay node port as set in the startup command
10
CNODE_HOSTNAME="CHANGE ME" # optional. must resolve to the IP you are requesting from
11
CNODE_BIN="/usr/local/bin"
12
CNODE_HOME=$NODE_HOME
13
CNODE_LOG_DIR="\${CNODE_HOME}/logs"
14
GENESIS_JSON="\${CNODE_HOME}/${NODE_CONFIG}-shelley-genesis.json"
15
16
###########################################
17
18
NETWORKID=\$(jq -r .networkId \$GENESIS_JSON)
19
CNODE_VALENCY=1 # optional for multi-IP hostnames
20
NWMAGIC=\$(jq -r .networkMagic < \$GENESIS_JSON)
21
[[ "\${NETWORKID}" = "Mainnet" ]] && HASH_IDENTIFIER="--mainnet" || HASH_IDENTIFIER="--testnet-magic \${NWMAGIC}"
22
[[ "\${NWMAGIC}" = "764824073" ]] && NETWORK_IDENTIFIER="--mainnet" || NETWORK_IDENTIFIER="--testnet-magic \${NWMAGIC}"
23
24
export PATH="\${CNODE_BIN}:\${PATH}"
25
export CARDANO_NODE_SOCKET_PATH="\${CNODE_HOME}/db/socket"
26
27
blockNo=\$(cardano-cli shelley query tip \${NETWORK_IDENTIFIER} | jq -r .blockNo )
28
29
# Note:
30
# if you run your node in IPv4/IPv6 dual stack network configuration and want announced the
31
# IPv4 address only please add the -4 parameter to the curl command below (curl -4 -s ...)
32
if [ "\${CNODE_HOSTNAME}" != "CHANGE ME" ]; then
33
T_HOSTNAME="&hostname=\${CNODE_HOSTNAME}"
34
else
35
T_HOSTNAME=''
36
fi
37
38
if [ ! -d \${CNODE_LOG_DIR} ]; then
39
mkdir -p \${CNODE_LOG_DIR};
40
fi
41
42
curl -s "https://api.clio.one/htopology/v1/?port=\${CNODE_PORT}&blockNo=\${blockNo}&valency=\${CNODE_VALENCY}&magic=\${NWMAGIC}\${T_HOSTNAME}" | tee -a \$CNODE_LOG_DIR/topologyUpdater_lastresult.json
43
EOF
Copied!
Add permissions and run the updater script.
1
###
2
### On relaynode1
3
###
4
cd $NODE_HOME
5
chmod +x topologyUpdater.sh
6
./topologyUpdater.sh
Copied!
Update your relay node topology files
Create relay-topology_pull.sh script which fetches your relay node buddies and updates your topology file. Update with your block producer's public IP address.
1
###
2
### On relaynode1
3
###
4
cat > $NODE_HOME/relay-topology_pull.sh << EOF
5
#!/bin/bash
6
BLOCKPRODUCING_IP=<BLOCK PRODUCERS PUBLIC IP ADDRESS>
7
BLOCKPRODUCING_PORT=6000
8
curl -s -o /home/test/cardano-my-node/testnet-topology.json "https://api.clio.one/htopology/v1/fetch/?max=15&magic=1097911063&customPeers=${BLOCKPRODUCING_IP}:${BLOCKPRODUCING_PORT}:1|relays-new.cardano-testnet.iohkdev.io:3001:2"
9
EOF
Copied!
Add permissions and pull new topology files.
1
###
2
### On relaynode1
3
###
4
chmod +x relay-topology_pull.sh
5
./relay-topology_pull.sh
Copied!

18.4 Changing the pledge, fee, margin, etc.

Find the minimum pool cost.
block producer node
1
minPoolCost=$(cat $NODE_HOME/params.json | jq -r .minPoolCost)
2
echo minPoolCost: ${minPoolCost}
Copied!
minPoolCost is 340000000 lovelace or 340 ADA. Therefore, your --pool-cost must be at a minimum this amount.
If you're changing your poolMetaData.json, remember to calculate the hash of your metadata file and re-upload the updated poolMetaData.json file.
block producer node
1
cardano-cli shelley stake-pool metadata-hash --pool-metadata-file poolMetaData.json > poolMetaDataHash.txt
Copied!
Update the below registration-certificate transaction with your desired settings.
If you have multiple relay nodes, refer to section 12 and change your parameters appropriately.
metadata-url must be no longer than 64 characters.
air-gapped offline machine
1
cardano-cli shelley stake-pool registration-certificate \
2
--cold-verification-key-file $HOME/cold-keys/node.vkey \
3
--vrf-verification-key-file vrf.vkey \
4
--pool-pledge 100000000000 \
5
--pool-cost 340000000 \
6
--pool-margin 0.01 \
7
--pool-reward-account-verification-key-file stake.vkey \
8
--pool-owner-stake-verification-key-file stake.vkey \
9
--testnet-magic 1097911063 \
10
--pool-relay-ipv4 81.108.149.100 \
11
--pool-relay-port 9001 \
12
--metadata-url <url where you uplaoded poolMetaData.json> \
13
--metadata-hash $(cat poolMetaDataHash.txt) \
14
--out-file pool.cert
Copied!
Here we are pledging 1000 ADA with a fixed pool cost of 345 ADA and a pool margin of 20%.
Pledge stake to your stake pool.
air-gapped offline machine
1
cardano-cli shelley stake-address delegation-certificate \
2
--stake-verification-key-file stake.vkey \
3
--cold-verification-key-file $HOME/cold-keys/node.vkey \
4
--out-file deleg.cert
Copied!
Copy deleg.cert to your hot environment.
You need to find the tip of the blockchain to set the ttl parameter properly.
block producer node
1
currentSlot=$(cardano-cli shelley query tip --testnet-magic 1097911063 | jq -r '.slotNo')
2
echo Current Slot: $currentSlot
Copied!
Find your balance and UTXOs.
block producer node
1
cardano-cli shelley query utxo \
2
--address $(cat payment.addr) \
3
--testnet-magic 1097911063 > fullUtxo.out
4
5
tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out
6
7
cat balance.out
8
9
tx_in=""
10
total_balance=0
11
while read -r utxo; do
12
in_addr=$(awk '{ print $1 }' <<< "${utxo}")
13
idx=$(awk '{ print $2 }' <<< "${utxo}")
14
utxo_balance=$(awk '{ print $3 }' <<< "${utxo}")
15
total_balance=$((${total_balance}+${utxo_balance}))
16
echo TxHash: ${in_addr}#${idx}
17
echo ADA: ${utxo_balance}
18
tx_in="${tx_in} --tx-in ${in_addr}#${idx}"
19
done < balance.out
20
txcnt=$(cat balance.out | wc -l)
21
echo Total ADA balance: ${total_balance}
22
echo Number of UTXOs: ${txcnt}
Copied!
Run the build-raw transaction command.
The ttl value must be greater than the current tip. In this example, we use current slot + 10000.
block producer node
1
cardano-cli shelley transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+${total_balance} \
4
--ttl $(( ${currentSlot} + 10000)) \
5
--fee 0 \
6
--certificate-file pool.cert \
7
--certificate-file deleg.cert \
8
--out-file tx.tmp
Copied!
Calculate the minimum fee:
block producer node
1
fee=$(cardano-cli shelley transaction calculate-min-fee \
2
--tx-body-file tx.tmp \
3
--tx-in-count ${txcnt} \
4
--tx-out-count 1 \
5
--testnet-magic 1097911063 \
6
--witness-count 3 \
7
--byron-witness-count 0 \
8
--protocol-params-file params.json | awk '{ print $1 }')
9
echo fee: $fee
Copied!
Calculate your change output.
block producer node
1
txOut=$((${total_balance}-${fee}))
2
echo txOut: ${txOut}
Copied!
Build the transaction.
block producer node
1
cardano-cli shelley transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+${txOut} \
4
--ttl $(( ${currentSlot} + 10000)) \
5
--fee ${fee} \
6
--certificate-file pool.cert \
7
--certificate-file deleg.cert \
8
--out-file tx.raw
Copied!
Copy tx.raw to your cold environment.
Sign the transaction.
air-gapped offline machine
1
cardano-cli shelley transaction sign \
2
--tx-body-file tx.raw \
3
--signing-key-file payment.skey \
4
--signing-key-file $HOME/cold-keys/node.skey \
5
--signing-key-file stake.skey \
6
--testnet-magic 1097911063 \
7
--out-file tx.signed
Copied!
Copy tx.signed to your hot environment.
Send the transaction.
block producer node
1
cardano-cli shelley transaction submit \
2
--tx-file tx.signed \
3
--testnet-magic 1097911063
Copied!
Changes take effect next epoch. After the next epoch transition, verify that your pool settings are correct.
block producer node
1
cardano-cli shelley query ledger-state --testnet-magic 1097911063 --out-file ledger-state.json
2
jq -r '.esLState._delegationState._pstate._pParams."'"$(cat stakepoolid.txt)"'" //
Copied!

18.9 Send a simple transaction example

If you have not downloaded and install bech32 from https://github.com/input-output-hk/bech32/releases
1
mkdir $HOME/bech32
2
cd $HOME/bech32
3
wget https://github.com/input-output-hk/bech32/releases/download/v1.1.0/bech32-v1.1.0-linux64.tar.gz
4
tar -xzvf bech32-v1.1.0-linux64.tar.gz
5
chmod +x $HOME/bech32/bin/bech32
6
cd $NODE_HOME
Copied!
Example sends 1000 ADA to Love2Stake address
First, find the tip of the blockchain to set the ttl parameter properly.
block producer node
1
currentSlot=$(cardano-cli shelley query tip --testnet-magic 1097911063 | jq -r '.slotNo')
2
echo Current Slot: $currentSlot
Copied!
Set the amount to send in lovelaces.
Remember 1 ADA = 1,000,000 lovelaces.
block producer node
1
amountToSend=99000000000000
2
echo amountToSend: $amountToSend
Copied!
cho "daedalus-address" | bech32 addr_test
Set the destination address which is where you're sending funds to.
block producer node
1
testnetDaedalusAddress=addr1qzgc2yx9p55x50ggc3jvr8tfmahx23fvj2zqmqrvyg3he0z89uja3cpcdnpstavx5f37md2xuc03v84zkphz23djd62qdyu0u5
2
echo ${testnetDaedalusAddress} | destinationAddress=$HOME/bech32/bin/bech32
3
echo destinationAddress: $destinationAddress
Copied!
Find your balance and UTXOs.
block producer node
1
cardano-cli shelley query utxo \
2
--address $(cat payment.addr) \
3
--testnet-magic 1097911063 > fullUtxo.out
4
5
tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out
6
7
cat balance.out
8
9
tx_in=""
10
total_balance=0
11
while read -r utxo; do
12
in_addr=$(awk '{ print $1 }' <<< "${utxo}")
13
idx=$(awk '{ print $2 }' <<< "${utxo}")
14
utxo_balance=$(awk '{ print $3 }' <<< "${utxo}")
15
total_balance=$((${total_balance}+${utxo_balance}))
16
echo TxHash: ${in_addr}#${idx}
17
echo ADA: ${utxo_balance}
18
tx_in="${tx_in} --tx-in ${in_addr}#${idx}"
19
done < balance.out
20
txcnt=$(cat balance.out | wc -l)
21
echo Total ADA balance: ${total_balance}
22
echo Number of UTXOs: ${txcnt}
Copied!
Run the build-raw transaction command.
block producer node
1
cardano-cli shelley transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+0 \
4
--tx-out ${destinationAddress}+0 \
5
--ttl $(( ${currentSlot} + 10000)) \
6
--fee 0 \
7
--out-file tx.tmp
Copied!
Calculate the current minimum fee:
block producer node
1
fee=$(cardano-cli shelley transaction calculate-min-fee \
2
--tx-body-file tx.tmp \
3
--tx-in-count ${txcnt} \
4
--tx-out-count 2 \
5
--testnet-magic 1097911063 \
6
--witness-count 1 \
7
--byron-witness-count 0 \
8
--protocol-params-file params.json | awk '{ print $1 }')
9
echo fee: $fee
Copied!
Calculate your change output.
block producer node
1
txOut=$((${total_balance}-${fee}-${amountToSend}))
2
echo Change Output: ${txOut}
Copied!
Build your transaction.
block producer node
1
cardano-cli shelley transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+${txOut} \
4
--tx-out ${destinationAddress}+${amountToSend} \
5
--ttl $(( ${currentSlot} + 10000)) \
6
--fee ${fee} \
7
--out-file tx.raw
Copied!
Copy tx.raw to your cold environment.
Sign the transaction with both the payment and stake secret keys.
air-gapped offline machine
1
cardano-cli shelley transaction sign \
2
--tx-body-file tx.raw \
3
--signing-key-file payment.skey \
4
--testnet-magic 1097911063 \
5
--out-file tx.signed
Copied!
Copy tx.signed to your hot environment.
Send the signed transaction.
block producer node
1
cardano-cli shelley transaction submit \
2
--tx-file tx.signed \
3
--testnet-magic 1097911063
Copied!
Check if the funds arrived.
block producer node
1
cardano-cli shelley query utxo \
2
--address ${destinationAddress} \
3
--testnet-magic 1097911063
Copied!
You should see output similar to this showing the funds you sent.
1
TxHash TxIx Lovelace
2
----------------------------------------------------------------------------------------
3
100322a39d02c2ead.... 0 1000000
Copied!
Last modified 1yr ago