Refund of deposits on deregistration (depending on protocol parameters and decay)

Before delegating to a staking pool, a stake address needs first to be registered, with a deposit, of currently 2 ADA, according to the protocol parameter keyDeposit.

  1. Does a reward account (corresponding to a registered stake key) store the amount originally deposited on chain ?
  2. Can/will the protocol parameter keyDeposit ever be updated ?
  3. Will some decay mechanism for the refund due to a deregistration be implemented ?
  4. If one of 2 or 3 holds, how to compute the amount of such a refund (which information is required for building a well-balanced transaction including a deregistration certificate). Currently, a hardcoded value of 2 ADA seems to work, but this approach may not be sustainable.
1 Like

Hi!

I think once the stake certificate registered the stake address is fine even the stake keyDeposit changed. The stake certificate can be de-registered and it will automatically gives back the stake keyDeposit.

this is the command how to de-register:
cardano-cli stake-address deregistration-certificate

I think 2 ADA does not need to be provided when building the transaction…
That case the 2 ADA should arrive to the stake address (just like in case of pool de-registration) where it can be withdraw from
https://docs.cardano.org/projects/cardano-node/en/latest/stake-pool-operations/withdraw-rewards.html
but I will verify this by creating a de-registration soon…

I just tried it and it turned out we do have to include 2 ADA to the TX output amount. See logs below. First execution did not include 2 ADA and caused an error. The second one did and went through successfully.

jsun@ubuntu:~/hobby/cardano/temp$ ../account-mng/deregister-stake.sh
For which network - mainnet or testnet? (default : testnet)
===> running deregister_stake ...
keyDeposit: 2000000
utxo (balance) for the account is :
TxHash: 36cb41d6164e0d11785910f5704994a89be4cc0f3c58ab8c3df5fc12269d1377#0
ADA: 7820683
Total ADA balance: 7820683
Number of UTXOs: 1
Current Slot: 25802049
fee: 179317
Change Output: 7641366
Command failed: transaction submit  Error: Error while submitting tx: ShelleyTxValidationError ShelleyBasedEraMary (ApplyTxError [LedgerFailure (UtxowFailure (UtxoFailure (ValueNotConservedUTxO (Value 9820683 (fromList [])) (Value 7820683 (fromList [])))))])
jsun@ubuntu:~/hobby/cardano/temp$ ../account-mng/deregister-stake.sh
For which network - mainnet or testnet? (default : testnet)
===> running deregister_stake ...
keyDeposit: 2000000
utxo (balance) for the account is :
TxHash: 36cb41d6164e0d11785910f5704994a89be4cc0f3c58ab8c3df5fc12269d1377#0
ADA: 7820683
Total ADA balance: 7820683
Number of UTXOs: 1
Current Slot: 25802075
fee: 179317
Change Output: 9641366
Transaction successfully submitted.
Initial build is done!
2 Likes

Thanks for figuring this out! Can you post the script or is it available somewhere?

My plan is to publish the scripts some day, but they are not in the best shape yet.

In any case, I attached the 2 relevant scripts, register-stake and deregister-stake for your reference.

set -e                  # exit on error
set -o pipefail         # exit on pipeline error
set -u                  # treat unset variable as error
#set -x

SCRIPT_FILE=$(readlink -f "$0")
SCRIPT_NAME=$(basename $SCRIPT_FILE)
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"

# we always excute under node-level directory
CARDANO_NODE_SOCKET_PATH=${CARDANO_NODE_SOCKET_PATH:-""}
if [[ -z $CARDANO_NODE_SOCKET_PATH ]]; then
    echo "please set env var $CARDANO_NODE_SOCKET_PATH"
    echo "you can either run a cardano node locally, or set up a ssh socket forward"
    echo
    echo "For example"
    echo
    echo "ssh -nNT -L /tmp/tmp-cardano-socket:/home/ubuntu/cardano/producer/db/socket ubuntu@cardano.netspectrum.com"
    echo "export CARDANO_NODE_SOCKET_PATH=/tmp/tmp-cardano-socket"
    echo
    exit 1
fi

function myerror() {
    echo -e "ERROR : $1"
    echo
    echo -e "QUITING ...."
    exit 1
}

