Retiring Your Stake Pool

If you no longer want to operate your stake pool, then you can deregister the pool. Deregistering the pool retires the pool.

To retire your stake pool, your stake pool does NOT require valid KES keys. However, you must ensure that your nodes are fully synchronized with the blockchain.

To retire your stake pool:

First, generate the protocol-parameters.

cardano-cli query protocol-parameters \
    --mainnet \
    --out-file $NODE_HOME/params.json

Calculate the current epoch.

startTimeGenesis=$(cat $NODE_HOME/shelley-genesis.json | jq -r .systemStart)
startTimeSec=$(date --date=${startTimeGenesis} +%s)
currentTimeSec=$(date -u +%s)
epochLength=$(cat $NODE_HOME/shelley-genesis.json | jq -r .epochLength)
epoch=$(( (${currentTimeSec}-${startTimeSec}) / ${epochLength} ))
echo current epoch: ${epoch}

Find the earliest and latest retirement epoch that your pool can retire.

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

minRetirementEpoch=$(( ${epoch} + 1 ))
maxRetirementEpoch=$(( ${epoch} + ${poolRetireMaxEpoch} ))

echo earliest epoch for retirement is: ${minRetirementEpoch}
echo latest epoch for retirement is: ${maxRetirementEpoch}
  • the earliest epoch for retirement is 40 ( current epoch + 1).

  • the latest epoch for retirement is 57 ( poolRetireMaxEpoch + current epoch).

Let's presume that you want to retire as soon as possible, in epoch 40.

Create the deregistration certificate and save it as pool.dereg. Update the epoch to your desired retirement epoch, usually the earliest epoch or asap.

cardano-cli stake-pool deregistration-certificate \
--cold-verification-key-file $HOME/cold-keys/node.vkey \
--epoch <retirementEpoch> \
--out-file pool.dereg

Copy pool.dereg to your hot environment.

Find your balance and UTXOs.

cardano-cli query utxo \
    --address $(cat payment.addr) \
    --mainnet > 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
    type=$(awk '{ print $6 }' <<< "${utxo}")
    if [[ ${type} == 'TxOutDatumNone' ]]
    then
        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}"
    fi
done < balance.out
txcnt=$(cat balance.out | wc -l)
echo Total available ADA balance: ${total_balance}
echo Number of UTXOs: ${txcnt}

Find the tip of the blockchain to set the invalid-here after parameter properly.

currentSlot=$(cardano-cli query tip --mainnet | jq -r '.slot')
echo Current Slot: $currentSlot

Run the build-raw transaction command.

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

Calculate the minimum fee:

fee=$(cardano-cli transaction calculate-min-fee \
    --tx-body-file tx.tmp \
    --tx-in-count ${txcnt} \
    --tx-out-count 1 \
    --mainnet \
    --witness-count 2 \
    --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 transaction build-raw \
    ${tx_in} \
    --tx-out $(cat payment.addr)+${txOut} \
    --invalid-hereafter $(( ${currentSlot} + 10000)) \
    --fee ${fee} \
    --certificate-file pool.dereg \
    --out-file tx.raw

Copy tx.raw to your cold environment.

Sign the transaction.

cardano-cli transaction sign \
    --tx-body-file tx.raw \
    --signing-key-file payment.skey \
    --signing-key-file $HOME/cold-keys/node.skey \
    --mainnet \
    --out-file tx.signed

Copy tx.signed to your hot environment.

Send the transaction.

cardano-cli transaction submit \
    --tx-file tx.signed \
    --mainnet

Pool will retire at the end of your specified epoch. In this example, retirement occurs at the end of epoch 40.

If you have a change of heart, you can create and submit a new registration certificate before the end of epoch 40, which will then overrule the deregistration certificate.

After the retirement epoch, you can verify that the pool was successfully retired with the following query which should return an empty result.

cardano-cli query ledger-state --mainnet > ledger-state.json
jq -r '.esLState._delegationState._pstate._pParams."'"$(cat stakepoolid.txt)"'"  // empty' ledger-state.json

In two epochs, after retirement completes:

  1. Verify that your pool is retired using a block explorer such as cardanoscan.io

  2. Your pool deposit of 500 ADA is returned to your stake address (stake.addr) as a reward.

  3. Claim your stake pool rewards.

  4. As needed, send funds to another wallet.

  5. Optionally, de-register the stake key to re-claim your 2 ADA stake deposit.

Important:

  • Do NOT de-register your stake key before your pool deposit of 500ADA is paid back to your rewards address. Nonreturnable pool deposits are sent to the Cardano treasury.

  • If there are multiple pool owners, communicate your intention to retire the pool and ensure they do not remove pledge funds until the pool is retired.

  • As a courtesy to your delegators, provide advanced notice of your intention to retire so that they may re-delegate their stake.

References