Create Stakepool on Testnet

How to create a stakepool on Testnet

1. Install Cabal, GHC and Set PATH

Update packages and install Ubuntu dependencies:

sudo apt-get update -y
sudo apt-get upgrade -y
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"
sudo apt-get -y install ${GETPKG_LIST}

Install Libsodium:

mkdir $HOME/git
cd $HOME/git
git clone https://github.com/input-output-hk/libsodium
cd libsodium
git checkout 66f017f1
./autogen.sh
./configure
make
sudo make install

Install Cabal:

cd
wget https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz
tar -xf cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz
rm cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz cabal.sig
mkdir -p $HOME/.local/bin
mv cabal $HOME/.local/bin/

Install GHC:

wget https://downloads.haskell.org/~ghc/8.6.5/ghc-8.6.5-x86_64-deb9-linux.tar.xz
tar -xf ghc-8.6.5-x86_64-deb9-linux.tar.xz
rm ghc-8.6.5-x86_64-deb9-linux.tar.xz
cd ghc-8.6.5
./configure
sudo make install

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.

echo PATH="$HOME/.local/bin:$PATH" >> $HOME/.bashrc
echo export LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH" >> $HOME/.bashrc
echo export NODE_HOME=$HOME/cardano-my-node >> $HOME/.bashrc
echo export NODE_CONFIG=testnet>> $HOME/.bashrc
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
source $HOME/.bashrc

Update cabal and verify the correct versions were installed successfully.

cabal update
cabal -V
ghc -V

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. stake pool cold key (node.cert)

  2. stake pool hot key (kes.skey)

  3. stake pool VRF key (vrf.skey)

First, make a KES key pair.

cd $NODE_HOME
cardano-cli shelley node key-gen-KES \
    --verification-key-file kes.vkey \
    --signing-key-file kes.skey

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.

mkdir $HOME/cold-keys
pushd $HOME/cold-keys

Make a set of cold keys and create the cold counter file.

on Airgap

cardano-cli shelley node key-gen \
    --cold-verification-key-file node.vkey \
    --cold-signing-key-file node.skey \
    --operational-certificate-issue-counter node.counter

Be sure to back up your all your keys to another secure storage device. Make multiple copies.

pushd +1
slotsPerKESPeriod=$(cat $NODE_HOME/${NODE_CONFIG}-shelley-genesis.json | jq -r '.slotsPerKESPeriod')
echo slotsPerKESPeriod: ${slotsPerKESPeriod}

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

slotNo=$(cardano-cli shelley query tip --testnet-magic 1097911063| jq -r '.slotNo')
echo slotNo: ${slotNo}

Find the kesPeriod by dividing the slot tip number by the slotsPerKESPeriod.

kesPeriod=$((${slotNo} / ${slotsPerKESPeriod}))
echo kesPeriod: ${kesPeriod}
startKesPeriod=$(( ${kesPeriod} - 1 ))
echo startKesPeriod: ${startKesPeriod}

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.

cardano-cli shelley node issue-op-cert \
    --kes-verification-key-file kes.vkey \
    --cold-signing-key-file $HOME/cold-keys/node.skey \
    --operational-certificate-issue-counter $HOME/cold-keys/node.counter \
    --kes-period $startKesPeriod \
    --out-file node.cert

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:

killall cardano-node

Update your BP startup script with the new KES, VRF and Operation Certificate.

cat > $NODE_HOME/startBlockProducingNode.sh << EOF 
DIRECTORY=\$NODE_HOME
PORT=9000
HOSTADDR=0.0.0.0
TOPOLOGY=\${DIRECTORY}/${NODE_CONFIG}-topology.json
DB_PATH=\${DIRECTORY}/db
SOCKET_PATH=\${DIRECTORY}/db/socket
CONFIG=\${DIRECTORY}/${NODE_CONFIG}-config.json
KES=\${DIRECTORY}/kes.skey
VRF=\${DIRECTORY}/vrf.skey
CERT=\${DIRECTORY}/node.cert
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}
EOF

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.

cd $NODE_HOME
./startBlockProducingNode.sh

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

cardano-cli shelley query protocol-parameters \
    --testnet-magic 1097911063 \
    --out-file params.json

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