function calc_tx_in() {
    address=$1

    # calc input    
    local raw_balance=$(cardano-cli query utxo --address $address $NETWORK_MAGIC |tail -n +3 | sort -k3 -nr)

    echo "utxo (balance) for the account is :"
    tx_in=""
    total_balance=0
    txcnt=0
    while read -r utxo; do
        if [[ -z $utxo ]]; then break; fi
        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}"
        txcnt=$((txcnt + 1))
    done <<< "$raw_balance"
    echo Total ADA balance: ${total_balance}
    echo Number of UTXOs: ${txcnt}
}

function deregister_stake() {
    echo "===> running deregister_stake ..."

    # gen stake cert
    cardano-cli stake-address deregistration-certificate \
        --stake-verification-key-file stake.vkey \
        --out-file stake-dereg.cert

    # calc deposite fee
    keyDeposit=$(cat $PARAMS_FILE | jq -r '.stakeAddressDeposit')
    echo keyDeposit: $keyDeposit

    # build tx.raw
    calc_tx_in ${PAYMENT_ADDR}
    if [[ $txcnt == 0 ]]; then
        myerror "Please fund the account first before registration"
    fi

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

    # build tmp for fee estimate
    cardano-cli transaction build-raw \
        ${tx_in} \
        --tx-out ${PAYMENT_ADDR}+0 \
        --invalid-hereafter $(( ${currentSlot} + 10000)) \
        --fee 0 \
        --out-file /tmp/tx.tmp \
        --certificate stake-dereg.cert

    # estimate fee
    fee=$(cardano-cli transaction calculate-min-fee \
        --tx-body-file /tmp/tx.tmp \
        --tx-in-count ${txcnt} \
        --tx-out-count 1 \
        $NETWORK_MAGIC \
        --witness-count 2 \
        --byron-witness-count 0 \
        --protocol-params-file $PARAMS_FILE | awk '{ print $1 }')
    echo fee: $fee

    # calc change amount
    txOut=$((total_balance+keyDeposit-fee))
    echo Change Output: ${txOut}

    # build tx raw
    cardano-cli transaction build-raw \
        ${tx_in} \
        --tx-out ${PAYMENT_ADDR}+${txOut} \
        --invalid-hereafter $(( ${currentSlot} + 10000)) \
        --fee ${fee} \
        --certificate-file stake-dereg.cert \
        --out-file /tmp/tx.raw

    # sign
    cardano-cli transaction sign \
        --tx-body-file /tmp/tx.raw \
        --signing-key-file $PAYMENT_SKEY \
        --signing-key-file stake.skey \
        $NETWORK_MAGIC \
        --out-file /tmp/tx.signed

    # submit
    cardano-cli transaction submit \
        --tx-file /tmp/tx.signed \
        $NETWORK_MAGIC

    # clean up
    rm -f /tmp/tx.*
}

# =============   main  ================

if [[ $# == 2 && $1 == "--payer" ]]; then
    PAYMENT_ADDR=$(cat $2/payment.addr)
    PAYMENT_SKEY="$2/payment.skey"
elif [[ $# == 0 ]]; then
    PAYMENT_ADDR=$(cat payment.addr)
    PAYMENT_SKEY="payment.skey"
else
    usage
fi

read -p "For which network - mainnet or testnet? (default : testnet) "  NETWORK
if [[ -z $NETWORK ]]; then
    NETWORK="testnet"
elif [[ $NETWORK != "mainnet" && $NETWORK != "testnet" ]]; then
    myerror "Wrong network inputed : $NETWORK"
fi

if [[ $NETWORK == "mainnet" ]]; then
    NETWORK_MAGIC="--mainnet"
elif [[ $NETWORK == "testnet" ]]; then
    NETWORK_MAGIC="--testnet-magic 1097911063"
else
    echo "unknown network $NETWORK. quitting"
    exit 1
fi

PARAMS_FILE=$SCRIPT_DIR/${NETWORK}-params.json
if [[ ! -f $PARAMS_FILE ]]; then
    echo "generating params file $PARAMS_FILE ..."
    cardano-cli query protocol-parameters $NETWORK_MAGIC --out-file $PARAMS_FILE
fi

deregister_stake