###
### On BP node machine,
###
cd $NODE_HOME
cardano-cli shelley address key-gen \
    --verification-key-file payment.vkey \
    --signing-key-file payment.skey

Create a new stake address key pair: stake.skey & stake.vkey.

###
### On air-gapped offline machine,
###
cardano-cli shelley stake-address key-gen \
    --verification-key-file stake.vkey \
    --signing-key-file stake.skey

Create your stake address from the stake address verification key and store it in stake.addr

###
### On air-gapped offline machine,
###
cardano-cli shelley stake-address build \
    --stake-verification-key-file stake.vkey \
    --out-file stake.addr \
    --testnet-magic 1097911063

Build a payment address for the payment key payment.vkey which will delegate to the stake address, stake.vkey

###
### On air-gapped offline machine,
###
cardano-cli shelley address build \
    --payment-verification-key-file payment.vkey \
    --stake-verification-key-file stake.vkey \
    --out-file payment.addr \
    --testnet-magic 1097911063

Next step is to fund your payment address. Fill in the form below with your payment.addr

https://docs.google.com/forms/d/1BmPI3PsBChSIrpKBgroOjscRXe1vI7iQDFLNGVR6y2o/

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.

cardano-cli shelley query utxo \
    --address $(cat payment.addr) \
    --testnet-magic 1097911063

You should see output similar to this. This is your unspent transaction output (UXTO).

                           TxHash                                 TxIx        Lovelace
----------------------------------------------------------------------------------------
c69b3e652fa237875a2c13593c3585dcd87f29233d746dd6697159c4fba17e83     0         997820683

11. Register your stake address

Create a certificate, stake.cert, using the stake.vkey

cardano-cli shelley stake-address registration-certificate \
    --stake-verification-key-file stake.vkey \
    --out-file stake.cert

You need to find the tip of the blockchain to set the ttl parameter properly.

currentSlot=$(cardano-cli shelley query tip --testnet-magic 1097911063 | jq -r '.slotNo')
echo Current Slot: $currentSlot

Find your balance and UTXOs.

cardano-cli shelley query utxo \
    --address $(cat payment.addr) \
    --testnet-magic 1097911063 > fullUtxo.out

tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out

cat balance.out

tx_in=""
total_balance=0
while read -r utxo; do
    in_addr=$(awk '{ print $1 }' <<< "${utxo}")
    idx=$(awk '{ print $2 }' <<< "${utxo}")
    utxo_balance=$(awk '{ print $3 }' <<< "${utxo}")
    total_balance=$((${total_balance}+${utxo_balance}))
    echo TxHash: ${in_addr}#${idx}
    echo ADA: ${utxo_balance}
    tx_in="${tx_in} --tx-in ${in_addr}#${idx}"
done < balance.out
txcnt=$(cat balance.out | wc -l)
echo Total ADA balance: ${total_balance}
echo Number of UTXOs: ${txcnt}

Find the keyDeposit value.

keyDeposit=$(cat $NODE_HOME/params.json | jq -r '.keyDeposit')
echo keyDeposit: $keyDeposit

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.

cardano-cli shelley transaction build-raw \
    ${tx_in} \
    --tx-out $(cat payment.addr)+0 \
    --ttl $(( ${currentSlot} + 10000)) \
    --fee 0 \
    --out-file tx.tmp \
    --certificate stake.cert

Calculate the current minimum fee:

fee=$(cardano-cli shelley transaction calculate-min-fee \
    --tx-body-file tx.tmp \
    --tx-in-count ${txcnt} \
    --tx-out-count 1 \
    --testnet-magic 1097911063 \
    --witness-count 2 \
    --byron-witness-count 0 \
    --protocol-params-file params.json | awk '{ print $1 }')
echo fee: $fee

Ensure your balance is greater than cost of fee + keyDeposit or this will not work.

Calculate your change output.

txOut=$((${total_balance}-${keyDeposit}-${fee}))
echo Change Output: ${txOut}

Build your transaction which will register your stake address.

cardano-cli shelley transaction build-raw \
    ${tx_in} \
    --tx-out $(cat payment.addr)+${txOut} \
    --ttl $(( ${currentSlot} + 10000)) \
    --fee ${fee} \
    --certificate-file stake.cert \
    --out-file tx.raw

Sign the transaction with both the payment and stake secret keys.

cardano-cli shelley transaction sign \
    --tx-body-file tx.raw \
    --signing-key-file payment.skey \
    --signing-key-file stake.skey \
    --testnet-magic 1097911063 \
    --out-file tx.signed

Sign transaction.

cardano-cli shelley transaction submit \
    --tx-file tx.signed \
    --testnet-magic 1097911063

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.

cat > poolMetaData.json << EOF
{
"name": "MyPoolName",
"description": "My pool description",
"ticker": "MPN",
"homepage": "https://myadapoolnamerocks.com"
}
EOF

Calculate the hash of your metadata file.

cardano-cli shelley stake-pool metadata-hash --pool-metadata-file poolMetaData.json > poolMetaDataHash.txt

Now upload your poolMetaData.json to your website or a public website such as https://pages.github.com/

Find the minimum pool cost.

minPoolCost=$(cat $NODE_HOME/params.json | jq -r .minPoolCost)
echo minPoolCost: ${minPoolCost}

minPoolCost is 340000000 lovelace or 340 ADA. Therefore, your --pool-cost must be at a minimum this amount.

cardano-cli shelley stake-pool registration-certificate \
    --cold-verification-key-file $HOME/cold-keys/node.vkey \
    --vrf-verification-key-file vrf.vkey \
    --pool-pledge 100000000000 \
    --pool-cost 340000000 \
    --pool-margin 0.01 \
    --pool-reward-account-verification-key-file stake.vkey \
    --pool-owner-stake-verification-key-file stake.vkey \
    --testnet-magic 1097911063 \
    --pool-relay-ipv4 81.108.149.100 \
    --pool-relay-port 9001 \
    --metadata-url <url where you uplaoded poolMetaData.json> \
    --metadata-hash $(cat poolMetaDataHash.txt) \
    --out-file pool.cert

Pledge stake to your stake pool.

cardano-cli shelley stake-address delegation-certificate \
    --stake-verification-key-file stake.vkey \
    --cold-verification-key-file $HOME/cold-keys/node.vkey \
    --out-file deleg.cert

You need to find the tip of the blockchain to set the ttl parameter properly.

currentSlot=$(cardano-cli shelley query tip --testnet-magic 1097911063 | jq -r '.slotNo')
echo Current Slot: $currentSlot

Find your balance and UTXOs.

cardano-cli shelley query utxo \
    --address $(cat payment.addr) \
    --testnet-magic 1097911063 > fullUtxo.out

tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out

cat balance.out

tx_in=""
total_balance=0
while read -r utxo; do
    in_addr=$(awk '{ print $1 }' <<< "${utxo}")
    idx=$(awk '{ print $2 }' <<< "${utxo}")
    utxo_balance=$(awk '{ print $3 }' <<< "${utxo}")
    total_balance=$((${total_balance}+${utxo_balance}))
    echo TxHash: ${in_addr}#${idx}
    echo ADA: ${utxo_balance}
    tx_in="${tx_in} --tx-in ${in_addr}#${idx}"
done < balance.out
txcnt=$(cat balance.out | wc -l)
echo Total ADA balance: ${total_balance}
echo Number of UTXOs: ${txcnt}

Find the keyDeposit value.

poolDeposit=$(cat $NODE_HOME/params.json | jq -r '.poolDeposit')
echo poolDeposit: $poolDeposit

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.

cardano-cli shelley transaction build-raw \
    ${tx_in} \
    --tx-out $(cat payment.addr)+$(( ${total_balance} - ${poolDeposit}))  \
    --ttl $(( ${currentSlot} + 10000)) \
    --fee 0 \
    --certificate-file pool.cert \
    --certificate-file deleg.cert \
    --out-file tx.tmp

Calculate the current minimum fee:

fee=$(cardano-cli shelley transaction calculate-min-fee \
    --tx-body-file tx.tmp \
    --tx-in-count ${txcnt} \
    --tx-out-count 1 \
    --testnet-magic 1097911063 \
    --witness-count 3 \
    --byron-witness-count 0 \
    --protocol-params-file params.json | awk '{ print $1 }')
echo fee: $fee

Ensure your balance is greater than cost of fee + minPoolCost or this will not work.

Calculate your change output.

txOut=$((${total_balance}-${poolDeposit}-${fee}))
echo txOut: ${txOut}

Build your transaction:

cardano-cli shelley transaction build-raw \
    ${tx_in} \
    --tx-out $(cat payment.addr)+${txOut} \
    --ttl $(( ${currentSlot} + 10000)) \
    --fee ${fee} \
    --certificate-file pool.cert \
    --certificate-file deleg.cert \
    --out-file tx.raw

Sign the transaction with both the payment and stake secret keys.

cardano-cli shelley transaction sign \
    --tx-body-file tx.raw \
    --signing-key-file payment.skey \
    --signing-key-file $HOME/cold-keys/node.skey \
    --signing-key-file stake.skey \
    --testnet-magic 1097911063 \
    --out-file tx.signed

Sign transaction.

cardano-cli shelley transaction submit \
    --tx-file tx.signed \
    --testnet-magic 1097911063

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.

###
### On relaynode1
###
cat > $NODE_HOME/topologyUpdater.sh << EOF
#!/bin/bash
# shellcheck disable=SC2086,SC2034
 
USERNAME=$(whoami)
CNODE_PORT=9001 # must match your relay node port as set in the startup command
CNODE_HOSTNAME="CHANGE ME"  # optional. must resolve to the IP you are requesting from
CNODE_BIN="/usr/local/bin"
CNODE_HOME=$NODE_HOME
CNODE_LOG_DIR="\${CNODE_HOME}/logs"
GENESIS_JSON="\${CNODE_HOME}/${NODE_CONFIG}-shelley-genesis.json"

###########################################

NETWORKID=\$(jq -r .networkId \$GENESIS_JSON)
CNODE_VALENCY=1   # optional for multi-IP hostnames
NWMAGIC=\$(jq -r .networkMagic < \$GENESIS_JSON)
[[ "\${NETWORKID}" = "Mainnet" ]] && HASH_IDENTIFIER="--mainnet" || HASH_IDENTIFIER="--testnet-magic \${NWMAGIC}"
[[ "\${NWMAGIC}" = "764824073" ]] && NETWORK_IDENTIFIER="--mainnet" || NETWORK_IDENTIFIER="--testnet-magic \${NWMAGIC}"
 
export PATH="\${CNODE_BIN}:\${PATH}"
export CARDANO_NODE_SOCKET_PATH="\${CNODE_HOME}/db/socket"
 
blockNo=\$(cardano-cli shelley query tip \${NETWORK_IDENTIFIER} | jq -r .blockNo )
 
# Note:
# if you run your node in IPv4/IPv6 dual stack network configuration and want announced the
# IPv4 address only please add the -4 parameter to the curl command below  (curl -4 -s ...)
if [ "\${CNODE_HOSTNAME}" != "CHANGE ME" ]; then
  T_HOSTNAME="&hostname=\${CNODE_HOSTNAME}"
else
  T_HOSTNAME=''
fi

if [ ! -d \${CNODE_LOG_DIR} ]; then
  mkdir -p \${CNODE_LOG_DIR};
fi
 
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
EOF

Add permissions and run the updater script.

###
### On relaynode1
###
cd $NODE_HOME
chmod +x topologyUpdater.sh
./topologyUpdater.sh

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.

###
### On relaynode1
###
cat > $NODE_HOME/relay-topology_pull.sh << EOF
#!/bin/bash
BLOCKPRODUCING_IP=<BLOCK PRODUCERS PUBLIC IP ADDRESS>
BLOCKPRODUCING_PORT=6000
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"
EOF

Add permissions and pull new topology files.

###
### On relaynode1
###
chmod +x relay-topology_pull.sh
./relay-topology_pull.sh

18.4 Changing the pledge, fee, margin, etc.

Find the minimum pool cost.

minPoolCost=$(cat $NODE_HOME/params.json | jq -r .minPoolCost)
echo minPoolCost: ${minPoolCost}

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.

cardano-cli shelley stake-pool metadata-hash --pool-metadata-file poolMetaData.json > poolMetaDataHash.txt

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.

cardano-cli shelley stake-pool registration-certificate \
    --cold-verification-key-file $HOME/cold-keys/node.vkey \
    --vrf-verification-key-file vrf.vkey \
    --pool-pledge 100000000000 \
    --pool-cost 340000000 \
    --pool-margin 0.01 \
    --pool-reward-account-verification-key-file stake.vkey \
    --pool-owner-stake-verification-key-file stake.vkey \
    --testnet-magic 1097911063 \
    --pool-relay-ipv4 81.108.149.100 \
    --pool-relay-port 9001 \
    --metadata-url <url where you uplaoded poolMetaData.json> \
    --metadata-hash $(cat poolMetaDataHash.txt) \
    --out-file pool.cert

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.

cardano-cli shelley stake-address delegation-certificate \
    --stake-verification-key-file stake.vkey \
    --cold-verification-key-file $HOME/cold-keys/node.vkey \
    --out-file deleg.cert

Copy deleg.cert to your hot environment.

You need to find the tip of the blockchain to set the ttl parameter properly.

currentSlot=$(cardano-cli shelley query tip  --testnet-magic 1097911063 | jq -r '.slotNo')
echo Current Slot: $currentSlot

Find your balance and UTXOs.

cardano-cli shelley query utxo \
    --address $(cat payment.addr) \
     --testnet-magic 1097911063 > fullUtxo.out

tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out

cat balance.out

tx_in=""
total_balance=0
while read -r utxo; do
    in_addr=$(awk '{ print $1 }' <<< "${utxo}")
    idx=$(awk '{ print $2 }' <<< "${utxo}")
    utxo_balance=$(awk '{ print $3 }' <<< "${utxo}")
    total_balance=$((${total_balance}+${utxo_balance}))
    echo TxHash: ${in_addr}#${idx}
    echo ADA: ${utxo_balance}
    tx_in="${tx_in} --tx-in ${in_addr}#${idx}"
done < balance.out
txcnt=$(cat balance.out | wc -l)
echo Total ADA balance: ${total_balance}
echo Number of UTXOs: ${txcnt}

Run the build-raw transaction command.

The ttl value must be greater than the current tip. In this example, we use current slot + 10000.

cardano-cli shelley transaction build-raw \
    ${tx_in} \
    --tx-out $(cat payment.addr)+${total_balance} \
    --ttl $(( ${currentSlot} + 10000)) \
    --fee 0 \
    --certificate-file pool.cert \
    --certificate-file deleg.cert \
    --out-file tx.tmp

Calculate the minimum fee:

fee=$(cardano-cli shelley transaction calculate-min-fee \
    --tx-body-file tx.tmp \
    --tx-in-count ${txcnt} \
    --tx-out-count 1 \
     --testnet-magic 1097911063 \
    --witness-count 3 \
    --byron-witness-count 0 \
    --protocol-params-file params.json | awk '{ print $1 }')
echo fee: $fee

Calculate your change output.

txOut=$((${total_balance}-${fee}))
echo txOut: ${txOut}

Build the transaction.

cardano-cli shelley transaction build-raw \
    ${tx_in} \
    --tx-out $(cat payment.addr)+${txOut} \
    --ttl $(( ${currentSlot} + 10000)) \
    --fee ${fee} \
    --certificate-file pool.cert \
    --certificate-file deleg.cert \
    --out-file tx.raw

Copy tx.raw to your cold environment.

Sign the transaction.

cardano-cli shelley transaction sign \
    --tx-body-file tx.raw \
    --signing-key-file payment.skey \
    --signing-key-file $HOME/cold-keys/node.skey \
    --signing-key-file stake.skey \
     --testnet-magic 1097911063 \
    --out-file tx.signed

Copy tx.signed to your hot environment.

Send the transaction.

cardano-cli shelley transaction submit \
    --tx-file tx.signed \
     --testnet-magic 1097911063

Changes take effect next epoch. After the next epoch transition, verify that your pool settings are correct.

cardano-cli shelley query ledger-state  --testnet-magic 1097911063 --out-file ledger-state.json
jq -r '.esLState._delegationState._pstate._pParams."'"$(cat stakepoolid.txt)"'"  // 

18.9 Send a simple transaction example

If you have not downloaded and install bech32 from https://github.com/input-output-hk/bech32/releases

mkdir $HOME/bech32
cd $HOME/bech32
wget https://github.com/input-output-hk/bech32/releases/download/v1.1.0/bech32-v1.1.0-linux64.tar.gz
tar -xzvf bech32-v1.1.0-linux64.tar.gz
chmod +x $HOME/bech32/bin/bech32
cd $NODE_HOME

Example sends 1000 ADA to Love2Stake address

First, find the tip of the blockchain to set the ttl parameter properly.

currentSlot=$(cardano-cli shelley query tip --testnet-magic 1097911063 | jq -r '.slotNo')
echo Current Slot: $currentSlot

Set the amount to send in lovelaces. Remember 1 ADA = 1,000,000 lovelaces.

amountToSend=99000000000000
echo amountToSend: $amountToSend

cho "daedalus-address" | bech32 addr_test

Set the destination address which is where you're sending funds to.

testnetDaedalusAddress=addr1qzgc2yx9p55x50ggc3jvr8tfmahx23fvj2zqmqrvyg3he0z89uja3cpcdnpstavx5f37md2xuc03v84zkphz23djd62qdyu0u5
echo ${testnetDaedalusAddress} | destinationAddress=$HOME/bech32/bin/bech32
echo destinationAddress: $destinationAddress

Find your balance and UTXOs.

cardano-cli shelley query utxo \
    --address $(cat payment.addr) \
    --testnet-magic 1097911063 > fullUtxo.out

tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out

cat balance.out

tx_in=""
total_balance=0
while read -r utxo; do
    in_addr=$(awk '{ print $1 }' <<< "${utxo}")
    idx=$(awk '{ print $2 }' <<< "${utxo}")
    utxo_balance=$(awk '{ print $3 }' <<< "${utxo}")
    total_balance=$((${total_balance}+${utxo_balance}))
    echo TxHash: ${in_addr}#${idx}
    echo ADA: ${utxo_balance}
    tx_in="${tx_in} --tx-in ${in_addr}#${idx}"
done < balance.out
txcnt=$(cat balance.out | wc -l)
echo Total ADA balance: ${total_balance}
echo Number of UTXOs: ${txcnt}

Run the build-raw transaction command.

cardano-cli shelley transaction build-raw \
    ${tx_in} \
    --tx-out $(cat payment.addr)+0 \
    --tx-out ${destinationAddress}+0 \
    --ttl $(( ${currentSlot} + 10000)) \
    --fee 0 \
    --out-file tx.tmp    

Calculate the current minimum fee:

fee=$(cardano-cli shelley transaction calculate-min-fee \
    --tx-body-file tx.tmp \
    --tx-in-count ${txcnt} \
    --tx-out-count 2 \
    --testnet-magic 1097911063 \
    --witness-count 1 \
    --byron-witness-count 0 \
    --protocol-params-file params.json | awk '{ print $1 }')
echo fee: $fee

Calculate your change output.

txOut=$((${total_balance}-${fee}-${amountToSend}))
echo Change Output: ${txOut}

Build your transaction.

cardano-cli shelley transaction build-raw \
    ${tx_in} \
    --tx-out $(cat payment.addr)+${txOut} \
    --tx-out ${destinationAddress}+${amountToSend} \
    --ttl $(( ${currentSlot} + 10000)) \
    --fee ${fee} \
    --out-file tx.raw

Copy tx.raw to your cold environment.

Sign the transaction with both the payment and stake secret keys.

cardano-cli shelley transaction sign \
    --tx-body-file tx.raw \
    --signing-key-file payment.skey \
    --testnet-magic 1097911063 \
    --out-file tx.signed

Copy tx.signed to your hot environment.

Send the signed transaction.

cardano-cli shelley transaction submit \
    --tx-file tx.signed \
    --testnet-magic 1097911063

Check if the funds arrived.

cardano-cli shelley query utxo \
    --address ${destinationAddress} \
    --testnet-magic 1097911063

You should see output similar to this showing the funds you sent.

                           TxHash                                 TxIx        Lovelace
----------------------------------------------------------------------------------------
100322a39d02c2ead....                                              0        1000000

Last updated