diff --git a/docs/Scripts/cntools-changelog.md b/docs/Scripts/cntools-changelog.md
index c09365cb8..014949197 100644
--- a/docs/Scripts/cntools-changelog.md
+++ b/docs/Scripts/cntools-changelog.md
@@ -6,6 +6,15 @@ All notable changes to this tool will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [13.0.0] - 2024-01-19
+#### Added
+- New light mode using Koios API instead of local node for blockchain queries. Mode can be selected at runtime using -l (light), -n (node, default) or -o (offline).
+#### Changed
+- Improved submission handling
+- Removed complicated file descriptor re-direction for logging. This simplified the code and improves screen printing speed as special hacks around FDs could be removed.
+#### Fixed
+- Update handling and reload of script.
+
## [12.1.0] - 2024-01-19
#### Changed
- ADA price discovery through CoinGecko in set currency incl 24hr change. Shown in main UI, wallet list & show as well as pool show. Disabled by default.
diff --git a/scripts/cnode-helper-scripts/cntools.library b/scripts/cnode-helper-scripts/cntools.library
index f369c12e9..a21a82285 100644
--- a/scripts/cnode-helper-scripts/cntools.library
+++ b/scripts/cnode-helper-scripts/cntools.library
@@ -11,9 +11,9 @@
# The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
# and this adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
# Major: Any considerable change in the code base, big feature, workflow or breaking change from previous version
-CNTOOLS_MAJOR_VERSION=12
+CNTOOLS_MAJOR_VERSION=13
# Minor: Changes and features of minor character that can be applied without breaking existing functionality or workflow
-CNTOOLS_MINOR_VERSION=1
+CNTOOLS_MINOR_VERSION=0
# Patch: Backwards compatible bug fixes. No additional functionality or major changes
CNTOOLS_PATCH_VERSION=0
@@ -28,6 +28,18 @@ if ! mkdir -p "${TMP_DIR}" 2>/dev/null; then myExit 1 "${FG_RED}ERROR${NC}: Fail
if ! mkdir -p "${WALLET_FOLDER}" 2>/dev/null; then myExit 1 "${FG_RED}ERROR${NC}: Failed to create wallet directory: ${WALLET_FOLDER}"; fi
if ! mkdir -p "${POOL_FOLDER}" 2>/dev/null; then myExit 1 "${FG_RED}ERROR${NC}: Failed to create pool directory: ${POOL_FOLDER}"; fi
if ! mkdir -p "${ASSET_FOLDER}" 2>/dev/null; then myExit 1 "${FG_RED}ERROR${NC}: Failed to create asset directory: ${POOL_ASSET}"; fi
+[[ -z ${CNTOOLS_MODE} ]] && CNTOOLS_MODE=LOCAL || CNTOOLS_MODE=${CNTOOLS_MODE^^}
+if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
+ CNTOOLS_MODE_COLOR="${FG_BLUE}"
+elif [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ CNTOOLS_MODE_COLOR="${FG_GREEN}"
+else
+ CNTOOLS_MODE_COLOR="${FG_GRAY}"
+fi
+printf -v launch_modes_info "${FG_BLUE}INFO${NC}: Available launch modes, re-run CNTools in
+ ${CNTOOLS_MODE_COLOR}LOCAL${NC} mode (-n): Default mode with a local node connection.
+ ${CNTOOLS_MODE_COLOR}LIGHT${NC} mode (-l): Utilizing Koios query layer with full functionallity for supported networks.
+ ${CNTOOLS_MODE_COLOR}OFFLINE${NC} mode (-o): A limited set of functionallity without external communication useful for air-gapped mode."
[[ -z ${TIMEOUT_NO_OF_SLOTS} ]] && TIMEOUT_NO_OF_SLOTS=600
[[ -z ${TX_TTL} ]] && TX_TTL=3600
[[ -z ${WALLET_SELECTION_FILTER_LIMIT} ]] && WALLET_SELECTION_FILTER_LIMIT=10
@@ -73,22 +85,18 @@ logln() {
# : newline > Add a newline at the end for tty output (default true)
# : message > The message to print/log
println() {
- sleep 0.05 # hack, sleep 50ms before each print to preserve order of execution
local log_level=$1
shift
local newline="\n"
- if [[ $1 =~ true|false ]]; then
- [[ $1 = false ]] && newline=""
- shift
- fi
+ if [[ $1 = false && $# -gt 2 ]]; then unset newline; shift; elif [[ $1 = true && $# -gt 2 ]]; then shift; fi
case $log_level in
- OFF) printf "%b${newline}" "$@" >&6 ;;
+ OFF) printf "%b${newline}" "$@" ;;
LOG) logln "DEBUG" "$@" ;;
- DEBUG) printf "%b${newline}" "$@" >&6; logln "DEBUG" "$@" ;;
- INFO) printf "%b${newline}" "$@" ;;
+ DEBUG) printf "%b${newline}" "$@"; logln "DEBUG" "$@" ;;
+ INFO) printf "%b${newline}" "$@"; logln "INFO" "$@" ;;
ACTION) logln "ACTION" "$@" ;;
- ERROR) printf "%b${newline}" "$@" >&2 ;;
- *) printf "%b${newline}" "${log_level}"; [[ $# -ge 1 ]] && printf "%b${newline}" "$@" ;;
+ ERROR) printf "%b${newline}" "$@"; logln "ERROR" "$@" ;;
+ *) println INFO "${log_level}" "$@" ;;
esac
}
@@ -99,7 +107,6 @@ println() {
# : log > [true|false] log question (default: true)
# : question > what to ask user to input
getAnswerAnyCust() {
- sleep 0.1 # hack, sleep 100ms before asking question to preserve order
var_name=$1
shift
local log_question=true
@@ -107,7 +114,7 @@ getAnswerAnyCust() {
[[ $1 = false ]] && log_question=false
shift
fi
- getAnswerAny "${var_name}" "$*" >&6
+ getAnswerAny "${var_name}" "$*"
[[ ${log_question} = true ]] && println LOG "$*: ${!var_name}"
}
@@ -122,15 +129,6 @@ archiveLog() {
find "${log_archive}" -maxdepth 1 -type f -name "${log_file}*" -printf '%Ts\t%p\n' | sort -n | head -n -10 | cut -f 2- | xargs rm -rf
}
-# Command : waitForInput [optional: message]
-# Description : wait for user keypress to continue
-# Parameters : message > [optional]: override default 'press any key to proceed ..' message
-waitForInput() {
- exec >&6 # normal stdout
- waitToProceed "$*"
- exec >&8 # custom stdout
-}
-
# Command : protectionPreRequisites
# Description : Check if needed protection prerequisites is available, else print error
protectionPreRequisites() {
@@ -170,6 +168,19 @@ safeDel() {
return 0
}
+updateProtocolParams() {
+ _epoch_=$(getEpoch)
+ [[ -n ${current_epoch} && ${current_epoch} -eq ${_epoch_} ]] && return
+ current_epoch=${_epoch_}
+ getProtocolParams
+ case $? in
+ 1) myExit 1 "${FG_YELLOW}WARN${NC}: node socket path wrongly configured or node not running, please verify that socket set in env file match what is used to run the node\n\n${launch_modes_info}" ;;
+ 2) myExit 1 "${FG_YELLOW}WARN${NC}: failed to query protocol parameters, ensure your node is running with correct genesis (the node needs to be in sync to 1 epoch after the hardfork)\n\nError message: ${PROT_PARAMS}\n\n${launch_modes_info}" ;;
+ 3) myExit 1 "${FG_YELLOW}WARN${NC}: Unable to query Koios for current epoch parameters\n\n${launch_modes_info}" ;;
+ esac
+ echo "${PROT_PARAMS}" > "${TMP_DIR}"/protparams.json
+}
+
# Command : dialogSetup
# Description : set config parameters for dialog formatting
dialogSetup() {
@@ -240,16 +251,13 @@ fileDialog() {
getAnswerAnyCust file "$1" && return
else
println DEBUG false "${1}: "
- waitForInput "Press any key to open the file explorer [cancel to skip!]"
+ waitToProceed "Press any key to open the file explorer [cancel to skip!]"
fi
- exec >&6 2>&7 # normal stdout/stderr
- sleep 0.1
dialogSetup
[[ -n $2 ]] && start_path="$2" || start_path="${TMP_DIR}/"
dialog --clear --keep-tite --title "$1" --fselect "${start_path}" $(($(tput lines)-14)) $(($(tput cols)-10)) 2>"${TMP_DIR}/dialog.out"
file=$([[ -f "${TMP_DIR}/dialog.out" ]] && cat "${TMP_DIR}/dialog.out" || echo "")
tput cup $(( ${ROW#*[} -1 )) $(( COL -1 ))
- exec >&8 2>&9 # custom stdout/stderr
println DEBUG "${FG_LGRAY}${file}${NC}"
}
# Command : dirDialog [title] [optional: start dir]
@@ -262,16 +270,13 @@ dirDialog() {
getAnswerAnyCust dir "$1" && return
else
println DEBUG false "${1}: "
- waitForInput "Press any key to open the file explorer [cancel to skip!]"
+ waitToProceed "Press any key to open the file explorer [cancel to skip!]"
fi
- exec >&6 2>&7 # normal stdout/stderr
- sleep 0.1
dialogSetup
[[ -n $2 ]] && start_path="$2" || start_path="${TMP_DIR}/"
dialog --clear --keep-tite --title "$1" --dselect "${start_path}" $(($(tput lines)-14)) $(($(tput cols)-10)) 2>"${TMP_DIR}/dialog.out"
dir=$([[ -f "${TMP_DIR}/dialog.out" ]] && cat "${TMP_DIR}/dialog.out" || echo "")
tput cup $(( ${ROW#*[} -1 )) $(( COL -1 ))
- exec >&8 2>&9 # custom stdout/stderr
println DEBUG "${FG_LGRAY}${dir}${NC}"
}
@@ -298,14 +303,20 @@ key_input() { key2=""
else echo ${key1}; fi; }
opt_shortcut() { [[ "$1" =~ ^\[([[:alnum:]]+)\].* ]] && echo ${BASH_REMATCH[1]}; }
opt_firstchar() { printf "${1:0:1}" | tr '[:upper:]' '[:lower:]'; }
+clrbuf() { read -r -t 0.1 -s -e; stty echo echok; }
selectOption() {
- sleep 0.1 # sleep for a short time to get tty in sync
# initially print empty new lines (scroll down if at bottom of screen)
printf "\n" && for opt; do printf "\n"; done
- # determine current screen position for overwriting the options
- local startrow=$(( $(get_cursor_row) - $# - 1 ))
+ # determine current screen position for overwriting the options or return -1 on failure
+ clrbuf
+ local startrow=-1
+ for i in {1..10}; do
+ local cursor_row=$(get_cursor_row)
+ isNumber ${cursor_row} && startrow=$(( cursor_row - $# - 1 )) && break
+ done
+ [[ ${startrow} -eq -1 ]] && return 255
cursor_blink_off
@@ -369,14 +380,16 @@ selectOption() {
# Description : Helper function to selectOption
# Parameters : optX > a list of available options to choose from
select_opt() {
- exec >&6 # normal stdout
local opts=()
for item in "$@"; do
[[ -n ${item} ]] && opts+=("${item}")
done
selectOption "${opts[@]}"
local answer=$?
- exec >&8 # custom stdout
+ if [[ ${answer} -eq 255 ]]; then
+ println ERROR "\n${FG_RED}ERROR${NC}: Failed to print menu, default selection used!\n"
+ return 0
+ fi
selected_value="${opts[${answer}]}"
println DEBUG "Selected value: ${selected_value}"
return $answer
@@ -389,7 +402,7 @@ select_opt() {
getDirs() {
if [[ ! -d "$1" ]]; then
println ERROR "${FG_RED}ERROR${NC}: Missing folder: $1"
- waitForInput && return 1
+ waitToProceed && return 1
fi
dirs=()
while IFS= read -r -d '' dir; do
@@ -404,14 +417,17 @@ getDirs() {
# : dirX > array of dirs to include in selection, '[Esc] Cancel' option added to all selections
# Return : populates ${dir_name} variable
selectDir() {
- exec >&6 # normal stdout
local type=$1 && shift
dirs=( "$@" )
dirs+=("[Esc] Cancel")
selectOption "${dirs[@]}"
- dir_name=${dirs[$?]}
- [[ "${dir_name}" = "[Esc] Cancel" ]] && return 1
- exec >&8 # custom stdout
+ local answer=$?
+ if [[ ${answer} -eq 255 ]]; then
+ println ERROR "\n${FG_RED}ERROR${NC}: Failed to print menu, please try again or report issue!"
+ return 1
+ fi
+ dir_name=${dirs[${answer}]}
+ [[ "${dir_name}" = "[Esc] Cancel" ]] && return 2
println DEBUG "Selected ${type}: ${dir_name}"
}
@@ -421,14 +437,40 @@ selectDir() {
# : arg array > array of files required to exist in wallet folder for it to be selectable **OR** the name of wallet to exclude from selection
# Return : populates ${wallet_name} variable with wallet selection
selectWallet() {
- wallet_dirs=()
+
mode=$1 && shift
+
+ if [[ ${mode} = "cache" && ${#wallet_dirs_filtered[@]} -gt 0 ]]; then
+ selectDir "wallet" "${wallet_dirs_filtered[@]}" || return $? # ${dir_name} populated by selectDir function
+ wallet_name="$(echo ${dir_name} | cut -d' ' -f1)"
+ return 0
+ fi
+
+ wallet_dirs=()
+
if ! getDirs "${WALLET_FOLDER}"; then return 1; fi # dirs() array populated with all wallet folders
- if [[ ${CNTOOLS_MODE} = "CONNECTED" && ${mode} != "none" ]]; then
+ if [[ ${CNTOOLS_MODE} != "OFFLINE" && ${mode} != "none" ]]; then
tput sc
wallet_count=${#dirs[@]}
- [[ ${wallet_count} -le ${WALLET_SELECTION_FILTER_LIMIT} ]] && println OFF "Balance checking wallets..."
+ if [[ ${wallet_count} -le ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
+ if [[ -n ${KOIOS_API} ]]; then
+ println OFF "${FG_YELLOW}> Querying Koios API for wallet balance${NC}"
+ else
+ println OFF "${FG_YELLOW}> Querying node for wallet balance${NC}"
+ fi
+ else
+ println OFF "${FG_YELLOW}> Max wallet count exceeded for balance/filtering (${wallet_count}/${WALLET_SELECTION_FILTER_LIMIT}).\nUpdate 'WALLET_SELECTION_FILTER_LIMIT' setting to increase this limit${NC}"
+ fi
fi
+
+ unset reward_status
+ addr_list=()
+ reward_addr_list=()
+ declare -gA asset_cnt=()
+ declare -gA balances=()
+ declare -gA reward_pool=()
+ declare -gA rewards_available=()
+
for dir in "${dirs[@]}"; do
for arg in "$@"; do # check if wallet is missing a required file or name matches execution, if so hide it
[[ ${arg} == *"."* && ! -f "${WALLET_FOLDER}/${dir}/${arg}" ]] && continue 2
@@ -441,35 +483,101 @@ selectWallet() {
else
wallet_dirs+=("${dir} (${FG_YELLOW}unprotected${NC})")
fi
- elif [[ ${CNTOOLS_MODE} = "CONNECTED" && ${mode} != "none" && ${wallet_count} -le ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
- if [[ ${mode} = "non-reg" ]]; then
- if isWalletRegistered ${dir}; then continue; fi
- elif [[ ${mode} = "reg" ]]; then
- if ! isWalletRegistered ${dir}; then continue; fi
+ elif [[ ${CNTOOLS_MODE} != "OFFLINE" && ${mode} != "none" && ${wallet_count} -le ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
+ if [[ ${mode} = "reg" || ${mode} = "non-reg" ]]; then
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
+ if [[ ${mode} = "reg" ]]; then
+ ! isWalletRegistered ${dir} && continue
+ else
+ isWalletRegistered ${dir} && continue
+ fi
+ else
+ getRewardAddress ${dir}
+ [[ -n ${reward_addr} ]] && reward_addr_list+=(${reward_addr})
+ fi
fi
if [[ ${mode} = "balance" || ${mode} = "non-reg" || ${mode} = "reg" ]]; then
getBaseAddress ${dir}
getPayAddress ${dir}
[[ -z ${base_addr} || -z ${pay_addr} ]] && wallet_dirs+=("${dir}") && continue # ignore and add wallet without extra details
- getBalance ${base_addr}
- base_lovelace=${assets[lovelace]}
- [[ ${#assets[@]} -gt 1 ]] && base_assets_out=" + ${FG_LBLUE}$((${#assets[@]}-1))${NC} additional assets" || base_assets_out=""
- getBalance ${pay_addr}
- pay_lovelace=${assets[lovelace]}
- [[ ${#assets[@]} -gt 1 ]] && pay_assets_out=" + ${FG_LBLUE}$((${#assets[@]}-1))${NC} additional assets" || pay_assets_out=""
- if [[ ${base_lovelace} -gt 0 && ${pay_lovelace} -gt 0 ]]; then
- wallet_dirs+=("${dir} (Funds: ${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA${base_assets_out} | Enterprise Funds: ${FG_LBLUE}$(formatLovelace ${pay_lovelace})${NC} ADA${pay_assets_out})")
- elif [[ ${pay_lovelace} -gt 0 ]]; then
- wallet_dirs+=("${dir} (Enterprise Funds: ${FG_LBLUE}$(formatLovelace ${pay_lovelace})${NC} ADA${pay_assets_out})")
- else
- wallet_dirs+=("${dir} (Funds: ${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA${base_assets_out})")
+ addr_list+=(${base_addr} ${pay_addr})
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
+ getBalance ${base_addr}
+ balances["${base_addr}"]=${assets[lovelace]}
+ [[ ${#assets[@]} -gt 1 ]] && asset_cnt["${base_addr}"]="$((${#assets[@]}-1))"
+ getBalance ${pay_addr}
+ balances["${pay_addr}"]=${assets[lovelace]}
+ [[ ${#assets[@]} -gt 1 ]] && asset_cnt["${pay_addr}"]="$((${#assets[@]}-1))"
fi
+ wallet_dirs+=("${dir}_balance_")
elif [[ ${mode} = "delegate" ]]; then
getBaseAddress ${dir}
[[ -z ${base_addr} ]] && wallet_dirs+=("${dir}") && continue # ignore and add wallet without extra details
- getBalance ${base_addr}
- if getRewardAddress ${dir}; then
- delegation_pool_id=$(${CCLI} ${NETWORK_ERA} query stake-address-info ${NETWORK_IDENTIFIER} --address "${reward_addr}" | jq -r '.[0].delegation // empty')
+ addr_list+=(${base_addr})
+ getRewardAddress ${dir}
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
+ getBalance ${base_addr}
+ balances["${base_addr}"]=${assets[lovelace]}
+ if [[ -n ${reward_addr} ]]; then
+ delegation_pool_id=$(${CCLI} ${NETWORK_ERA} query stake-address-info ${NETWORK_IDENTIFIER} --address "${reward_addr}" | jq -r '.[0].delegation // empty')
+ [[ -n ${delegation_pool_id} ]] && reward_pool[${reward_addr}]=${delegation_pool_id}
+ fi
+ else
+ [[ -n ${reward_addr} ]] && reward_addr_list+=(${reward_addr})
+ fi
+ wallet_dirs+=("${dir}_balance_")
+ elif [[ ${mode} = "reward" ]]; then
+ if [[ -n ${KOIOS_API} ]]; then
+ getRewardAddress ${dir}
+ [[ -n ${reward_addr} ]] && reward_addr_list+=(${reward_addr})
+ else
+ getWalletRewards ${dir}
+ [[ ${reward_lovelace} -eq 0 ]] && continue
+ rewards_available[${reward_addr}]=${reward_lovelace}
+ fi
+ wallet_dirs+=("${dir}_balance_")
+ fi
+ else
+ wallet_dirs+=("${dir}")
+ fi
+ done
+
+ if [[ -n ${KOIOS_API} ]]; then
+ if [[ ${#addr_list[@]} -gt 0 ]]; then
+ getBalanceKoios false
+ for key in ${!assets[@]}; do
+ if [[ ${key} = *lovelace ]]; then
+ _address=${key%,*}
+ balances[${_address}]=${assets[${key}]}
+ fi
+ done
+ fi
+ [[ ${#reward_addr_list[@]} -gt 0 ]] && getRewardInfoKoios
+ fi
+
+ wallet_dirs_filtered=()
+
+ for dir in "${wallet_dirs[@]}"; do
+ if [[ ${dir} = *_balance_ ]]; then
+ wallet_dir=${dir%%_balance_}
+ unset base_addr
+ getBaseAddress ${wallet_dir}
+ base_lovelace=${balances[${base_addr}]:-0}
+ if [[ ${mode} = "reg" || ${mode} = "non-reg" ]]; then
+ getRewardAddress ${wallet_dir}
+ if [[ -n ${reward_addr} ]]; then
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ if [[ ${mode} = "reg" ]]; then
+ if [[ ! -v reward_status[${reward_addr}] || ${reward_status[${reward_addr}]} != "registered" ]]; then continue; fi
+ else
+ [[ -v reward_status[${reward_addr}] && ${reward_status[${reward_addr}]} = "registered" ]] && continue
+ fi
+ fi
+ fi
+ elif [[ ${mode} = "delegate" ]]; then
+ getRewardAddress ${wallet_dir}
+ if [[ -n ${reward_addr} ]]; then
+ delegation_pool_id=${reward_pool[${reward_addr}]}
unset poolName
if [[ -n ${delegation_pool_id} ]]; then
while IFS= read -r -d '' pool; do
@@ -480,38 +588,58 @@ selectWallet() {
done < <(find "${POOL_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z)
fi
if [[ -n ${poolName} ]]; then
- wallet_dirs+=("${dir} (${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA - ${FG_RED}delegated${NC} to ${FG_GREEN}${poolName}${NC})")
+ wallet_dirs_filtered+=("${wallet_dir} (${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA - ${FG_RED}delegated${NC} to ${FG_GREEN}${poolName}${NC})")
elif [[ -n ${delegation_pool_id} ]]; then
- wallet_dirs+=("${dir} (${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA - ${FG_RED}delegated${NC} to external address)")
+ wallet_dirs_filtered+=("${wallet_dir} (${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA - ${FG_RED}delegated${NC} to ${FG_LGRAY}${delegation_pool_id:0:6}...${delegation_pool_id: -6}${NC})")
else
- wallet_dirs+=("${dir} (${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA)")
+ wallet_dirs_filtered+=("${wallet_dir} (${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA)")
fi
else
- wallet_dirs+=("${dir} (${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA)")
+ wallet_dirs_filtered+=("${wallet_dir} (${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA)")
fi
+ continue
elif [[ ${mode} = "reward" ]]; then
- getRewards ${dir}
- [[ ${reward_lovelace} -le 0 ]] && continue
- wallet_dirs+=("${dir} (Rewards: ${FG_LBLUE}$(formatLovelace ${reward_lovelace})${NC} ADA)")
+ getRewardAddress ${wallet_dir}
+ if [[ -n ${reward_addr} && -v rewards_available[${reward_addr}] && ${rewards_available[${reward_addr}]} -gt 0 ]]; then
+ wallet_dirs_filtered+=("${wallet_dir} (Rewards: ${FG_LBLUE}$(formatLovelace ${rewards_available[${reward_addr}]})${NC} ADA)")
+ fi
+ continue
+ fi
+ getPayAddress ${wallet_dir}
+ pay_lovelace=${balances[${pay_addr}]:-0}
+ [[ -v asset_cnt[${base_addr}] ]] && base_asset_str=" + ${FG_LBLUE}${asset_cnt[${base_addr}]}${NC} additional assets" || unset base_asset_str
+ [[ -v asset_cnt[${pay_addr}] ]] && pay_asset_str=" + ${FG_LBLUE}${asset_cnt[${pay_addr}]}${NC} additional assets" || unset pay_asset_str
+ if [[ ${base_lovelace} -gt 0 && ${pay_lovelace} -gt 0 ]]; then
+ wallet_dirs_filtered+=("${wallet_dir} (Funds: ${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA${base_asset_str} | Enterprise Funds: ${FG_LBLUE}$(formatLovelace ${pay_lovelace})${NC} ADA${pay_asset_str})")
+ elif [[ ${pay_lovelace} -gt 0 ]]; then
+ wallet_dirs_filtered+=("${wallet_dir} (Enterprise Funds: ${FG_LBLUE}$(formatLovelace ${pay_lovelace})${NC} ADA${pay_asset_str})")
+ else
+ wallet_dirs_filtered+=("${wallet_dir} (Funds: ${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA${base_asset_str})")
fi
else
- wallet_dirs+=("${dir}")
+ wallet_dirs_filtered+=("${dir}")
fi
done
- if [[ ${CNTOOLS_MODE} = "CONNECTED" && ${mode} != "none" ]]; then tput rc && tput ed; fi
- if [[ ${#wallet_dirs[@]} -eq 0 ]]; then
+
+ if [[ ${CNTOOLS_MODE} != "OFFLINE" && ${mode} != "none" && ${wallet_count} -le ${WALLET_SELECTION_FILTER_LIMIT} ]]; then tput rc && tput ed; fi
+ if [[ ${#wallet_dirs_filtered[@]} -eq 0 ]]; then
if [[ ${mode} = "balance" ]]; then
- println ERROR "${FG_YELLOW}WARN${NC}: No wallets with funds available for selection! Required files:\n$(printf '%b\n' "$@")"
+ println ERROR "\n${FG_YELLOW}WARN${NC}: No wallets with funds available for selection! Required files:\n$(printf '%b\n' "$@")"
elif [[ ${mode} = "delegate" ]]; then
- println ERROR "${FG_YELLOW}WARN${NC}: No wallets available that can be delegated or used as pool pledge/owner/reward wallet! Required files:\n$(printf '%b\n' "$@")"
+ println ERROR "\n${FG_YELLOW}WARN${NC}: No wallets available that can be delegated or used as pool pledge/owner/reward wallet! Required files:\n$(printf '%b\n' "$@")"
elif [[ ${mode} = "reward" ]]; then
- println ERROR "${FG_YELLOW}WARN${NC}: No wallets available that have rewards to withdraw!"
+ println ERROR "\n${FG_YELLOW}WARN${NC}: No wallets available that have rewards to withdraw or signing keys to do so!"
+ elif [[ ${mode} = "reg" ]]; then
+ println ERROR "\n${FG_YELLOW}WARN${NC}: No wallets available that are registered on chain!"
+ elif [[ ${mode} = "non-reg" ]]; then
+ println ERROR "\n${FG_YELLOW}WARN${NC}: No wallets available that are unregistered!"
else
- println ERROR "${FG_YELLOW}WARN${NC}: No wallets available for selection! Required files:\n$(printf '%b\n' "$@")"
+ println ERROR "\n${FG_YELLOW}WARN${NC}: No wallets available for selection! Required files:\n$(printf '%b\n' "$@")"
fi
return 1
fi
- if ! selectDir "wallet" "${wallet_dirs[@]}"; then return 2; fi # ${dir_name} populated by selectDir function
+
+ selectDir "wallet" "${wallet_dirs_filtered[@]}" || return $? # ${dir_name} populated by selectDir function
wallet_name="$(echo ${dir_name} | cut -d' ' -f1)"
}
@@ -556,7 +684,7 @@ selectPool() {
return 1
fi
[[ ${enc_req_files} -gt 0 ]] && println DEBUG "${FG_YELLOW}encrypted pools found but NOT listed, please decrypt to show${NC}"
- if ! selectDir "pool" "${pool_dirs[@]}"; then return 2; fi # ${dir_name} populated by selectDir function
+ selectDir "pool" "${pool_dirs[@]}" || return $? # ${dir_name} populated by selectDir function
pool_name="$(echo ${dir_name} | cut -d' ' -f1)"
}
@@ -573,7 +701,7 @@ isPoolRegistered() {
unset error_msg pool_info pool_info_tsv pool_info_arr
unset p_active_epoch_no p_vrf_key_hash p_margin p_fixed_cost p_pledge p_reward_addr p_owners p_relays p_meta_url p_meta_hash p_meta_json p_pool_status
unset p_retiring_epoch p_op_cert p_op_cert_counter p_active_stake p_epoch_block_cnt p_live_stake p_live_delegators p_live_saturation
- if [[ ${CNTOOLS_MODE} = "OFFLINE" || -z ${KOIOS_API} ]]; then
+ if [[ ${CNTOOLS_MODE} != "LIGHT" ]]; then
[[ -f "${POOL_FOLDER}/${1}/${POOL_REGCERT_FILENAME}" ]] && return 2 || return 1
else
getPoolID "$1"
@@ -642,7 +770,7 @@ isPoolRegistered() {
# 2: offline/disabled/no result
getAssetInfo() {
unset
- if [[ ${CNTOOLS_MODE} = "OFFLINE" || -z ${KOIOS_API} || $# -ge 1 ]]; then
+ if [[ ${CNTOOLS_MODE} != "LIGHT" || $# -lt 1 ]]; then
return 2
else
println ACTION "curl -sSL -f -d _asset_policy=$1 -d _asset_name=$2 ${KOIOS_API}/asset_info"
@@ -707,7 +835,7 @@ selectPolicy() {
return 1
fi
[[ ${enc_req_files} -gt 0 ]] && println DEBUG "${FG_YELLOW}encrypted policies found but NOT listed, please decrypt to show${NC}"
- if ! selectDir "policy" "${policy_dirs[@]}"; then return 2; fi # ${dir_name} populated by selectDir function
+ selectDir "policy" "${policy_dirs[@]}" || return $? # ${dir_name} populated by selectDir function
policy_name="$(echo ${dir_name} | cut -d' ' -f1)"
}
@@ -729,7 +857,7 @@ selectAsset() {
println ERROR "${FG_YELLOW}WARN${NC}: No assets found on disk!"
return 1
fi
- if ! selectDir "asset" "${asset_list[@]}"; then return 2; fi # ${dir_name} populated by selected value
+ selectDir "asset" "${asset_list[@]}" || return $? # ${dir_name} populated by selected value
policy_dir="${dir_name%%/*}"
asset_name="${dir_name##*/}"
asset_file="${ASSET_FOLDER}/${policy_dir}/${asset_name}.asset"
@@ -740,11 +868,8 @@ selectAsset() {
# Parameters : confirm > [optional] force user to provide password twice for confirmation
# Return : populates ${password} variable, make sure to unset variable when done
getPasswordCust() {
- exec >&6 2>&7 # normal stdout/stderr
- sleep 0.1
getPassword 8 $1
return_code=$?
- exec >&8 2>&9 # custom stdout/stderr
return ${return_code}
}
@@ -753,15 +878,11 @@ getPasswordCust() {
# Parameters : file > Path for file to encrypt, will get a new .gpg file extention added to filename
# : password > Password to encrypt file with
encryptFile() {
- exec >&6 2>&7 # normal stdout/stderr
- sleep 0.1
echo "${2}" | gpg --symmetric --yes --batch --cipher-algo AES256 --passphrase-fd 0 --output "${1}.gpg" "${1}" &>/dev/null && \
safeDel "${1}" >/dev/null || {
- exec >&8 2>&9 # custom stdout/stderr
println ERROR "${FG_RED}ERROR${NC}: failed to encrypt ${1}"
return 1
}
- exec >&8 2>&9 # custom stdout/stderr
println DEBUG "${1} successfully encrypted"
}
@@ -771,15 +892,11 @@ encryptFile() {
# Parameters : file > Path for file to decrypt, file extension .gpg required
# : password > Password to decrypt file with
decryptFile() {
- exec >&6 2>&7 # normal stdout/stderr
- sleep 0.1
echo "${2}" | gpg --decrypt --batch --yes --passphrase-fd 0 --output "${1%.*}" "${1}" &>/dev/null && \
rm -f "${1}" || {
- exec >&8 2>&9 # custom stdout/stderr
println ERROR "${FG_RED}ERROR${NC}: failed to decrypt ${1}"
return 1
}
- exec >&8 2>&9 # custom stdout/stderr
println DEBUG "${1} successfully decrypted"
}
@@ -835,15 +952,32 @@ waitNewBlockCreated() {
# Description : Verify that the transaction was successfully registered by checking address balance against $newBalance
# Parameters : address > the address to compare with
verifyTx() {
- if ! waitNewBlockCreated; then return 1; fi
- getBalance ${1}
- while [[ ${assets[lovelace]} -ne ${newBalance} ]]; do
- println DEBUG "${FG_YELLOW}WARN${NC}: Balance mismatch, transaction not included in latest block... waiting for next block!"
- println LOG "$(formatLovelace ${assets[lovelace]}) != $(formatLovelace ${newBalance})"
- if ! waitNewBlockCreated "silent"; then return 1; fi
- getBalance ${1}
- done
- return 0
+ if [[ -n ${KOIOS_API} && -n ${tx_id} ]]; then
+ println DEBUG "Waiting for transaction to be seen on chain"
+ println DEBUG "Id: ${tx_id}"
+ println DEBUG "${FG_BLUE}INFO${NC}: press any key to cancel and return (won't stop transaction)"
+ while :; do
+ read -r -n 1 -s -t 5 abort
+ if [[ $? -eq 0 ]]; then
+ println "\n${FG_YELLOW}WARN${NC}: aborted!! transaction still in queue!"
+ return 1
+ fi
+ println ACTION "curl -sSL -f -X POST -H \"Content-Type: application/json\" -H \"accept: text/csv\" -d '{\"_tx_hashes\":[\"${tx_id}\"]' ${KOIOS_API}/tx_status?select=num_confirmations"
+ ! num_confirmations=$(curl -sSL -f -X POST -H "Content-Type: application/json" -H "accept: text/csv" -d '{"_tx_hashes":["'${tx_id}'"]}' "${KOIOS_API}/tx_status?select=num_confirmations" 2>&1) && println "ERROR" "\n${FG_RED}KOIOS_API ERROR${NC}: ${num_confirmations}\n" && return 1 # print error and return
+ num_confirmations=$(tail -n +2 <<< ${num_confirmations})
+ [[ -n "${num_confirmations}" ]] && { println DEBUG "\nTx put on chain !!"; break; } || printf .
+ done
+ else
+ if ! waitNewBlockCreated; then return 1; fi
+ getAddressBalance ${1} true
+ while [[ ${lovelace} -ne ${newBalance} ]]; do
+ println DEBUG "${FG_YELLOW}WARN${NC}: Balance mismatch, transaction not included in latest block... waiting for next block!"
+ println LOG "$(formatLovelace ${lovelace}) != $(formatLovelace ${newBalance})"
+ if ! waitNewBlockCreated "silent"; then return 1; fi
+ getAddressBalance ${1} true
+ done
+ return 0
+ fi
}
# Command : getPayAddress [wallet name]
@@ -857,9 +991,11 @@ getPayAddress() {
pay_addr=""
if [[ -f "${payment_vk_file}" ]]; then
println ACTION "${CCLI} ${NETWORK_ERA} address build --payment-verification-key-file ${payment_vk_file} --out-file ${payment_addr_file} ${NETWORK_IDENTIFIER}"
- if ${CCLI} ${NETWORK_ERA} address build --payment-verification-key-file "${payment_vk_file}" --out-file "${payment_addr_file}" ${NETWORK_IDENTIFIER} 2>/dev/null; then
+ if stdout=$(${CCLI} ${NETWORK_ERA} address build --payment-verification-key-file "${payment_vk_file}" --out-file "${payment_addr_file}" ${NETWORK_IDENTIFIER} 2>&1); then
pay_addr=$(cat "${payment_addr_file}")
return 0
+ else
+ println LOG "\n${FG_RED}ERROR${NC}: failure during payment address creation!\n${stdout}"
fi
fi
return 1
@@ -871,19 +1007,34 @@ getPayAddress() {
# Return : populates ${base_addr}
getBaseAddress() {
payment_vk_file="${WALLET_FOLDER}/${1}/${WALLET_PAY_VK_FILENAME}"
+ payment_script_file="${WALLET_FOLDER}/${1}/${WALLET_PAY_SCRIPT_FILENAME}"
stake_vk_file="${WALLET_FOLDER}/${1}/${WALLET_STAKE_VK_FILENAME}"
base_addr_file="${WALLET_FOLDER}/${1}/${WALLET_BASE_ADDR_FILENAME}"
[[ -f ${base_addr_file} ]] && base_addr=$(cat "${base_addr_file}") && return 0
base_addr=""
if [[ -f "${payment_vk_file}" && -f "${stake_vk_file}" ]]; then
println ACTION "${CCLI} ${NETWORK_ERA} address build --payment-verification-key-file ${payment_vk_file} --stake-verification-key-file ${stake_vk_file} --out-file ${base_addr_file} ${NETWORK_IDENTIFIER}"
- if ${CCLI} ${NETWORK_ERA} address build --payment-verification-key-file "${payment_vk_file}" --stake-verification-key-file "${stake_vk_file}" --out-file "${base_addr_file}" ${NETWORK_IDENTIFIER} 2>/dev/null; then
+ if stdout=$(${CCLI} ${NETWORK_ERA} address build --payment-verification-key-file "${payment_vk_file}" --stake-verification-key-file "${stake_vk_file}" --out-file "${base_addr_file}" ${NETWORK_IDENTIFIER} 2>&1); then
base_addr=$(cat "${base_addr_file}")
return 0
+ else
+ println LOG "\n${FG_RED}ERROR${NC}: failure during base address creation!\n${stdout}"
+ fi
+ elif [[ -f "${payment_script_file}" && -f "${stake_vk_file}" ]]; then
+ println ACTION "${CCLI} ${NETWORK_ERA} address build --payment-script-file ${payment_script_file} --stake-verification-key-file ${stake_vk_file} --out-file ${base_addr_file} ${NETWORK_IDENTIFIER}"
+ if stdout=$(${CCLI} ${NETWORK_ERA} address build --payment-script-file "${payment_script_file}" --stake-verification-key-file "${stake_vk_file}" --out-file "${base_addr_file}" ${NETWORK_IDENTIFIER} 2>&1); then
+ base_addr=$(cat "${base_addr_file}")
+ return 0
+ else
+ println LOG "\n${FG_RED}ERROR${NC}: failure during base address creation!\n${stdout}"
fi
elif [[ $# -eq 2 && -f "${1}" && -f "${2}" ]]; then
println ACTION "${CCLI} ${NETWORK_ERA} address build --payment-verification-key-file ${1} --stake-verification-key-file ${2} ${NETWORK_IDENTIFIER}"
- base_addr=$(${CCLI} ${NETWORK_ERA} address build --payment-verification-key-file "${1}" --stake-verification-key-file "${2}" ${NETWORK_IDENTIFIER} 2>/dev/null)
+ if base_addr=$(${CCLI} ${NETWORK_ERA} address build --payment-verification-key-file "${1}" --stake-verification-key-file "${2}" ${NETWORK_IDENTIFIER} 2>&1); then
+ return 0
+ else
+ println LOG "\n${FG_RED}ERROR${NC}: failure during base address creation!\n${base_addr}"
+ fi
fi
return 1
}
@@ -899,13 +1050,15 @@ getRewardAddress() {
reward_addr=""
if [[ -f "${stake_vk_file}" ]]; then
println ACTION "${CCLI} ${NETWORK_ERA} stake-address build --stake-verification-key-file ${stake_vk_file} --out-file ${stake_addr_file} ${NETWORK_IDENTIFIER}"
- if ${CCLI} ${NETWORK_ERA} stake-address build --stake-verification-key-file "${stake_vk_file}" --out-file "${stake_addr_file}" ${NETWORK_IDENTIFIER} 2>/dev/null; then
+ if stdout=$(${CCLI} ${NETWORK_ERA} stake-address build --stake-verification-key-file "${stake_vk_file}" --out-file "${stake_addr_file}" ${NETWORK_IDENTIFIER} 2>&1); then
reward_addr=$(cat "${stake_addr_file}")
return 0
+ else
+ println LOG "\n${FG_RED}ERROR${NC}: failure during reward address creation!\n${stdout}"
fi
elif [[ -f "${1}" ]]; then
- println ACTION "${CCLI} ${NETWORK_ERA} stake-address build --stake-verification-key-file ${1} ${NETWORK_IDENTIFIER}"
- reward_addr=$(${CCLI} ${NETWORK_ERA} stake-address build --stake-verification-key-file "${1}" ${NETWORK_IDENTIFIER} 2>/dev/null)
+ getRewardAddressFromKey ${1}
+ return $?
fi
return 1
}
@@ -916,7 +1069,62 @@ getRewardAddress() {
# Return : populates ${reward_addr}
getRewardAddressFromKey() {
println ACTION "${CCLI} ${NETWORK_ERA} stake-address build --stake-verification-key-file ${1} ${NETWORK_IDENTIFIER}"
- reward_addr=$(${CCLI} ${NETWORK_ERA} stake-address build --stake-verification-key-file "${1}" ${NETWORK_IDENTIFIER} 2>/dev/null)
+ if ! reward_addr=$(${CCLI} ${NETWORK_ERA} stake-address build --stake-verification-key-file "${1}" ${NETWORK_IDENTIFIER} 2>&1); then
+ println LOG "\n${FG_RED}ERROR${NC}: failure during reward address creation!\n${base_addr}"
+ return 1
+ fi
+}
+
+# Command : getPayScriptAddress [wallet name]
+# Description : create, store and save multi-sig payment script address
+# Parameters : wallet name > the name of the wallet
+# Return : populates ${pay_script_addr}
+getPayScriptAddress() {
+ payment_script_file="${WALLET_FOLDER}/${1}/${WALLET_PAY_SCRIPT_FILENAME}"
+ payment_script_addr_file="${WALLET_FOLDER}/${1}/${WALLET_PAY_SCRIPT_ADDR_FILENAME}"
+ [[ -f ${payment_script_addr_file} ]] && pay_script_addr=$(cat "${payment_script_addr_file}") && return 0
+ unset pay_script_addr
+ if [[ -f "${payment_script_file}" ]]; then
+ println ACTION "${CCLI} ${NETWORK_ERA} address build --payment-script-file ${payment_script_file} --out-file ${payment_script_addr_file} ${NETWORK_IDENTIFIER}"
+ if stdout=$(${CCLI} ${NETWORK_ERA} address build --payment-script-file "${payment_script_file}" --out-file "${payment_script_addr_file}" ${NETWORK_IDENTIFIER} 2>&1); then
+ pay_script_addr=$(cat "${payment_script_addr_file}")
+ return 0
+ else
+ println LOG "\n${FG_RED}ERROR${NC}: failure during payment script address creation!\n${stdout}"
+ fi
+ fi
+ return 1
+}
+
+# Command : getCredentials [wallet name]
+# Description : create and save wallet credentials (key hash) for payment and stake keys
+# Parameters : wallet name > the name of the wallet
+# Return : populates ${pay_cred} & ${stake_cred}
+getCredentials() {
+ payment_cred_file="${WALLET_FOLDER}/${1}/${WALLET_PAY_CRED_FILENAME}"
+ stake_cred_file="${WALLET_FOLDER}/${1}/${WALLET_STAKE_CRED_FILENAME}"
+ [[ -f ${payment_cred_file} && -f ${stake_cred_file} ]] && pay_cred=$(cat "${payment_cred_file}") && stake_cred=$(cat "${stake_cred_file}") && return 0
+ unset pay_cred stake_cred
+ payment_vk_file="${WALLET_FOLDER}/${1}/${WALLET_PAY_VK_FILENAME}"
+ stake_vk_file="${WALLET_FOLDER}/${1}/${WALLET_STAKE_VK_FILENAME}"
+ if [[ -f "${payment_vk_file}" ]]; then
+ println ACTION "${CCLI} ${NETWORK_ERA} address key-hash --payment-verification-key-file ${payment_vk_file} --out-file ${payment_cred_file}"
+ if stdout=$(${CCLI} ${NETWORK_ERA} address key-hash --payment-verification-key-file "${payment_vk_file}" --out-file "${payment_cred_file}" 2>&1); then
+ pay_cred=$(cat "${payment_cred_file}")
+ else
+ println LOG "\n${FG_RED}ERROR${NC}: failure during payment key hash creation!\n${stdout}"
+ return 1
+ fi
+ fi
+ if [[ -f "${stake_vk_file}" ]]; then
+ println ACTION "${CCLI} ${NETWORK_ERA} stake-address key-hash --stake-verification-key-file ${stake_vk_file} --out-file ${stake_cred_file}"
+ if stdout=$(${CCLI} ${NETWORK_ERA} stake-address key-hash --stake-verification-key-file "${stake_vk_file}" --out-file "${stake_cred_file}" 2>&1); then
+ stake_cred=$(cat "${stake_cred_file}")
+ else
+ println LOG "\n${FG_RED}ERROR${NC}: failure during stake key hash creation!\n${stdout}"
+ return 1
+ fi
+ fi
}
# Command : getAddressInfo [address]
@@ -925,15 +1133,17 @@ getRewardAddressFromKey() {
# Return : populates ${address_info}
getAddressInfo() {
println ACTION "${CCLI} ${NETWORK_ERA} address info --address $1"
- address_info=$(${CCLI} ${NETWORK_ERA} address info --address $1)
+ if ! address_info=$(${CCLI} ${NETWORK_ERA} address info --address $1 2>&1); then
+ println LOG "\n${FG_RED}ERROR${NC}: failure during reward address creation!\n${base_addr}"
+ return 1
+ fi
}
# Command : getBalance [address]
# Description : check balance for provided address
# Parameters : address > the wallet address to query
-# Return : populates associative arrays ${assets[]} & ${policyIDs[]}
getBalance() {
- declare -gA utxos=(); declare -gA assets=(); declare -gA policyIDs=()
+ declare -gA utxos=(); declare -gA assets=()
assets["lovelace"]=0; utxo_cnt=0
asset_name_maxlen=5; asset_amount_maxlen=12
tx_in=""
@@ -961,8 +1171,9 @@ getBalance() {
if ! isNumber "${asset_amount}"; then break; fi
asset_hash_name="${utxo_entry[$((idx+1))]}"
IFS='.' read -ra asset <<< "${asset_hash_name}"
- policyIDs["${asset[0]}"]=1
- [[ ${#asset[@]} -eq 2 && ${#asset[1]} -gt ${asset_name_maxlen} ]] && asset_name_maxlen=${#asset[1]}
+ tname="$(hexToAscii ${asset[1]})"
+ tname="${tname//[![:print:]]/}"
+ [[ ${#asset[@]} -eq 2 && ${#tname} -gt ${asset_name_maxlen} ]] && asset_name_maxlen=${#tname}
asset_amount_fmt="$(formatAsset ${asset_amount})"
[[ ${#asset_amount_fmt} -gt ${asset_amount_maxlen} ]] && asset_amount_maxlen=${#asset_amount_fmt}
assets["${asset_hash_name}"]=$(( ${assets["${asset_hash_name}"]:-0} + asset_amount ))
@@ -977,9 +1188,129 @@ getBalance() {
[[ ${#lovelace_fmt} -gt ${asset_amount_maxlen} ]] && asset_amount_maxlen=${#lovelace_fmt}
}
+# Command : getBalanceKoios parse_assets
+# Description : check balance for provided addresses using Koios API
+# Parameters : parse_assets > [true|false] should additional assets on utxo be parsed or not (default=true)
+getBalanceKoios() {
+ # generate different arrays using key constructed in format:
,
+ # Ex: ( [addr123,lovelace]=1000 [addr456,policy.name]=500 )
+ # Its assumed that an array called addr_list has been populated with all addresses to fetch balance for
+
+ declare -gA utxos=(); declare -gA utxos_cnt=(); declare -gA assets=(); declare -gA tx_in_arr=(); declare -gA asset_name_maxlen_arr=(); declare -gA asset_amount_maxlen_arr=()
+
+ if [[ -n ${KOIOS_API} && -n ${addr_list+x} ]]; then
+ printf -v addr_list_joined '\"%s\",' "${addr_list[@]}"
+ [[ $1 != false ]] && extended=true || extended=false
+ println ACTION "curl -sSL -f -X POST -H \"Content-Type: application/json\" -H \"accept: text/csv\" -d '{\"_addresses\":[${addr_list_joined%,}],\"_extended\":${extended}}' ${KOIOS_API}/address_utxos?select=address,tx_hash,tx_index,value,asset_list"
+ ! address_utxo_list=$(curl -sSL -f -X POST -H "Content-Type: application/json" -H "accept: text/csv" -d '{"_addresses":['${addr_list_joined%,}'],"_extended":'${extended}'}' "${KOIOS_API}/address_utxos?select=address,tx_hash,tx_index,value,asset_list" 2>&1) && println "ERROR" "\n${FG_RED}KOIOS_API ERROR${NC}: ${address_utxo_list}\n" && return 1 # print error and return
+ [[ -z ${address_utxo_list} ]] && return
+ while IFS=',' read -r _address _tx_hash _tx_index _value _asset_list; do
+ [[ ${_address} = address ]] && continue # header line
+ index_prefix="${_address},"
+ assets["${index_prefix}lovelace"]=$(( ${assets["${index_prefix}lovelace"]:-0} + _value ))
+ utxos["${index_prefix}${_tx_hash}#${_tx_index}. ADA"]=${_value}
+ utxos_cnt["${_address}"]=$(( ${utxos_cnt["${_address}"]:-0} + 1 ))
+ tx_in_arr["${_address}"]="${tx_in_arr["${_address}"]} --tx-in ${_tx_hash}#${_tx_index}"
+ if [[ $1 != false ]]; then
+ asset_list_unescaped=${_asset_list:1: -1} # remove first and last char (quotation)
+ asset_list_unescaped=$(sed 's/""/"/g' <<< "${asset_list_unescaped}") # remove all double quotes, sed seems to perform better than bash string manipulation
+ while IFS=',' read -r _policy_id _asset_name _quantity; do
+ tname="$(hexToAscii ${_asset_name})"
+ tname="${tname//[![:print:]]/}"
+ [[ ${#tname} -gt ${asset_name_maxlen_arr["${_address}"]:-5} ]] && asset_name_maxlen_arr["${_address}"]=${#tname}
+ asset_amount_fmt="$(formatAsset ${_quantity})"
+ [[ ${#asset_amount_fmt} -gt ${asset_amount_maxlen_arr["${_address}"]:-12} ]] && asset_amount_maxlen_arr["${_address}"]=${#asset_amount_fmt}
+ assets["${index_prefix}${_policy_id}.${_asset_name}"]=$(( ${assets["${index_prefix}${_policy_id}.${_asset_name}"]:-0} + _quantity ))
+ utxos["${index_prefix}${_tx_hash}#${_tx_index}.${_policy_id}.${_asset_name}"]=${_quantity}
+ done < <( jq -cr '.[] | "\(.policy_id),\(.asset_name),\(.quantity)"' <<< "${asset_list_unescaped}" )
+ fi
+ done <<< "${address_utxo_list}"
+ fi
+}
+
+# Command : getWalletBalance [wallet name] [force] [base] [pay] [asset]
+# Description : get balance for wallet
+# Parameters : force > optional: [true|false] force update of balance (default = false)
+# : base > optional: [true|false] get base address balance (default = true)
+# : pay > optional: [true|false] get payment address balance (default = true)
+# : asset > optional: [true|false] fetch additional koios asset data (default = false)
+getWalletBalance() {
+ addr_list=()
+ declare -gA base_assets=(); declare -gA pay_assets=()
+ [[ $2 = true ]] && declare -gA balances=()
+ [[ $5 = true ]] && asset_info=true || asset_info=false
+ if [[ $3 != false ]] && getBaseAddress $1 && [[ -n ${base_addr} ]]; then
+ if [[ -v balances[${base_addr}] ]]; then
+ base_lovelace=${balances[${base_addr}]}
+ else
+ if [[ -n ${KOIOS_API} ]]; then
+ addr_list+=(${base_addr})
+ else
+ getBalance ${base_addr}
+ base_lovelace=${assets[lovelace]:-0}
+ for idx in "${!assets[@]}"; do base_assets[${idx}]=${assets[${idx}]}; done
+ fi
+ fi
+ else
+ base_lovelace=0
+ fi
+ if [[ $4 != false ]] && getPayAddress $1 && [[ -n ${pay_addr} ]]; then
+ if [[ -v balances[${pay_addr}] ]]; then
+ pay_lovelace=${balances[${pay_addr}]}
+ else
+ if [[ -n ${KOIOS_API} ]]; then
+ addr_list+=(${pay_addr})
+ else
+ getBalance ${pay_addr}
+ pay_lovelace=${assets[lovelace]:-0}
+ for idx in "${!assets[@]}"; do pay_assets[${idx}]=${assets[${idx}]}; done
+ fi
+ fi
+ else
+ pay_lovelace=0
+ fi
+ if [[ ${#addr_list[@]} -gt 0 ]]; then
+ getBalanceKoios ${asset_info}
+ if [[ -n ${base_addr} ]]; then
+ base_lovelace=${assets["${base_addr},lovelace"]:-0}
+ for idx in "${!assets[@]}"; do [[ ${idx} != "${base_addr},"* ]] && continue; base_assets[${idx#*,}]=${assets[${idx}]}; done
+ fi
+ if [[ -n ${pay_addr} ]]; then
+ pay_lovelace=${assets["${pay_addr},lovelace"]:-0}
+ for idx in "${!assets[@]}"; do [[ ${idx} != "${pay_addr},"* ]] && continue; pay_assets[${idx#*,}]=${assets[${idx}]}; done
+ fi
+ fi
+}
+
+# Command : getAddressBalance [address] [force] [asset]
+# Description : get balance for address
+# Parameters : force > optional: [true|false] force update of balance (default = false)
+# : asset > optional: [true|false] fetch additional koios asset data (default = false)
+getAddressBalance() {
+ [[ $2 = true ]] && declare -gA balances=()
+ [[ $3 = true ]] && asset_info=true || asset_info=false
+ if [[ -n ${1} ]]; then
+ if [[ -v balances[${1}] ]]; then
+ lovelace=${balances[${1}]}
+ else
+ if [[ -n ${KOIOS_API} ]]; then
+ addr_list=(${1})
+ getBalanceKoios ${asset_info}
+ lovelace=${assets["${1},lovelace"]:-0}
+ else
+ getBalance ${1}
+ lovelace=${assets[lovelace]:-0}
+ fi
+ fi
+ else
+ lovelace=0
+ fi
+}
+
# Command : getAssetsTxOut [PolicyID.AssetName] [Amount]
# Description : generate tx out string for multi-assets in wallet
# getBalance assumed to be run before calling this function
+# address variable assumed to be set to selected wallet bech32 address
# Parameters : PolicyID.AssetName > optional: Adjust balance for this asset before generating output
# Amount > optional: The amount to adjust balance
# Return : populates ${assets_tx_out}
@@ -990,8 +1321,8 @@ getAssetsTxOut() {
assets[$1]=$(( old_value + $2 ))
fi
for idx in "${!assets[@]}"; do
- [[ ${idx} = "lovelace" ]] && continue
- [[ ${assets[${idx}]} -gt 0 ]] && assets_tx_out+="+${assets[${idx}]} ${idx}"
+ [[ ${idx} = *lovelace ]] && continue
+ [[ ${assets[${idx}]} -gt 0 ]] && assets_tx_out+="+${assets[${idx}]} ${idx#*,}"
done
}
@@ -1000,6 +1331,7 @@ getAssetsTxOut() {
# : string as passed to --tx-out parameter
# Return : populates ${min_utxo_out}
getMinUTxO() {
+ unset min_utxo_out
min_utxo_args=(
${NETWORK_ERA}
transaction calculate-min-required-utxo
@@ -1007,31 +1339,72 @@ getMinUTxO() {
--tx-out "$1"
)
println ACTION "${CCLI} ${min_utxo_args[*]}"
- min_utxo_out=$([[ "$(${CCLI} "${min_utxo_args[@]}")" =~ ([0-9]+) ]] && echo ${BASH_REMATCH[1]})
+ if ! stdout=$(${CCLI} "${min_utxo_args[@]}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during min utxo calculation!\n${stdout}"
+ return 1
+ fi
+ min_utxo_out=$([[ ${stdout} =~ ([0-9]+) ]] && echo ${BASH_REMATCH[1]})
}
-# Command : getRewards [wallet name]
+# Command : getWalletRewards [wallet name] [force]
# Description : check balance of reward address
# Parameters : wallet name > the name of the wallet
# Return : populates ${reward_lovelace}
-getRewards() {
+getWalletRewards() {
reward_lovelace=-1
+ if [[ $2 = true ]]; then
+ declare -gA rewards_available=(); declare -gA reward_status=(); declare -gA reward_pool=();
+ fi
if isWalletRegistered $1; then
reward_lovelace=0
- for reward_entry in $(jq -r '.[] | @base64' <<< "${stake_address_info}"); do
- _jq() { base64 -d <<< ${reward_entry} | jq -r "${1}"; }
- reward_lovelace=$(( reward_lovelace + $(_jq '.rewardAccountBalance //0') ))
- done
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
+ for reward_entry in $(jq -r '.[] | @base64' <<< "${stake_address_info}"); do
+ _jq() { base64 -d <<< ${reward_entry} | jq -r "${1}"; }
+ reward_lovelace=$(( reward_lovelace + $(_jq '.rewardAccountBalance //0') ))
+ done
+ else
+ reward_lovelace=${rewards_available[${reward_addr}]:-0}
+ fi
fi
}
+
+# Command : getRewardInfoKoios
+# Description : check status and rewards for provided reward addresses using Koios API
+getRewardInfoKoios() {
+ # generate different arrays using reward address as key, rewards available, status and delegated pool if any
+ # Its assumed that an array called reward_addr_list has been populated with all reward addresses to fetch data for
+
+ declare -gA rewards_available=(); declare -gA reward_status=(); declare -gA reward_pool=();
+
+ # set defaults
+ for _reward_addr in "${reward_addr_list[@]}"; do
+ reward_status["${_reward_addr}"]="not registered"
+ rewards_available["${_reward_addr}"]=0
+ unset 'reward_pool[${_reward_addr}]'
+ done
+
+ if [[ -n ${KOIOS_API} && -n ${reward_addr_list+x} ]]; then
+ printf -v addr_list_joined '\"%s\",' "${reward_addr_list[@]}"
+ println ACTION "curl -sSL -f -X POST -H \"Content-Type: application/json\" -H \"accept: text/csv\" -d '{\"_stake_addresses\":[${addr_list_joined%,}]}' ${KOIOS_API}/account_info?select=stake_address,status,delegated_pool,rewards_available"
+ ! account_info_list=$(curl -sSL -f -X POST -H "Content-Type: application/json" -H "accept: text/csv" -d '{"_stake_addresses":['${addr_list_joined%,}']}' "${KOIOS_API}/account_info?select=stake_address,status,delegated_pool,rewards_available" 2>&1) && println "ERROR" "\n${FG_RED}KOIOS_API ERROR${NC}: ${account_info_list}\n" && return 1 # print error and return
+ [[ -z ${account_info_list} ]] && return
+ while IFS=',' read -r stake_address status delegated_pool rewards_available; do
+ [[ ${stake_address} = stake_address ]] && continue # header line
+ reward_status["${stake_address}"]="${status}"
+ rewards_available["${stake_address}"]="${rewards_available}"
+ [[ -n ${delegated_pool} ]] && reward_pool["${stake_address}"]="${delegated_pool}"
+ done <<< "${account_info_list}"
+ fi
+}
+
# Command : getRewardsFromAddr [stake address]
# Description : check balance of reward address
# Parameters : stake address > the address from stake.vkey
# Return : populates ${reward_lovelace}
getRewardsFromAddr() {
- println ACTION "${CCLI} ${NETWORK_ERA} query stake-address-info ${NETWORK_IDENTIFIER} --address ${1}"
- stake_address_info=$(${CCLI} ${NETWORK_ERA} query stake-address-info ${NETWORK_IDENTIFIER} --address ${1})
reward_lovelace=0
+ println ACTION "${CCLI} ${NETWORK_ERA} query stake-address-info ${NETWORK_IDENTIFIER} --address ${1}"
+ ! stake_address_info=$(${CCLI} ${NETWORK_ERA} query stake-address-info ${NETWORK_IDENTIFIER} --address ${1}) && println "ERROR" "\n${FG_RED}NODE CLI ERROR${NC}: ${stake_address_info}\n" && return 1 # print error and return
for reward_entry in $(jq -r '.[] | @base64' <<< "${stake_address_info}"); do
_jq() { base64 -d <<< ${reward_entry} | jq -r "${1}"; }
reward_lovelace=$(( reward_lovelace + $(_jq '.rewardAccountBalance //0') ))
@@ -1043,19 +1416,25 @@ getRewardsFromAddr() {
# Parameters : wallet name > the name of the wallet
isWalletRegistered() {
if getRewardAddress $1; then
- println ACTION "${CCLI} ${NETWORK_ERA} query stake-address-info ${NETWORK_IDENTIFIER} --address ${reward_addr}"
- stake_address_info=$(${CCLI} ${NETWORK_ERA} query stake-address-info ${NETWORK_IDENTIFIER} --address ${reward_addr})
- [[ -n "${stake_address_info}" && $(jq -r 'length' <<< ${stake_address_info}) -gt 0 ]] && return 0
+ if [[ -n ${KOIOS_API} ]]; then
+ [[ ! -v "reward_status[${reward_addr}]" ]] && reward_addr_list=( ${reward_addr} ) && getRewardInfoKoios
+ [[ ${reward_status[${reward_addr}]} = registered ]] && return 0
+ else
+ println ACTION "${CCLI} ${NETWORK_ERA} query stake-address-info ${NETWORK_IDENTIFIER} --address ${reward_addr}"
+ ! stake_address_info=$(${CCLI} ${NETWORK_ERA} query stake-address-info ${NETWORK_IDENTIFIER} --address ${reward_addr}) && println "ERROR" "\n${FG_RED}NODE CLI ERROR${NC}: ${stake_address_info}\n" && return 1 # print error and return
+ [[ -n "${stake_address_info}" && $(jq -r 'length' <<< ${stake_address_info}) -gt 0 ]] && return 0
+ fi
fi
return 1
}
# Command : getWalletType [wallet name]
-# Description : check if wallet is a hardware wallet, 0=yes, 1=cli, 2=cli & encrypted, 3=signing keys missing, 4=verification keys missing
+# Description : check if wallet is a hardware wallet, 0=yes, 1=cli, 2=cli & encrypted, 3=signing keys missing, 4=verification keys missing, 5=multi-sig
# Parameters : wallet name > the name of the wallet
getWalletType() {
payment_vk_file="${WALLET_FOLDER}/${1}/${WALLET_PAY_VK_FILENAME}"
payment_sk_file="${WALLET_FOLDER}/${1}/${WALLET_PAY_SK_FILENAME}"
+ payment_script_file="${WALLET_FOLDER}/${1}/${WALLET_PAY_SCRIPT_FILENAME}"
stake_vk_file="${WALLET_FOLDER}/${1}/${WALLET_STAKE_VK_FILENAME}"
stake_sk_file="${WALLET_FOLDER}/${1}/${WALLET_STAKE_SK_FILENAME}"
if [[ -f "${WALLET_FOLDER}/${1}/${WALLET_PAY_VK_FILENAME}" && -f "${WALLET_FOLDER}/${1}/${WALLET_STAKE_VK_FILENAME}" ]]; then # CNTools wallet
@@ -1068,6 +1447,8 @@ getWalletType() {
else
[[ ${op_mode} = "online" && ( ! -f ${payment_sk_file} || ! -f ${stake_sk_file} ) ]] && return 3 || return 1
fi
+ elif [[ -f "${WALLET_FOLDER}/${1}/${WALLET_PAY_SCRIPT_FILENAME}" && -f "${WALLET_FOLDER}/${1}/${WALLET_STAKE_VK_FILENAME}" ]]; then # CNTools multi-sig wallet
+ return 5
else
return 4
fi
@@ -1133,23 +1514,27 @@ registerStakeWallet() {
wallet_name=$1
wallet_source="base"
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ utxo_cnt=${utxos_cnt[${base_addr}]}
+ tx_in=${tx_in_arr[${base_addr}]}
+ fi
+
if [[ -z $2 || $2 = "false" ]]; then
println DEBUG "Wallet ${FG_GREEN}${wallet_name}${NC} not registered on chain"
- waitForInput "press any key to continue with registration"
+ waitToProceed "press any key to continue with registration"
fi
stake_vk_file="${WALLET_FOLDER}/${wallet_name}/${WALLET_STAKE_VK_FILENAME}"
stake_cert_file="${WALLET_FOLDER}/${wallet_name}/${WALLET_STAKE_CERT_FILENAME}"
- getBaseAddress "${wallet_name}"
- getBalance ${base_addr}
-
println ACTION "${CCLI} ${NETWORK_ERA} stake-address registration-certificate --stake-verification-key-file ${stake_vk_file} --out-file ${stake_cert_file}"
- if ! ${CCLI} ${NETWORK_ERA} stake-address registration-certificate --stake-verification-key-file "${stake_vk_file}" --out-file "${stake_cert_file}"; then return 1; fi
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} stake-address registration-certificate --stake-verification-key-file "${stake_vk_file}" --out-file "${stake_cert_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during stake registration certificate creation!\n${stdout}"; return 1
+ fi
if ! getTTL; then return 1; fi
- stakeAddressDeposit=$(jq -r '.stakeAddressDeposit' <<< "${PROT_PARAMS}")
- println LOG "Key Deposit is ${stakeAddressDeposit}"
+
+ println LOG "Key Deposit is ${KEY_DEPOSIT}"
getAssetsTxOut
@@ -1164,20 +1549,20 @@ registerStakeWallet() {
if ! buildTx; then return 1; fi
- calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2
+ calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2 || return 1
- newBalance=$(( ${assets[lovelace]} - min_fee - stakeAddressDeposit ))
- println LOG "New balance after tx fee and key deposit is $(formatLovelace ${newBalance}) ADA ($(formatLovelace ${assets[lovelace]}) - $(formatLovelace ${min_fee}) - $(formatLovelace ${stakeAddressDeposit}))"
+ newBalance=$(( base_lovelace - min_fee - KEY_DEPOSIT ))
+ println LOG "New balance after tx fee and key deposit is $(formatLovelace ${newBalance}) ADA ($(formatLovelace ${base_lovelace}) - $(formatLovelace ${min_fee}) - $(formatLovelace ${KEY_DEPOSIT}))"
- if [[ ${assets[lovelace]} -lt $(( min_fee + stakeAddressDeposit )) ]]; then
+ if [[ ${base_lovelace} -lt $(( min_fee + KEY_DEPOSIT )) ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Not enough ADA in base address for tx fee and key deposit!"\
- "Funds in address: ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"\
- "Minimum required: ${FG_LBLUE}$(formatLovelace $(( min_fee + stakeAddressDeposit )))${NC} ADA"
+ "Funds in address: ${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA"\
+ "Minimum required: ${FG_LBLUE}$(formatLovelace $(( min_fee + KEY_DEPOSIT )))${NC} ADA"
return 1
fi
tx_out="${base_addr}+${newBalance}${assets_tx_out}"
- getMinUTxO "${tx_out}"
+ getMinUTxO "${tx_out}" || return 1
if [[ ${newBalance} -lt ${min_utxo_out} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: minimum UTxO value not fulfilled, only ${FG_LBLUE}$(formatLovelace ${newBalance})${NC} ADA left in address after tx fee and key deposit, at least ${FG_LBLUE}$(formatLovelace ${min_utxo_out})${NC} ADA required!"
return 1
@@ -1197,7 +1582,7 @@ registerStakeWallet() {
if [[ ${op_mode} = "hybrid" ]]; then
if ! buildOfflineJSON "Wallet Registration"; then return 1; fi
if ! offlineJSON=$(jq ". += { \"wallet-name\": \"${wallet_name}\" }" <<< ${offlineJSON}); then return 1; fi
- if ! offlineJSON=$(jq ". += { txFee: \"$(( min_fee + stakeAddressDeposit ))\" }" <<< ${offlineJSON}); then return 1; fi
+ if ! offlineJSON=$(jq ". += { txFee: \"$(( min_fee + KEY_DEPOSIT ))\" }" <<< ${offlineJSON}); then return 1; fi
if ! offlineJSON=$(jq ". += { txBody: $(jq -c . "${TMP_DIR}"/tx.raw) }" <<< ${offlineJSON}); then return 1; fi
if ! offlineJSON=$(jq ". += { \"signing-file\": [] }" <<< ${offlineJSON}); then return 1; fi
if ! offlineJSON=$(jq ".\"signing-file\" += [{ name: \"Wallet '${wallet_name}' payment signing key\", vkey: $(jq -c . "${payment_vk_file}") }]" <<< ${offlineJSON}); then return 1; fi
@@ -1229,14 +1614,20 @@ deregisterStakeWallet() {
wallet_source="base"
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ utxo_cnt=${utxos_cnt[${base_addr}]}
+ tx_in=${tx_in_arr[${base_addr}]}
+ fi
+
stake_dereg_file="${WALLET_FOLDER}/${wallet_name}/${WALLET_STAKE_DEREG_FILENAME}"
println ACTION "${CCLI} ${NETWORK_ERA} stake-address deregistration-certificate --stake-verification-key-file ${stake_vk_file} --out-file ${stake_dereg_file}"
- if ! ${CCLI} ${NETWORK_ERA} stake-address deregistration-certificate --stake-verification-key-file "${stake_vk_file}" --out-file "${stake_dereg_file}"; then return 1; fi
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} stake-address deregistration-certificate --stake-verification-key-file "${stake_vk_file}" --out-file "${stake_dereg_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during stake deregistration certificate creation!\n${stdout}"; return 1
+ fi
if ! getTTL; then return 1; fi
- stakeAddressDeposit=$(jq -r '.stakeAddressDeposit' <<< "${PROT_PARAMS}")
- println LOG "Key Deposit is ${stakeAddressDeposit}"
+ println LOG "Key Deposit is ${KEY_DEPOSIT}"
getAssetsTxOut
@@ -1251,20 +1642,20 @@ deregisterStakeWallet() {
if ! buildTx; then return 1; fi
- calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2
+ calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2 || return 1
- newBalance=$(( ${assets[lovelace]} + stakeAddressDeposit - min_fee ))
- println LOG "New balance after returned key deposit and subtracted tx fee is $(formatLovelace ${newBalance}) ADA ($(formatLovelace ${assets[lovelace]}) + $(formatLovelace ${stakeAddressDeposit}) - $(formatLovelace ${min_fee}))"
+ newBalance=$(( base_lovelace + KEY_DEPOSIT - min_fee ))
+ println LOG "New balance after returned key deposit and subtracted tx fee is $(formatLovelace ${newBalance}) ADA ($(formatLovelace ${base_lovelace}) + $(formatLovelace ${KEY_DEPOSIT}) - $(formatLovelace ${min_fee}))"
- if [[ $(( ${assets[lovelace]} + stakeAddressDeposit )) -lt ${min_fee} ]]; then
+ if [[ $(( ${base_lovelace} + KEY_DEPOSIT )) -lt ${min_fee} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Not enough ADA in base address for tx fee!"\
- "Funds in address: ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"\
- "Minimum required: ${FG_LBLUE}$(formatLovelace $(( min_fee - stakeAddressDeposit )))${NC} ADA"
+ "Funds in address: ${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA"\
+ "Minimum required: ${FG_LBLUE}$(formatLovelace $(( min_fee - KEY_DEPOSIT )))${NC} ADA"
return 1
fi
tx_out="${base_addr}+${newBalance}${assets_tx_out}"
- getMinUTxO "${tx_out}"
+ getMinUTxO "${tx_out}" || return 1
if [[ ${newBalance} -lt ${min_utxo_out} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: minimum UTxO value not fulfilled, only ${FG_LBLUE}$(formatLovelace ${newBalance})${NC} ADA left in address after tx fee and returned key deposit, at least ${FG_LBLUE}$(formatLovelace ${min_utxo_out})${NC} ADA required!"
return 1
@@ -1284,7 +1675,7 @@ deregisterStakeWallet() {
if [[ ${op_mode} = "hybrid" ]]; then
if ! buildOfflineJSON "Wallet De-Registration"; then return 1; fi
if ! offlineJSON=$(jq ". += { \"wallet-name\": \"${wallet_name}\" }" <<< ${offlineJSON}); then return 1; fi
- if ! offlineJSON=$(jq ". += { \"amount-returned\": \"${stakeAddressDeposit}\" }" <<< ${offlineJSON}); then return 1; fi
+ if ! offlineJSON=$(jq ". += { \"amount-returned\": \"${KEY_DEPOSIT}\" }" <<< ${offlineJSON}); then return 1; fi
if ! offlineJSON=$(jq ". += { txFee: \"${min_fee}\" }" <<< ${offlineJSON}); then return 1; fi
if ! offlineJSON=$(jq ". += { txBody: $(jq -c . "${TMP_DIR}"/tx.raw) }" <<< ${offlineJSON}); then return 1; fi
if ! offlineJSON=$(jq ". += { \"signing-file\": [] }" <<< ${offlineJSON}); then return 1; fi
@@ -1314,6 +1705,11 @@ sendAssets() {
[[ $(cat "${WALLET_FOLDER}/${s_wallet}/${WALLET_PAY_ADDR_FILENAME}" 2>/dev/null) = "${s_addr}" ]] && wallet_source="enterprise" || wallet_source="base"
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ utxo_cnt=${utxos_cnt[${s_addr}]}
+ tx_in=${tx_in_arr[${s_addr}]}
+ fi
+
if ! getTTL; then return 1; fi
if [[ -n ${metafile} && -f ${metafile} ]]; then
@@ -1321,8 +1717,6 @@ sendAssets() {
else
metafile_param=""
fi
-
- getBalance ${s_addr}
[[ ${#assets_left[@]} -eq 0 ]] && outCount=1 || outCount=2
@@ -1352,7 +1746,7 @@ sendAssets() {
if ! buildTx; then return 1; fi
- calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} ${outCount} 1
+ calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} ${outCount} 1 || return 1
build_args=(
${tx_in}
@@ -1365,7 +1759,7 @@ sendAssets() {
if [[ ${outCount} -eq 1 ]]; then # all assets to destination, nothing to return
newBalance=0
tx_out="${d_addr}+$(( ${assets_to_send[lovelace]} - min_fee ))${assets_tx_out_d}"
- getMinUTxO "${tx_out}"
+ getMinUTxO "${tx_out}" || return 1
if [[ ${assets_to_send[lovelace]} -lt ${min_utxo_out} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Not enough ADA in address ( $(formatLovelace ${assets_to_send[lovelace]}) < $(formatLovelace ${min_utxo_out}) )"
println ERROR "Top up wallet with enough ADA to cover minimum UTxO balance"
@@ -1374,10 +1768,10 @@ sendAssets() {
build_args+=( --tx-out "${tx_out}" )
else
if [[ ${include_fee} = "no" ]]; then
- newBalance=$(( ${assets[lovelace]} - ${assets_to_send[lovelace]} - min_fee ))
+ newBalance=$(( ${assets[${index_prefix}lovelace]} - ${assets_to_send[lovelace]} - min_fee ))
tx_out_d="${d_addr}+${assets_to_send[lovelace]}${assets_tx_out_d}"
else
- newBalance=$(( ${assets[lovelace]} - ${assets_to_send[lovelace]} ))
+ newBalance=$(( ${assets[${index_prefix}lovelace]} - ${assets_to_send[lovelace]} ))
tx_out_d="${d_addr}+$(( ${assets_to_send[lovelace]} - min_fee ))${assets_tx_out_d}"
fi
getMinUTxO "${tx_out_d}"
@@ -1438,6 +1832,11 @@ delegate() {
wallet_source="base"
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ utxo_cnt=${utxos_cnt[${base_addr}]}
+ tx_in=${tx_in_arr[${base_addr}]}
+ fi
+
if ! getTTL; then return 1; fi
getAssetsTxOut
@@ -1453,20 +1852,20 @@ delegate() {
if ! buildTx; then return 1; fi
- calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2
+ calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2 || return 1
- newBalance=$(( ${assets[lovelace]} - min_fee ))
- println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${assets[lovelace]}) - $(formatLovelace ${min_fee}) )"
+ newBalance=$(( base_lovelace - min_fee ))
+ println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${base_lovelace}) - $(formatLovelace ${min_fee}) )"
- if [[ ${assets[lovelace]} -lt ${min_fee} ]]; then
+ if [[ ${base_lovelace} -lt ${min_fee} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Not enough ADA in base address for tx fee!"\
- "Funds in address: ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"\
+ "Funds in address: ${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA"\
"Minimum required: ${FG_LBLUE}$(formatLovelace ${min_fee})${NC} ADA"
return 1
fi
tx_out="${base_addr}+${newBalance}${assets_tx_out}"
- getMinUTxO "${tx_out}"
+ getMinUTxO "${tx_out}" || return 1
if [[ ${newBalance} -lt ${min_utxo_out} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: minimum UTxO value not fulfilled, only ${FG_LBLUE}$(formatLovelace ${newBalance})${NC} ADA left in address after tx fee, at least ${FG_LBLUE}$(formatLovelace ${min_utxo_out})${NC} ADA required!"
return 1
@@ -1517,6 +1916,11 @@ withdrawRewards() {
wallet_source="base"
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ utxo_cnt=${utxos_cnt[${base_addr}]}
+ tx_in=${tx_in_arr[${base_addr}]}
+ fi
+
if ! getTTL; then return 1; fi
getAssetsTxOut
@@ -1531,20 +1935,20 @@ withdrawRewards() {
if ! buildTx; then return 1; fi
- calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2
+ calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2 || return 1
- newBalance=$(( ${assets[lovelace]} - min_fee + reward_lovelace ))
- println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${assets[lovelace]}) - $(formatLovelace ${min_fee}) )"
+ newBalance=$(( base_lovelace - min_fee + reward_lovelace ))
+ println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${base_lovelace}) - $(formatLovelace ${min_fee}) )"
- if [[ ${assets[lovelace]} -lt ${min_fee} ]]; then
+ if [[ ${base_lovelace} -lt ${min_fee} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Not enough ADA in base address for tx fee!"\
- "Funds in address: ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"\
+ "Funds in address: ${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA"\
"Minimum required: ${FG_LBLUE}$(formatLovelace $((min_fee - reward_lovelace)))${NC} ADA"
return 1
fi
tx_out="${base_addr}+${newBalance}${assets_tx_out}"
- getMinUTxO "${tx_out}"
+ getMinUTxO "${tx_out}" || return 1
if [[ ${newBalance} -lt ${min_utxo_out} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: minimum UTxO value not fulfilled, only ${FG_LBLUE}$(formatLovelace ${newBalance})${NC} ADA left in address after tx fee and withdrawal, at least ${FG_LBLUE}$(formatLovelace ${min_utxo_out})${NC} ADA required!"
return 1
@@ -1590,13 +1994,14 @@ withdrawRewards() {
# Description : Register pool with pledge on chain
registerPool() {
- getBaseAddress ${owner_wallets[0]}
- getBalance ${base_addr}
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ utxo_cnt=${utxos_cnt[${base_addr}]}
+ tx_in=${tx_in_arr[${base_addr}]}
+ fi
if ! getTTL; then return 1; fi
- stakePoolDeposit=$(jq -r '.stakePoolDeposit' <<< "${PROT_PARAMS}")
- println LOG "Pool Deposit is ${stakePoolDeposit}"
+ println LOG "Pool Deposit is ${POOL_DEPOSIT}"
owner_delegation_cert=""
[[ ${delegate_owner_wallet} = 'Y' ]] && owner_delegation_cert="--certificate-file ${owner_delegation_cert_file}"
@@ -1622,20 +2027,20 @@ registerPool() {
if ! buildTx; then return 1; fi
- calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_count}
+ calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_count} || return 1
- newBalance=$(( ${assets[lovelace]} - min_fee - stakePoolDeposit ))
- println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${assets[lovelace]}) - $(formatLovelace ${min_fee}) - $(formatLovelace ${stakePoolDeposit}) )"
+ newBalance=$(( base_lovelace - min_fee - POOL_DEPOSIT ))
+ println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${base_lovelace}) - $(formatLovelace ${min_fee}) - $(formatLovelace ${POOL_DEPOSIT}) )"
- if [[ ${assets[lovelace]} -lt $(( min_fee + stakePoolDeposit )) ]]; then
+ if [[ ${base_lovelace} -lt $(( min_fee + POOL_DEPOSIT )) ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Not enough ADA in base address for tx fee and pool registration deposit!"\
- "Funds in address: ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"\
- "Minimum required: ${FG_LBLUE}$(formatLovelace $(( min_fee + stakePoolDeposit )))${NC} ADA"
+ "Funds in address: ${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA"\
+ "Minimum required: ${FG_LBLUE}$(formatLovelace $(( min_fee + POOL_DEPOSIT )))${NC} ADA"
return 1
fi
tx_out="${base_addr}+${newBalance}${assets_tx_out}"
- getMinUTxO "${tx_out}"
+ getMinUTxO "${tx_out}" || return 1
if [[ ${newBalance} -lt ${min_utxo_out} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: minimum UTxO value not fulfilled, only ${FG_LBLUE}$(formatLovelace ${newBalance})${NC} ADA left in address after tx fee and pool registration deposit, at least ${FG_LBLUE}$(formatLovelace ${min_utxo_out})${NC} ADA required!"
return 1
@@ -1671,7 +2076,7 @@ registerPool() {
if ! offlineJSON=$(jq ". += { \"pool-margin\": \"${margin}\" }" <<< ${offlineJSON}); then return 1; fi
if ! offlineJSON=$(jq ". += { \"pool-cost\": \"${cost_ada}\" }" <<< ${offlineJSON}); then return 1; fi
if ! offlineJSON=$(jq ". += { \"pool-reg-cert\": $(jq -c . "${pool_regcert_file}") }" <<< ${offlineJSON}); then return 1; fi
- if ! offlineJSON=$(jq ". += { txFee: \"$(( min_fee + stakePoolDeposit ))\" }" <<< ${offlineJSON}); then return 1; fi
+ if ! offlineJSON=$(jq ". += { txFee: \"$(( min_fee + POOL_DEPOSIT ))\" }" <<< ${offlineJSON}); then return 1; fi
if ! offlineJSON=$(jq ". += { txBody: $(jq -c . "${TMP_DIR}"/tx.raw) }" <<< ${offlineJSON}); then return 1; fi
if ! offlineJSON=$(jq ". += { \"signing-file\": [] }" <<< ${offlineJSON}); then return 1; fi
for index in "${!owner_wallets[@]}"; do
@@ -1715,8 +2120,10 @@ registerPool() {
# Description : Register pool with pledge on chain
modifyPool() {
- getBaseAddress ${owner_wallets[0]}
- getBalance ${base_addr}
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ utxo_cnt=${utxos_cnt[${base_addr}]}
+ tx_in=${tx_in_arr[${base_addr}]}
+ fi
if ! getTTL; then return 1; fi
@@ -1735,20 +2142,20 @@ modifyPool() {
if ! buildTx; then return 1; fi
- calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_count}
+ calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_count} || return 1
- newBalance=$(( ${assets[lovelace]} - min_fee ))
- println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${assets[lovelace]}) - $(formatLovelace ${min_fee}) )"
+ newBalance=$(( base_lovelace - min_fee ))
+ println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${base_lovelace}) - $(formatLovelace ${min_fee}) )"
- if [[ ${assets[lovelace]} -lt ${min_fee} ]]; then
+ if [[ ${base_lovelace} -lt ${min_fee} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Not enough ADA in base address for tx fee!"\
- "Funds in address: ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"\
+ "Funds in address: ${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA"\
"Minimum required: ${FG_LBLUE}$(formatLovelace ${min_fee})${NC} ADA"
return 1
fi
tx_out="${base_addr}+${newBalance}${assets_tx_out}"
- getMinUTxO "${tx_out}"
+ getMinUTxO "${tx_out}" || return 1
if [[ ${newBalance} -lt ${min_utxo_out} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: minimum UTxO value not fulfilled, only ${FG_LBLUE}$(formatLovelace ${newBalance})${NC} ADA left in address after tx fee, at least ${FG_LBLUE}$(formatLovelace ${min_utxo_out})${NC} ADA required!"
return 1
@@ -1828,9 +2235,18 @@ deRegisterPool() {
[[ $(cat "${WALLET_FOLDER}/${wallet_name}/${WALLET_PAY_ADDR_FILENAME}" 2>/dev/null) = "${addr}" ]] && wallet_source="enterprise" || wallet_source="base"
- getBalance ${addr}
if ! getTTL; then return 1; fi
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ for key in ${!assets[@]}; do
+ [[ ${key} != "${addr},"* ]] && unset 'assets[$key]'
+ done
+ utxo_cnt=${utxos_cnt[${addr}]}
+ tx_in=${tx_in_arr[${addr}]}
+ else
+ getBalance ${addr}
+ fi
+
getAssetsTxOut
build_args=(
@@ -1844,20 +2260,20 @@ deRegisterPool() {
if ! buildTx; then return 1; fi
- calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2
+ calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2 || return 1
- newBalance=$(( ${assets[lovelace]} - min_fee ))
- println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${assets[lovelace]}) - $(formatLovelace ${min_fee}) )"
+ newBalance=$(( lovelace - min_fee ))
+ println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${lovelace}) - $(formatLovelace ${min_fee}) )"
- if [[ ${assets[lovelace]} -lt ${min_fee} ]]; then
+ if [[ ${lovelace} -lt ${min_fee} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Not enough ADA in ${wallet_source} address for tx fee!"\
- "Funds in address: ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"\
+ "Funds in address: ${FG_LBLUE}$(formatLovelace ${lovelace})${NC} ADA"\
"Minimum required: ${FG_LBLUE}$(formatLovelace ${min_fee})${NC} ADA"
return 1
fi
tx_out="${addr}+${newBalance}${assets_tx_out}"
- getMinUTxO "${tx_out}"
+ getMinUTxO "${tx_out}" || return 1
if [[ ${newBalance} -lt ${min_utxo_out} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: minimum UTxO value not fulfilled, only ${FG_LBLUE}$(formatLovelace ${newBalance})${NC} ADA left in address after tx fee, at least ${FG_LBLUE}$(formatLovelace ${min_utxo_out})${NC} ADA required!"
return 1
@@ -1934,20 +2350,31 @@ rotatePoolKeys() {
if [[ ! -f ${pool_coldkey_vk_file} ]]; then # lets re-generate it from cold signing key
println ACTION "${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file ${pool_coldkey_sk_file} --verification-key-file ${pool_coldkey_vk_file}"
- ! ${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file "${pool_coldkey_sk_file}" --verification-key-file "${pool_coldkey_vk_file}" && return 1
- output=$(jq '.description = "Stake Pool Operator Verification Key"' "${pool_coldkey_vk_file}") && jq <<< ${output} > "${pool_coldkey_vk_file}"
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file "${pool_coldkey_sk_file}" --verification-key-file "${pool_coldkey_vk_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during cold verification key creation!\n${stdout}"; return 1
+ fi
+ println ACTION "jq '.description = \"Stake Pool Operator Verification Key\"' ${pool_coldkey_vk_file}"
+ if ! stdout=$(jq '.description = "Stake Pool Operator Verification Key"' "${pool_coldkey_vk_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during cold verification key description update!\n${stdout}"; return 1
+ else
+ jq <<< ${stdout} > "${pool_coldkey_vk_file}"
+ fi
fi
current_kes_period=$(getCurrentKESperiod)
echo "${current_kes_period}" > ${pool_saved_kes_start}
println ACTION "${CCLI} ${NETWORK_ERA} node key-gen-KES --verification-key-file ${pool_hotkey_vk_file} --signing-key-file ${pool_hotkey_sk_file}"
- ! ${CCLI} ${NETWORK_ERA} node key-gen-KES --verification-key-file "${pool_hotkey_vk_file}" --signing-key-file "${pool_hotkey_sk_file}" && return 1
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} node key-gen-KES --verification-key-file "${pool_hotkey_vk_file}" --signing-key-file "${pool_hotkey_sk_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during KES key creation!\n${stdout}"; return 1
+ fi
p_opcert=""
if [[ $# -eq 1 ]]; then
println ACTION "${CCLI} ${NETWORK_ERA} node new-counter --cold-verification-key-file ${pool_coldkey_vk_file} --counter-value $1 --operational-certificate-issue-counter-file ${pool_opcert_counter_file}"
- ! ${CCLI} ${NETWORK_ERA} node new-counter --cold-verification-key-file "${pool_coldkey_vk_file}" --counter-value $1 --operational-certificate-issue-counter-file "${pool_opcert_counter_file}" && return 1
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} node new-counter --cold-verification-key-file "${pool_coldkey_vk_file}" --counter-value $1 --operational-certificate-issue-counter-file "${pool_opcert_counter_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during operational certificate counter creation!\n${stdout}"; return 1
+ fi
elif [[ -n ${KOIOS_API} ]]; then
! getPoolID "${pool_name}" && println "ERROR" "\n${FG_RED}ERROR${NC}: failed to get pool ID!\n" && return 1
println ACTION "curl -sSL -f -X POST -H \"Content-Type: application/json\" -d '{\"_pool_bech32_ids\":[\"${pool_id_bech32}\"]}' ${KOIOS_API}/pool_info"
@@ -1958,7 +2385,9 @@ rotatePoolKeys() {
new_counter_nbr=0 # null returned = no block on chain for this pool
fi
println ACTION "${CCLI} ${NETWORK_ERA} node new-counter --cold-verification-key-file ${pool_coldkey_vk_file} --counter-value ${new_counter_nbr} --operational-certificate-issue-counter-file ${pool_opcert_counter_file}"
- ! ${CCLI} ${NETWORK_ERA} node new-counter --cold-verification-key-file "${pool_coldkey_vk_file}" --counter-value ${new_counter_nbr} --operational-certificate-issue-counter-file "${pool_opcert_counter_file}" && return 1
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} node new-counter --cold-verification-key-file "${pool_coldkey_vk_file}" --counter-value ${new_counter_nbr} --operational-certificate-issue-counter-file "${pool_opcert_counter_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during operational certificate counter creation!\n${stdout}"; return 1
+ fi
elif [[ -f ${pool_opcert_file} ]]; then
println ACTION "${CCLI} ${NETWORK_ERA} query kes-period-info --op-cert-file ${pool_opcert_file} ${NETWORK_IDENTIFIER}"
if ! kes_period_info=$(${CCLI} ${NETWORK_ERA} query kes-period-info --op-cert-file "${pool_opcert_file}" ${NETWORK_IDENTIFIER}); then
@@ -1970,7 +2399,9 @@ rotatePoolKeys() {
new_counter_nbr=0 # null returned = no block on chain for this pool
fi
println ACTION "${CCLI} ${NETWORK_ERA} node new-counter --cold-verification-key-file ${pool_coldkey_vk_file} --counter-value ${new_counter_nbr} --operational-certificate-issue-counter-file ${pool_opcert_counter_file}"
- ! ${CCLI} ${NETWORK_ERA} node new-counter --cold-verification-key-file "${pool_coldkey_vk_file}" --counter-value ${new_counter_nbr} --operational-certificate-issue-counter-file "${pool_opcert_counter_file}" && return 1
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} node new-counter --cold-verification-key-file "${pool_coldkey_vk_file}" --counter-value ${new_counter_nbr} --operational-certificate-issue-counter-file "${pool_opcert_counter_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during operational certificate counter creation!\n${stdout}"; return 1
+ fi
else
println "ERROR" "\n${FG_RED}ERROR${NC}: op cert file missing and Koios disabled/unavailable. Unable to get current on-chain counter value!\n" && return 1
fi
@@ -1978,17 +2409,19 @@ rotatePoolKeys() {
if [[ ${needHWCLI} = true ]]; then
if ! unlockHWDevice "issue the opcert"; then return 1; fi
println ACTION "cardano-hw-cli node issue-op-cert --kes-verification-key-file ${pool_hotkey_vk_file} --hw-signing-file ${pool_coldkey_sk_file} --operational-certificate-issue-counter-file ${pool_opcert_counter_file} --kes-period ${current_kes_period} --out-file ${pool_opcert_file}"
- ! cardano-hw-cli node issue-op-cert \
+ if ! stdout=$(cardano-hw-cli node issue-op-cert \
--kes-verification-key-file "${pool_hotkey_vk_file}" \
--hw-signing-file "${pool_coldkey_sk_file}" \
--operational-certificate-issue-counter-file "${pool_opcert_counter_file}" \
--kes-period "${current_kes_period}" \
- --out-file "${pool_opcert_file}" \
- && return 1
-
+ --out-file "${pool_opcert_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during hardware operational certificate creation!\n${stdout}"; return 1
+ fi
else
println ACTION "${CCLI} ${NETWORK_ERA} node issue-op-cert --kes-verification-key-file ${pool_hotkey_vk_file} --cold-signing-key-file ${pool_coldkey_sk_file} --operational-certificate-issue-counter-file ${pool_opcert_counter_file} --kes-period ${current_kes_period} --out-file ${pool_opcert_file}"
- ! ${CCLI} ${NETWORK_ERA} node issue-op-cert --kes-verification-key-file "${pool_hotkey_vk_file}" --cold-signing-key-file "${pool_coldkey_sk_file}" --operational-certificate-issue-counter-file "${pool_opcert_counter_file}" --kes-period "${current_kes_period}" --out-file "${pool_opcert_file}" && return 1
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} node issue-op-cert --kes-verification-key-file "${pool_hotkey_vk_file}" --cold-signing-key-file "${pool_coldkey_sk_file}" --operational-certificate-issue-counter-file "${pool_opcert_counter_file}" --kes-period "${current_kes_period}" --out-file "${pool_opcert_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during operational certificate creation!\n${stdout}"; return 1
+ fi
fi
chmod 700 ${POOL_FOLDER}/${pool_name}/*
@@ -2014,9 +2447,18 @@ sendMetadata() {
return 1
fi
- getBalance ${addr}
if ! getTTL; then return 1; fi
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ for key in ${!assets[@]}; do
+ [[ ${key} != "${addr},"* ]] && unset 'assets[$key]'
+ done
+ utxo_cnt=${utxos_cnt[${addr}]}
+ tx_in=${tx_in_arr[${addr}]}
+ else
+ getBalance ${addr}
+ fi
+
getAssetsTxOut
build_args=(
@@ -2030,20 +2472,20 @@ sendMetadata() {
if ! buildTx; then return 1; fi
- calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 1
+ calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 1 || return 1
- newBalance=$(( ${assets[lovelace]} - min_fee ))
- println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${assets[lovelace]}) - $(formatLovelace ${min_fee}) )"
+ newBalance=$(( lovelace - min_fee ))
+ println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${lovelace}) - $(formatLovelace ${min_fee}) )"
- if [[ ${assets[lovelace]} -lt ${min_fee} ]]; then
+ if [[ ${lovelace} -lt ${min_fee} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Not enough ADA in ${wallet_source} address for tx fee!"\
- "Funds in address: ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"\
+ "Funds in address: ${FG_LBLUE}$(formatLovelace ${lovelace})${NC} ADA"\
"Minimum required: ${FG_LBLUE}$(formatLovelace ${min_fee})${NC} ADA"
return 1
fi
tx_out="${addr}+${newBalance}${assets_tx_out}"
- getMinUTxO "${tx_out}"
+ getMinUTxO "${tx_out}" || return 1
if [[ ${newBalance} -lt ${min_utxo_out} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: minimum UTxO value not fulfilled, only ${FG_LBLUE}$(formatLovelace ${newBalance})${NC} ADA left in address after tx fee, at least ${FG_LBLUE}$(formatLovelace ${min_utxo_out})${NC} ADA required!"
return 1
@@ -2090,7 +2532,18 @@ mintAsset() {
[[ $(cat "${WALLET_FOLDER}/${wallet_name}/${WALLET_PAY_ADDR_FILENAME}" 2>/dev/null) = "${addr}" ]] && wallet_source="enterprise" || wallet_source="base"
- getBalance ${addr}
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ for key in ${!assets[@]}; do
+ [[ ${key} != "${addr},"* ]] && unset 'assets[$key]'
+ done
+ index_prefix="${addr},"
+ utxo_cnt=${utxos_cnt[${addr}]}
+ tx_in=${tx_in_arr[${addr}]}
+ else
+ getBalance ${addr}
+ unset index_prefix
+ fi
+
if [[ ${policy_ttl} -eq 0 ]]; then
if ! getTTL; then return 1; fi
else
@@ -2100,7 +2553,7 @@ mintAsset() {
fi
[[ -z ${asset_name} ]] && asset_name_out="" || asset_name_out=".$(asciiToHex "${asset_name}")"
- getAssetsTxOut "${policy_id}${asset_name_out}" "${assets_to_mint}"
+ getAssetsTxOut "${index_prefix}${policy_id}${asset_name_out}" "${assets_to_mint}"
build_args=(
${tx_in}
@@ -2115,14 +2568,14 @@ mintAsset() {
if ! buildTx; then return 1; fi
- calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2
+ calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2 || return 1
- newBalance=$(( ${assets[lovelace]} - min_fee ))
- println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${assets[lovelace]}) - $(formatLovelace ${min_fee}) )"
+ newBalance=$(( lovelace - min_fee ))
+ println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${lovelace}) - $(formatLovelace ${min_fee}) )"
- if [[ ${assets[lovelace]} -lt ${min_fee} ]]; then
+ if [[ ${lovelace} -lt ${min_fee} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Not enough ADA in ${wallet_source} address for tx fee!"\
- "Funds in address: ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"\
+ "Funds in address: ${FG_LBLUE}$(formatLovelace ${lovelace})${NC} ADA"\
"Minimum required: ${FG_LBLUE}$(formatLovelace ${min_fee})${NC} ADA"
return 1
fi
@@ -2184,7 +2637,18 @@ mintAsset() {
# Description : burn custom assets on specified wallet
burnAsset() {
- getBalance ${addr}
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ for key in ${!assets[@]}; do
+ [[ ${key} != "${addr},"* ]] && unset 'assets[$key]'
+ done
+ index_prefix="${addr},"
+ utxo_cnt=${utxos_cnt[${addr}]}
+ tx_in=${tx_in_arr[${addr}]}
+ else
+ getBalance ${addr}
+ unset index_prefix
+ fi
+
if [[ ${policy_ttl} -eq 0 ]]; then
if ! getTTL; then return 1; fi
else
@@ -2194,7 +2658,7 @@ burnAsset() {
fi
[[ -z ${asset_name} ]] && asset_name_out="" || asset_name_out=".${asset_name}"
- getAssetsTxOut "${policy_id}${asset_name_out}" "-${assets_to_burn}"
+ getAssetsTxOut "${index_prefix}${policy_id}${asset_name_out}" "-${assets_to_burn}"
build_args=(
${tx_in}
@@ -2209,20 +2673,20 @@ burnAsset() {
if ! buildTx; then return 1; fi
- calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2
+ calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2 || return 1
- newBalance=$(( ${assets[lovelace]} - min_fee ))
- println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${assets[lovelace]}) - $(formatLovelace ${min_fee}) )"
+ newBalance=$(( lovelace - min_fee ))
+ println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${lovelace}) - $(formatLovelace ${min_fee}) )"
- if [[ ${assets[lovelace]} -lt ${min_fee} ]]; then
+ if [[ ${lovelace} -lt ${min_fee} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Not enough ADA in ${wallet_source} address for tx fee!"\
- "Funds in address: ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"\
+ "Funds in address: ${FG_LBLUE}$(formatLovelace ${lovelace})${NC} ADA"\
"Minimum required: ${FG_LBLUE}$(formatLovelace ${min_fee})${NC} ADA"
return 1
fi
tx_out="${addr}+${newBalance}${assets_tx_out}"
- getMinUTxO "${tx_out}"
+ getMinUTxO "${tx_out}" || return 1
if [[ ${newBalance} -lt ${min_utxo_out} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: minimum UTxO value not fulfilled, only ${FG_LBLUE}$(formatLovelace ${newBalance})${NC} ADA left in address after tx fee, at least ${FG_LBLUE}$(formatLovelace ${min_utxo_out})${NC} ADA required!"
return 1
@@ -2280,7 +2744,9 @@ burnAsset() {
# Parameters : build_args > an array with all the arguments to assemble the transaction
buildTx() {
println ACTION "${CCLI} ${NETWORK_ERA} transaction build-raw ${build_args[*]}"
- ${CCLI} ${NETWORK_ERA} transaction build-raw "${build_args[@]}"
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} transaction build-raw "${build_args[@]}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during transaction building!\n${stdout}"; return 1
+ fi
}
# Command : calcMinFee [rax tx file]
@@ -2302,7 +2768,10 @@ calcMinFee() {
--protocol-params-file "${TMP_DIR}"/protparams.json
)
println ACTION "${CCLI} ${min_fee_args[*]}"
- min_fee=$([[ "$(${CCLI} ${min_fee_args[*]})" =~ ([0-9]+) ]] && echo ${BASH_REMATCH[1]})
+ if ! stdout=$(${CCLI} "${min_fee_args[@]}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during minimum fee calculation!\n${stdout}"; return 1
+ fi
+ min_fee=$([[ ${stdout} =~ ([0-9]+) ]] && echo ${BASH_REMATCH[1]})
println LOG "fee is $(formatLovelace ${min_fee}) ADA"
}
@@ -2351,7 +2820,7 @@ witnessTx() {
--out-file "${tx_witness}"
)
println ACTION "${witness_command[@]}"
- if ! "${witness_command[@]}"; then println ERROR "\n${FG_RED}ERROR${NC}: during transaction signing !!" && return 1; fi
+ if ! stdout=$("${witness_command[@]}" 2>&1); then println ERROR "\n${FG_RED}ERROR${NC}: during transaction signing !!\n${stdout}" && return 1; fi
fi
tx_witness_files+=( "${tx_witness}" )
done
@@ -2360,7 +2829,7 @@ witnessTx() {
if [[ ${isHW} = 'Y' ]]; then
if ! unlockHWDevice "witness the transaction"; then return 1; fi
println ACTION "${hw_witness_command[@]}"
- if ! "${hw_witness_command[@]}"; then println ERROR "\n${FG_RED}ERROR${NC}: during hardware wallet signing !!" && return 1; fi
+ if ! stdout=$("${hw_witness_command[@]}" 2>&1); then println ERROR "\n${FG_RED}ERROR${NC}: during hardware wallet signing !!\n${stdout}" && return 1; fi
fi
}
@@ -2387,7 +2856,7 @@ assembleTx() {
--out-file "${tx_signed}"
)
println ACTION "${sign_command[@]}"
- "${sign_command[@]}"
+ if ! stdout=$("${sign_command[@]}" 2>&1); then println ERROR "\n${FG_RED}ERROR${NC}: during hardware wallet signing !!\n${stdout}" && return 1; fi
else
println ERROR "\n${FG_RED}ERROR${NC}: no witness files provided, unable to assemble tx!"
return 1
@@ -2399,21 +2868,88 @@ assembleTx() {
# Parameters : signed tx file > the signed transaction file to submit
submitTx() {
tx_signed="$1"
+ answer=0
+ while true; do
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
+ submitTxNode ${tx_signed} && break
+ else
+ submitTxKoiosOgmios ${tx_signed} && break
+ fi
+ tput sc
+ println DEBUG "\nRetry transaction submit?"
+ select_opt "[y] Yes" "[n] No"
+ answer=$?
+ tput rc && tput ed
+ case ${answer} in
+ 0) : ;;
+ 1) break ;;
+ esac
+ done
+ return ${answer}
+}
- #if [[ -n ${KOIOS_API} ]]; then
- # txdata="$(mktemp "${TMP_DIR}/tx.signed_XXXXXXXXXX")"
- # xxd -p -r <<< $(jq .cborHex ${tx.signed}) > ${txdata}
- # println ACTION "curl -X POST -H \"Content-Type: application/cbor\" --data-binary @${txdata} \"${KOIOS_API}/submittx\""
- # curl -X POST -H "Content-Type: application/cbor" --data-binary @${txdata} "${KOIOS_API}/submittx"
- #else
- submit_command=(
- ${CCLI} ${NETWORK_ERA} transaction submit
- --tx-file "${tx_signed}"
- ${NETWORK_IDENTIFIER}
- )
- println ACTION "${submit_command[@]}"
- "${submit_command[@]}"
- #fi
+# Command : submitTxNode [signed tx file]
+# Description : Helper function to submit signed transaction file using local node
+# Parameters : signed tx file > the signed transaction file to submit
+submitTxNode() {
+ submit_command=(
+ ${CCLI} ${NETWORK_ERA} transaction submit
+ --tx-file "$1"
+ ${NETWORK_IDENTIFIER}
+ )
+ println ACTION "${submit_command[@]}"
+ if ! stdout=$("${submit_command[@]}" 2>&1); then println ERROR "\n${FG_RED}ERROR${NC}: Transaction submit failed !!\n${stdout}"; return 1; fi
+}
+
+# Command : getTxId [tx file]
+# Description : Helper function to calculate transaction id
+# Parameters : signed tx file > the signed transaction file to submit
+# Info : tx_id set to hash of transaction body
+getTxId() {
+ txid_command=(
+ ${CCLI} transaction txid
+ --tx-file "$1"
+ )
+ println ACTION "${txid_command[@]}"
+ if ! tx_id=$("${txid_command[@]}" 2>&1); then println ERROR "\n${FG_RED}ERROR${NC}: during transaction hashing !!\n${tx_id}" && return 1; fi
+}
+
+# Command : submitTxKoiosSubmitAPI [signed tx file]
+# Description : Helper function to submit signed transaction file using koios submitapi endpoint
+# Parameters : signed tx file > the signed transaction file to submit
+submitTxKoiosSubmitAPI() {
+ getTxId $1 || return $?
+ cborHex=$(jq -er '.cborHex' "$1" 2>/dev/null) || { println ERROR "\n${FG_RED}ERROR${NC}: Invalid tx file format, 'cborHex' missing in: $1"; return 1; }
+ txdata="$(mktemp "${TMP_DIR}/tx.signed_XXXXXXXXXX")"
+ xxd -p -r <<< ${cborHex} > ${txdata}
+ println ACTION "curl -sfSL -X POST -H \"Content-Type: application/cbor\" --data-binary @${txdata} \"${KOIOS_API}/submittx\""
+ if ! stdout=$(curl -sfSL -X POST -H "Content-Type: application/cbor" --data-binary @${txdata} "${KOIOS_API}/submittx" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: Transaction submit failed !!\n${stdout}"; return 1
+ fi
+ println LOG "Submit result: ${stdout}"
+}
+
+# Command : submitTxKoiosOgmios [signed tx file]
+# Description : Helper function to submit signed transaction file using koios submitapi endpoint
+# Parameters : signed tx file > the signed transaction file to submit
+submitTxKoiosOgmios() {
+ getTxId $1 || return $?
+ cborHex=$(jq -er '.cborHex' "$1" 2>/dev/null) || { println ERROR "\n${FG_RED}ERROR${NC}: Invalid tx file format, 'cborHex' missing in: $1"; return 1; }
+ jsonrpc=$(jq -n -c --arg cbor "${cborHex}" '{jsonrpc: "2.0", method: "submitTransaction", params: {transaction: {cbor: $cbor}}}')
+ unset ogmios_error
+ println ACTION "curl -sSL -X POST -H \"accept: application/json\" -H \"Content-Type: application/json\" -d \"${jsonrpc}\" \"${KOIOS_API}/ogmios/\""
+ stdout=$(curl -sSL -X POST -H "accept: application/json" -H "Content-Type: application/json" -d "${jsonrpc}" "${KOIOS_API}/ogmios/" 2>&1)
+ if [[ -z ${stdout} ]] || ogmios_error=$(jq -er '.error //empty' <<< "${stdout}") || ! jq -er '.result //empty' <<< "${stdout}" &>/dev/null; then
+ println ERROR "\n${FG_RED}ERROR${NC}: Transaction submit failed !!"
+ if [[ -n ${ogmios_error} ]]; then
+ jq -r . <<< "${ogmios_error}"
+ println LOG $(jq -rc . <<< "${ogmios_error}")
+ else
+ println ERROR "Submit API error: ${stdout}"
+ fi
+ return 1
+ fi
+ ogmios_res=$(jq -erc '.result' <<< "${stdout}") && println LOG "Submit result: ${ogmios_res}"
}
# Command : transformRawTx [raw tx file]
@@ -2423,26 +2959,32 @@ transformRawTx() {
tx_raw="$1"
tx_raw_tmp="$(mktemp "${TMP_DIR}/tx.raw_XXXXXXXXXX")"
println ACTION "cardano-hw-cli transaction transform --tx-file ${tx_raw} --out-file ${tx_raw_tmp}"
- if ! cardano-hw-cli transaction transform --tx-file "${tx_raw}" --out-file "${tx_raw_tmp}" >/dev/null; then return 1; fi
+ if ! stdout=$(cardano-hw-cli transaction transform --tx-file "${tx_raw}" --out-file "${tx_raw_tmp}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: Transaction transform failed !!\n${stdout}"; return 1
+ fi
println ACTION "mv ${tx_raw_tmp} ${tx_raw}"
- if ! mv "${tx_raw_tmp}" "${tx_raw}" >/dev/null; then return 1; fi
+ if ! stdout=$(mv "${tx_raw_tmp}" "${tx_raw}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: Transaction transform failure moving temporary file to ${tx_raw} !!\n${stdout}"; return 1
+ fi
}
# Command : unlockHWDevice [action]
# Description : Directions to unlock and open HW device
# Parameters : action > message for action to be taken
unlockHWDevice() {
- if ! HWCLIversionCheck; then waitForInput && return 1; fi
- waitForInput "${FG_BLUE}INFO${NC}: please connect and unlock hardware device" "\n ${FG_YELLOW}Ledger${NC} - Unlock with pin and open Cardano app" "\n ${FG_YELLOW}Trezor${NC} - Make sure trezor bridge is installed (https://wallet.trezor.io/#/bridge) " "\n\nwhen done, press any key to continue"
+ if ! HWCLIversionCheck; then waitToProceed && return 1; fi
+ waitToProceed "${FG_BLUE}INFO${NC}: please connect and unlock hardware device" "\n ${FG_YELLOW}Ledger${NC} - Unlock with pin and open Cardano app" "\n ${FG_YELLOW}Trezor${NC} - Make sure trezor bridge is installed (https://wallet.trezor.io/#/bridge) " "\n\nwhen done, press any key to continue"
println ACTION "cardano-hw-cli device version"
- device_app="$(cardano-hw-cli device version)"
+ if ! device_app=$(cardano-hw-cli device version 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: accessing hardware device failed !!\n${device_app}"; return 1
+ fi
device_app_vendor="$(cut -d' ' -f1 <<< "${device_app}")"
device_app_version="$(cut -d' ' -f4 <<< "${device_app}")"
println LOG "hardware device: vendor=${device_app_vendor} version=${device_app_version}"
if [[ ! ${device_app_version} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
println ERROR "${FG_RED}ERROR${NC}: unable to identify connected hardware device, is the device plugged in and unlocked?"
println ERROR "Make sure device is seen by OS using tools like lsusb etc and is working correctly"
- waitForInput && return 1
+ waitToProceed && return 1
elif [[ ${device_app_vendor} = Ledger ]]; then
if ! versionCheck "5.0.1" "${device_app_version}"; then
println ERROR "${FG_RED}ERROR${NC}: Cardano app version installed on Ledger is ${FG_LGRAY}v${device_app_version}${NC}, minimum required app version is ${FG_GREEN}v5.0.1${NC} !!"
@@ -2587,9 +3129,20 @@ submitPoll() {
[[ $(cat "${WALLET_FOLDER}/${wallet_name}/${WALLET_PAY_ADDR_FILENAME}" 2>/dev/null) = "${addr}" ]] && wallet_source="enterprise" || wallet_source="base"
POOL_ID_HASH=$(cat ${POOL_FOLDER}/${pool_name}/${POOL_ID_FILENAME})
- getBalance ${addr}
+ if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ for key in ${!assets[@]}; do
+ [[ ${key} != "${addr},"* ]] && unset 'assets[$key]'
+ done
+ utxo_cnt=${utxos_cnt[${addr}]}
+ tx_in=${tx_in_arr[${addr}]}
+ else
+ getBalance ${addr}
+ fi
+
if ! getTTL; then return 1; fi
+
getAssetsTxOut
+
metafile_param="--metadata-cbor-file ${cborFile}"
if [[ -n ${metafile} && -f ${metafile} ]]; then
metafile_param+=" --json-metadata-no-schema --metadata-json-file ${metafile}"
@@ -2607,20 +3160,20 @@ submitPoll() {
if ! buildTx; then return 1; fi
- calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2
+ calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 2 || return 1
- newBalance=$(( ${assets[lovelace]} - min_fee ))
- println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${assets[lovelace]}) - $(formatLovelace ${min_fee}) )"
+ newBalance=$(( lovelace - min_fee ))
+ println LOG "Balance left to be returned in used UTxO is $(formatLovelace ${newBalance}) ADA ( $(formatLovelace ${lovelace}) - $(formatLovelace ${min_fee}) )"
- if [[ ${assets[lovelace]} -lt ${min_fee} ]]; then
+ if [[ ${lovelace} -lt ${min_fee} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Not enough ADA in ${wallet_source} address for tx fee!"\
- "Funds in address: ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"\
+ "Funds in address: ${FG_LBLUE}$(formatLovelace ${lovelace})${NC} ADA"\
"Minimum required: ${FG_LBLUE}$(formatLovelace ${min_fee})${NC} ADA"
return 1
fi
tx_out="${addr}+${newBalance}${assets_tx_out}"
- getMinUTxO "${tx_out}"
+ getMinUTxO "${tx_out}" || return 1
if [[ ${newBalance} -lt ${min_utxo_out} ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: minimum UTxO value not fulfilled, only ${FG_LBLUE}$(formatLovelace ${newBalance})${NC} ADA left in address after tx fee, at least ${FG_LBLUE}$(formatLovelace ${min_utxo_out})${NC} ADA required!"
return 1
@@ -2679,7 +3232,7 @@ submitPoll() {
if ! assembleTx "${TMP_DIR}/tx.raw"; then return 1; fi
if ! submitTx "${tx_signed}"; then return 1; fi
println "Poll ${FG_GREEN}${poll_txId}${NC} ballot casted to the network"
- waitForInput && continue
+ waitToProceed && continue
esac
}
diff --git a/scripts/cnode-helper-scripts/cntools.sh b/scripts/cnode-helper-scripts/cntools.sh
index 3bcb8cdce..77b121aaa 100755
--- a/scripts/cnode-helper-scripts/cntools.sh
+++ b/scripts/cnode-helper-scripts/cntools.sh
@@ -1,17 +1,6 @@
#!/usr/bin/env bash
# shellcheck disable=SC1090,SC2086,SC2154,SC2034,SC2012,SC2140,SC2028,SC1091
-. "$(dirname $0)"/env offline
-
-# legacy config (deprecated and removed in future major version update)
-if [[ -f "$(dirname $0)"/cntools.config ]]; then
- ! . "$(dirname $0)"/cntools.config && exit 1
- clear && waitToProceed "${FG_RED}cntools.config deprecated and will be removed in future major version!${NC}\n"\
- "Uncomment and set any customization in User Variables section of cntools.sh instead."\
- "Once done, delete cntools.config file to get rid of this message.\n"\
- "press any key to proceed .."
-fi
-
######################################
# User Variables - Change as desired #
# Common variables set in env file #
@@ -50,6 +39,9 @@ fi
# Price fetching currency. Disable by setting value 'off' [off|usd|eur|...] (default: off) (https://api.coingecko.com/api/v3/simple/supported_vs_currencies)
#CURRENCY=usd
+# Runtime mode, offline | local | light (default local)
+# CNTOOLS_MODE=local
+
######################################
# Do NOT modify code below #
######################################
@@ -59,9 +51,6 @@ fi
# General exit handler
cleanup() {
sleep 0.1
- if { true >&6; } 2<> /dev/null; then
- exec 1>&6 2>&7 3>&- 6>&- 7>&- 8>&- 9>&- # Restore stdout/stderr and close tmp file descriptors
- fi
[[ -n $1 ]] && err=$1 || err=$?
[[ $err -eq 0 ]] && clear
[[ -n ${exit_msg} ]] && echo -e "\n${exit_msg}\n" || echo -e "\nCNTools terminated, cleaning up...\n"
@@ -86,7 +75,9 @@ usage() {
Usage: $(basename "$0") [-o] [-a] [-b ] [-v]
Koios CNTools - The Cardano SPOs best friend
- -o Activate offline mode - run CNTools in offline mode without node access, a limited set of functions available
+ -n Local mode - run CNTools in local node mode (default)
+ -l Light mode - run CNTools using Koios query layer for full functionallity without a local node
+ -o Offline mode - run CNTools with a limited set of functionallity without external communication useful for air-gapped mode
-a Enable advanced/developer features like metadata transactions, multi-asset management etc (not needed for SPO usage)
-u Skip script update check overriding UPDATE_CHECK value in env
-b Run CNTools and look for updates on alternate branch instead of master (only for testing/development purposes)
@@ -95,16 +86,19 @@ usage() {
EOF
}
-CNTOOLS_MODE="CONNECTED"
ADVANCED_MODE="false"
SKIP_UPDATE=N
PRINT_VERSION="false"
PARENT="$(dirname $0)"
[[ -f "${PARENT}"/.env_branch ]] && BRANCH="$(cat "${PARENT}"/.env_branch)" || BRANCH="master"
-while getopts :oaub:v opt; do
+# save launch params
+arg_copy=("$@")
+
+while getopts :olaub:v opt; do
case ${opt} in
o ) CNTOOLS_MODE="OFFLINE" ;;
+ l ) CNTOOLS_MODE="LIGHT" ;;
a ) ADVANCED_MODE="true" ;;
u ) SKIP_UPDATE=Y ;;
b ) echo "${OPTARG}" > "${PARENT}"/.env_branch ;;
@@ -125,20 +119,28 @@ if [[ ! -f "${PARENT}"/env ]]; then
myExit 1
fi
-# Source env file, re-sourced later
-if [[ "${CNTOOLS_MODE}" == "OFFLINE" ]]; then
- . "${PARENT}"/env offline &>/dev/null
+# Source env file in normal mode with node connection, else offline mode
+if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
+ . "${PARENT}"/env || myExit 1
else
- . "${PARENT}"/env &>/dev/null
+ . "${PARENT}"/env offline || myExit 1
fi
# Source cntools.library to populate defaults for CNTools
-! . "${PARENT}"/cntools.library && myExit 1
+. "${PARENT}"/cntools.library || myExit 1
+
+# If light mode, test if koios is reachable, otherwise - unset KOIOS_API
+if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then
+ test_koios
+ [[ -z ${KOIOS_API} ]] && myExit 1 "ERROR: Koios query test failed, unable to launch CNTools in light mode utilizing Koios query layer\n\n${launch_modes_info}"
+fi
+
+[[ ${CNTOOLS_MODE} != "LIGHT" ]] && unset KOIOS_API
[[ ${PRINT_VERSION} = "true" ]] && myExit 0 "CNTools v${CNTOOLS_VERSION} (branch: $([[ -f "${PARENT}"/.env_branch ]] && cat "${PARENT}"/.env_branch || echo "master"))"
-# Do some checks when run in connected mode
-if [[ ${CNTOOLS_MODE} = "CONNECTED" ]]; then
+# Do some checks when run in connected(local|light) mode
+if [[ ${CNTOOLS_MODE} != "OFFLINE" ]]; then
# check to see if there are any updates available
clear
if [[ ${UPDATE_CHECK} = Y && ${SKIP_UPDATE} != Y ]]; then
@@ -159,11 +161,14 @@ if [[ ${CNTOOLS_MODE} = "CONNECTED" ]]; then
esac
# source common env variables in case it was updated
- . "${PARENT}"/env
- case $? in
- 1) myExit 1 "ERROR: CNTools failed to load common env file\nPlease verify set values in 'User Variables' section in env file or log an issue on GitHub" ;;
- 2) clear ;;
- esac
+ if [[ ${ENV_UPDATED} = Y ]]; then
+ [[ ${CNTOOLS_MODE} = "LOCAL" ]] && . "${PARENT}"/env || . "${PARENT}"/env offline
+ case $? in
+ 1) myExit 1 "ERROR: CNTools failed to load common env file\nPlease verify set values in 'User Variables' section in env file or log an issue on GitHub" ;;
+ 2) clear ;;
+ esac
+ [[ ${CNTOOLS_MODE} != "LIGHT" ]] && unset KOIOS_API
+ fi
# check for cntools update
checkUpdate "${PARENT}"/cntools.library "${ENV_UPDATED}" Y N
@@ -173,7 +178,7 @@ if [[ ${CNTOOLS_MODE} = "CONNECTED" ]]; then
echo -e "\n${FG_RED}ERROR${NC}: Update check of cntools.sh against GitHub failed!"
waitToProceed
fi
- $0 "$@" "-u"; myExit 0 ;; # re-launch script with same args skipping update check
+ $0 "${arg_copy[@]}" "-u"; myExit 1 ;; # re-launch script with same args skipping update check
2) echo -e "\n${FG_RED}ERROR${NC}: Update check of cntools.library against GitHub failed!"
waitToProceed ;;
esac
@@ -182,8 +187,7 @@ if [[ ${CNTOOLS_MODE} = "CONNECTED" ]]; then
if curl -s -f -m ${CURL_TIMEOUT} -o "${TMP_DIR}"/cntools-changelog.md "${URL_DOCS}/cntools-changelog.md"; then
if ! cmp -s "${TMP_DIR}"/cntools-changelog.md "${PARENT}/cntools-changelog.md"; then
# Latest changes not shown, show whats new and copy changelog
- clear
- sleep 0.1
+ clear
if [[ ! -f "${PARENT}/cntools-changelog.md" ]]; then
# special case for first installation or 5.0.0 upgrade, print release notes until previous major version
echo -e "~ CNTools - What's New ~\n\n" "$(sed -n "/\[${CNTOOLS_MAJOR_VERSION}\.${CNTOOLS_MINOR_VERSION}\.${CNTOOLS_PATCH_VERSION}\]/,/\[$((CNTOOLS_MAJOR_VERSION-1))\.[0-9]\.[0-9]\]/p" "${TMP_DIR}"/cntools-changelog.md | head -n -2)" | less -X
@@ -199,19 +203,8 @@ if [[ ${CNTOOLS_MODE} = "CONNECTED" ]]; then
waitToProceed
fi
fi
-
- # Validate protocol parameters
- if grep -q "Network.Socket.connect" <<< "${PROT_PARAMS}"; then
- myExit 1 "${FG_YELLOW}WARN${NC}: node socket path wrongly configured or node not running, please verify that socket set in env file match what is used to run the node\n\n${FG_BLUE}INFO${NC}: re-run CNTools in offline mode with -o parameter if you want to access CNTools with limited functionality"
- elif [[ -z "${PROT_PARAMS}" ]] || ! jq -er . <<< "${PROT_PARAMS}" &>/dev/null; then
- myExit 1 "${FG_YELLOW}WARN${NC}: failed to query protocol parameters, ensure your node is running with correct genesis (the node needs to be in sync to 1 epoch after the hardfork)\n\nError message: ${PROT_PARAMS}\n\n${FG_BLUE}INFO${NC}: re-run CNTools in offline mode with -o parameter if you want to access CNTools with limited functionality"
- fi
- echo "${PROT_PARAMS}" > "${TMP_DIR}"/protparams.json
fi
-# Test if koios is reachable , otherwise - unset KOIOS_API
-test_koios
-
archiveLog # archive current log and cleanup log archive folder
# check for required command line tools
@@ -230,14 +223,6 @@ if ! versionCheck "4.4.0" "${BASH_REMATCH[1]}"; then
myExit 1 "BASH does not meet the minimum required version of ${FG_LBLUE}4.4.0${NC}, found ${FG_LBLUE}${BASH_REMATCH[1]}${NC}\n\nPlease upgrade to a newer Linux distribution or compile latest BASH following official docs.\n\nINSTALL: https://www.gnu.org/software/bash/manual/html_node/Installing-Bash.html\nDOWNLOAD: http://git.savannah.gnu.org/cgit/bash.git/ (latest stable TAG)"
fi
-exec 6>&1 # Link file descriptor #6 with normal stdout.
-exec 7>&2 # Link file descriptor #7 with normal stderr.
-[[ -n ${CNTOOLS_LOG} ]] && exec > >( tee >( while read -r line; do logln "INFO" "${line}"; done ) )
-[[ -n ${CNTOOLS_LOG} ]] && exec 2> >( tee >( while read -r line; do logln "ERROR" "${line}"; done ) >&2 )
-[[ -n ${CNTOOLS_LOG} ]] && exec 3> >( tee >( while read -r line; do logln "DEBUG" "${line}"; done ) >&6 )
-exec 8>&1 # Link file descriptor #8 with custom stdout.
-exec 9>&2 # Link file descriptor #9 with custom stderr.
-
# check if there are pools in need of KES key rotation
clear
kes_rotation_needed="no"
@@ -245,10 +230,10 @@ if [[ ${CHECK_KES} = true ]]; then
while IFS= read -r -d '' pool; do
unset pool_kes_start
- [[ ${CNTOOLS_MODE} = "CONNECTED" ]] && getNodeMetrics
+ [[ ${CNTOOLS_MODE} = "LOCAL" ]] && getNodeMetrics
[[ (-z ${remaining_kes_periods} || ${remaining_kes_periods} -eq 0) && -f "${pool}/${POOL_CURRENT_KES_START}" ]] && unset remaining_kes_periods && pool_kes_start="$(cat "${pool}/${POOL_CURRENT_KES_START}")"
- if ! kesExpiration ${pool_kes_start}; then println ERROR "${FG_RED}ERROR${NC}: failure during KES calculation for ${FG_GREEN}$(basename ${pool})${NC}" && waitForInput && continue; fi
+ if ! kesExpiration ${pool_kes_start}; then println ERROR "${FG_RED}ERROR${NC}: failure during KES calculation for ${FG_GREEN}$(basename ${pool})${NC}" && waitToProceed && continue; fi
if [[ ${expiration_time_sec_diff} -lt ${KES_ALERT_PERIOD} ]]; then
kes_rotation_needed="yes"
@@ -266,7 +251,7 @@ if [[ ${CHECK_KES} = true ]]; then
println DEBUG "Time left : ${FG_YELLOW}$(timeLeft ${expiration_time_sec_diff})${NC}"
fi
done < <(find "${POOL_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z)
- [[ ${kes_rotation_needed} = "yes" ]] && waitForInput
+ [[ ${kes_rotation_needed} = "yes" ]] && waitToProceed
fi
@@ -284,14 +269,14 @@ function main {
find "${TMP_DIR:?}" -type f -not \( -name 'protparams.json' -o -name '.dialogrc' -o -name "offline_tx*" -o -name "*_cntools_backup*" -o -name "metadata_*" -o -name "asset*" \) -delete
unset IFS
clear
- [[ ${CNTOOLS_MODE} != "OFFLINE" ]] && getNodeMetrics && getPriceInfo
- println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- if [[ ${CNTOOLS_MODE} = "CONNECTED" ]]; then
- println "$(printf " >> Koios CNTools v%s - %s - ${FG_GREEN}%s${NC} <<" "${CNTOOLS_VERSION}" "${NETWORK_NAME}" "${CNTOOLS_MODE}")"
- else
- println "$(printf " >> Koios CNTools v%s - %s - ${FG_LBLUE}%s${NC} <<" "${CNTOOLS_VERSION}" "${NETWORK_NAME}" "${CNTOOLS_MODE}")"
+ if [[ ${CNTOOLS_MODE} != "OFFLINE" ]]; then
+ [[ ${CNTOOLS_MODE} = "LOCAL" ]] && getNodeMetrics
+ getPriceInfo
+ updateProtocolParams
fi
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+ println "$(printf " >> Koios CNTools v%s - %s - ${CNTOOLS_MODE_COLOR}%s${NC} <<" "${CNTOOLS_VERSION}" "${NETWORK_NAME}" "${CNTOOLS_MODE}")"
+ println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println OFF " Main Menu Telegram Announcement / Support channel: ${FG_YELLOW}t.me/CardanoKoios/9759${NC}\n"\
" ) Wallet - create, show, remove and protect wallets"\
" ) Funds - send, withdraw and delegate"\
@@ -303,7 +288,7 @@ function main {
" ) Refresh - reload home screen content"\
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println DEBUG "$(printf "%84s" "Epoch $(getEpoch) - $(timeLeft "$(timeUntilNextEpoch)") until next")"
- if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
+ if [[ ${CNTOOLS_MODE} != "LOCAL" ]]; then
println DEBUG " What would you like to do?"
else
tip_diff=$(( $(getSlotTipRef) - slotnum ))
@@ -378,17 +363,17 @@ function main {
println " >> WALLET >> NEW"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo
- getAnswerAnyCust wallet_name "Name of new wallet" wallet_name
+ getAnswerAnyCust wallet_name "Name of new wallet"
# Remove unwanted characters from wallet name
wallet_name=${wallet_name//[^[:alnum:]]/_}
if [[ -z "${wallet_name}" ]]; then
println ERROR "${FG_RED}ERROR${NC}: Empty wallet name, please retry!"
- waitForInput && continue
+ waitToProceed && continue
fi
echo
if ! mkdir -p "${WALLET_FOLDER}/${wallet_name}"; then
println ERROR "${FG_RED}ERROR${NC}: Failed to create directory for wallet:\n${WALLET_FOLDER}/${wallet_name}"
- waitForInput && continue
+ waitToProceed && continue
fi
# Wallet key filenames
payment_sk_file="${WALLET_FOLDER}/${wallet_name}/${WALLET_PAY_SK_FILENAME}"
@@ -398,27 +383,28 @@ function main {
if [[ $(find "${WALLET_FOLDER}/${wallet_name}" -type f -print0 | wc -c) -gt 0 ]]; then
println "${FG_RED}WARN${NC}: A wallet ${FG_GREEN}$wallet_name${NC} already exists"
println " Choose another name or delete the existing one"
- waitForInput && continue
+ waitToProceed && continue
fi
println ACTION "${CCLI} ${NETWORK_ERA} address key-gen --verification-key-file ${payment_vk_file} --signing-key-file ${payment_sk_file}"
- if ! ${CCLI} ${NETWORK_ERA} address key-gen --verification-key-file "${payment_vk_file}" --signing-key-file "${payment_sk_file}"; then
- println ERROR "\n${FG_RED}ERROR${NC}: failure during payment key creation!"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitForInput && continue
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} address key-gen --verification-key-file "${payment_vk_file}" --signing-key-file "${payment_sk_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during payment key creation!\n${stdout}"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitToProceed && continue
fi
println ACTION "${CCLI} ${NETWORK_ERA} stake-address key-gen --verification-key-file ${stake_vk_file} --signing-key-file ${stake_sk_file}"
- if ! ${CCLI} ${NETWORK_ERA} stake-address key-gen --verification-key-file "${stake_vk_file}" --signing-key-file "${stake_sk_file}"; then
- println ERROR "\n${FG_RED}ERROR${NC}: failure during stake key creation!"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitForInput && continue
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} stake-address key-gen --verification-key-file "${stake_vk_file}" --signing-key-file "${stake_sk_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during stake key creation!\n${stdout}"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitToProceed && continue
fi
chmod 600 "${WALLET_FOLDER}/${wallet_name}/"*
getBaseAddress ${wallet_name}
getPayAddress ${wallet_name}
getRewardAddress ${wallet_name}
+ getCredentials ${wallet_name}
println "New Wallet : ${FG_GREEN}${wallet_name}${NC}"
println "Address : ${FG_LGRAY}${base_addr}${NC}"
println "Enterprise Address : ${FG_LGRAY}${pay_addr}${NC}"
println DEBUG "\nYou can now send and receive ADA using the above addresses."
println DEBUG "Note that Enterprise Address will not take part in staking."
println DEBUG "Wallet will be automatically registered on chain if you\nchoose to delegate or pledge wallet when registering a stake pool."
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
import)
while true; do # Wallet >> Import loop
@@ -449,24 +435,24 @@ function main {
! cmdAvailable "cardano-address" &>/dev/null; then
println ERROR "${FG_RED}ERROR${NC}: bech32 and/or cardano-address not found in '\$PATH'"
println ERROR "Please run updated guild-deploy.sh and re-build/re-download cardano-node"
- waitForInput && continue
+ waitToProceed && continue
fi
getAnswerAnyCust wallet_name "Name of imported wallet"
# Remove unwanted characters from wallet name
wallet_name=${wallet_name//[^[:alnum:]]/_}
if [[ -z "${wallet_name}" ]]; then
println ERROR "${FG_RED}ERROR${NC}: Empty wallet name, please retry!"
- waitForInput && continue
+ waitToProceed && continue
fi
echo
if ! mkdir -p "${WALLET_FOLDER}/${wallet_name}"; then
println ERROR "${FG_RED}ERROR${NC}: Failed to create directory for wallet:\n${WALLET_FOLDER}/${wallet_name}"
- waitForInput && continue
+ waitToProceed && continue
fi
if [[ $(find "${WALLET_FOLDER}/${wallet_name}" -type f -print0 | wc -c) -gt 0 ]]; then
println "${FG_RED}WARN${NC}: A wallet ${FG_GREEN}$wallet_name${NC} already exists"
println " Choose another name or delete the existing one"
- waitForInput && continue
+ waitToProceed && continue
fi
getAnswerAnyCust mnemonic false "24 or 15 word mnemonic(space separated)"
echo
@@ -475,7 +461,7 @@ function main {
println ERROR "${FG_RED}ERROR${NC}: 24 or 15 words expected, found ${FG_RED}${#words[@]}${NC}"
echo && safeDel "${WALLET_FOLDER}/${wallet_name}"
unset mnemonic; unset words
- waitForInput && continue
+ waitToProceed && continue
fi
payment_sk_file="${WALLET_FOLDER}/${wallet_name}/${WALLET_PAY_SK_FILENAME}"
payment_vk_file="${WALLET_FOLDER}/${wallet_name}/${WALLET_PAY_VK_FILENAME}"
@@ -486,7 +472,7 @@ function main {
if ! root_prv=$(cardano-address key from-recovery-phrase Shelley <<< ${mnemonic}); then
echo && safeDel "${WALLET_FOLDER}/${wallet_name}"
unset mnemonic; unset words
- waitForInput && continue
+ waitToProceed && continue
fi
unset mnemonic; unset words
payment_xprv=$(cardano-address key child 1852H/1815H/0H/0/0 <<< ${root_prv})
@@ -518,31 +504,32 @@ function main {
}
EOF
println ACTION "${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file ${payment_sk_file} --verification-key-file ${TMP_DIR}/payment.evkey"
- if ! ${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file "${payment_sk_file}" --verification-key-file "${TMP_DIR}/payment.evkey"; then
- println ERROR "\n${FG_RED}ERROR${NC}: failure during payment signing key extraction!"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitForInput && continue
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file "${payment_sk_file}" --verification-key-file "${TMP_DIR}/payment.evkey"2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during payment signing key extraction!\n${stdout}"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitToProceed && continue
fi
println ACTION "${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file ${stake_sk_file} --verification-key-file ${TMP_DIR}/stake.evkey"
- if ! ${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file "${stake_sk_file}" --verification-key-file "${TMP_DIR}/stake.evkey"; then
- println ERROR "\n${FG_RED}ERROR${NC}: failure during stake signing key extraction!"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitForInput && continue
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file "${stake_sk_file}" --verification-key-file "${TMP_DIR}/stake.evkey"2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during stake signing key extraction!\n${stdout}"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitToProceed && continue
fi
println ACTION "${CCLI} ${NETWORK_ERA} key non-extended-key --extended-verification-key-file ${TMP_DIR}/payment.evkey --verification-key-file ${payment_vk_file}"
- if ! ${CCLI} ${NETWORK_ERA} key non-extended-key --extended-verification-key-file "${TMP_DIR}/payment.evkey" --verification-key-file "${payment_vk_file}"; then
- println ERROR "\n${FG_RED}ERROR${NC}: failure during payment verification key extraction!"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitForInput && continue
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} key non-extended-key --extended-verification-key-file "${TMP_DIR}/payment.evkey" --verification-key-file "${payment_vk_file}"2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during payment verification key extraction!\n${stdout}"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitToProceed && continue
fi
println ACTION "${CCLI} ${NETWORK_ERA} key non-extended-key --extended-verification-key-file ${TMP_DIR}/stake.evkey --verification-key-file ${stake_vk_file}"
- if ! ${CCLI} ${NETWORK_ERA} key non-extended-key --extended-verification-key-file "${TMP_DIR}/stake.evkey" --verification-key-file "${stake_vk_file}"; then
- println ERROR "\n${FG_RED}ERROR${NC}: failure during stake verification key extraction!"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitForInput && continue
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} key non-extended-key --extended-verification-key-file "${TMP_DIR}/stake.evkey" --verification-key-file "${stake_vk_file}"2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during stake verification key extraction!\n${stdout}"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitToProceed && continue
fi
chmod 600 "${WALLET_FOLDER}/${wallet_name}/"*
getBaseAddress ${wallet_name}
getPayAddress ${wallet_name}
getRewardAddress ${wallet_name}
+ getCredentials ${wallet_name}
if [[ ${base_addr} != "${base_addr_candidate}" ]]; then
println ERROR "${FG_RED}ERROR${NC}: base address generated doesn't match base address candidate."
println ERROR "base_addr[${FG_LGRAY}${base_addr}${NC}]\n!=\nbase_addr_candidate[${FG_LGRAY}${base_addr_candidate}${NC}]"
println ERROR "Create a GitHub issue and include log file from failed CNTools session."
echo && safeDel "${WALLET_FOLDER}/${wallet_name}"
- waitForInput && continue
+ waitToProceed && continue
fi
echo
println "Wallet Imported : ${FG_GREEN}${wallet_name}${NC}"
@@ -566,7 +553,7 @@ function main {
echo
println DEBUG "Please read more about HD wallets at:"
println DEBUG "https://cardano-community.github.io/support-faq/wallets?id=heirarchical-deterministic-hd-wallets"
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
hardware)
@@ -580,34 +567,34 @@ function main {
select_opt "[y] Yes" "[n] No"
case $? in
0) : ;; # do nothing
- 1) waitForInput "Unsupported hardware wallet, press any key to return home" && continue ;;
+ 1) waitToProceed "Unsupported hardware wallet, press any key to return home" && continue ;;
esac
echo
if ! cmdAvailable "cardano-hw-cli" &>/dev/null; then
println ERROR "${FG_RED}ERROR${NC}: cardano-hw-cli executable not found in path!"
println ERROR "Please run '${FG_YELLOW}guild-deploy.sh -s w${NC}' to add hardware wallet support and install Vaccumlabs cardano-hw-cli, '${FG_YELLOW}guild-deploy.sh -h${NC}' shows all available options"
- waitForInput && continue
+ waitToProceed && continue
fi
if [[ ! -x $(command -v cardano-hw-cli) ]]; then
println ERROR "${FG_RED}ERROR${NC}: cardano-hw-cli binary doesn't have execution persmission, please fix!"
- waitForInput && continue
+ waitToProceed && continue
fi
- if ! HWCLIversionCheck; then waitForInput && continue; fi
+ if ! HWCLIversionCheck; then waitToProceed && continue; fi
getAnswerAnyCust wallet_name "Name of imported wallet"
# Remove unwanted characters from wallet name
wallet_name=${wallet_name//[^[:alnum:]]/_}
if [[ -z "${wallet_name}" ]]; then
println ERROR "${FG_RED}ERROR${NC}: Empty wallet name, please retry!"
- waitForInput && continue
+ waitToProceed && continue
fi
if ! mkdir -p "${WALLET_FOLDER}/${wallet_name}"; then
println ERROR "${FG_RED}ERROR${NC}: Failed to create directory for wallet:\n${WALLET_FOLDER}/${wallet_name}"
- waitForInput && continue
+ waitToProceed && continue
fi
if [[ $(find "${WALLET_FOLDER}/${wallet_name}" -type f -print0 | wc -c) -gt 0 ]]; then
println "${FG_RED}WARN${NC}: A wallet ${FG_GREEN}$wallet_name${NC} already exists"
println " Choose another name or delete the existing one"
- waitForInput && continue
+ waitToProceed && continue
fi
payment_sk_file="${WALLET_FOLDER}/${wallet_name}/${WALLET_HW_PAY_SK_FILENAME}"
payment_vk_file="${WALLET_FOLDER}/${wallet_name}/${WALLET_PAY_VK_FILENAME}"
@@ -615,14 +602,14 @@ function main {
stake_vk_file="${WALLET_FOLDER}/${wallet_name}/${WALLET_STAKE_VK_FILENAME}"
if ! unlockHWDevice "extract ${FG_LGRAY}payment keys${NC}"; then safeDel "${WALLET_FOLDER}/${wallet_name}"; continue; fi
println ACTION "cardano-hw-cli address key-gen --path 1852H/1815H/0H/0/0 --verification-key-file ${payment_vk_file} --hw-signing-file ${payment_sk_file}"
- if ! cardano-hw-cli address key-gen --path 1852H/1815H/0H/0/0 --verification-key-file "${payment_vk_file}" --hw-signing-file "${payment_sk_file}"; then
- println ERROR "\n${FG_RED}ERROR${NC}: failure during payment key extraction!"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitForInput && continue
+ if ! stdout=$(cardano-hw-cli address key-gen --path 1852H/1815H/0H/0/0 --verification-key-file "${payment_vk_file}" --hw-signing-file "${payment_sk_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during payment key extraction!\n${stdout}"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitToProceed && continue
fi
jq '.description = "Payment Hardware Verification Key"' "${payment_vk_file}" > "${TMP_DIR}/$(basename "${payment_vk_file}").tmp" && mv -f "${TMP_DIR}/$(basename "${payment_vk_file}").tmp" "${payment_vk_file}"
println DEBUG "${FG_BLUE}INFO${NC}: repeat and follow instructions on hardware device to extract the ${FG_LGRAY}stake keys${NC}"
println ACTION "cardano-hw-cli address key-gen --path 1852H/1815H/0H/2/0 --verification-key-file ${stake_vk_file} --hw-signing-file ${stake_sk_file}"
- if ! cardano-hw-cli address key-gen --path 1852H/1815H/0H/2/0 --verification-key-file "${stake_vk_file}" --hw-signing-file "${stake_sk_file}"; then
- println ERROR "\n${FG_RED}ERROR${NC}: failure during stake key extraction!"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitForInput && continue
+ if ! stdout=$(cardano-hw-cli address key-gen --path 1852H/1815H/0H/2/0 --verification-key-file "${stake_vk_file}" --hw-signing-file "${stake_sk_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during stake key extraction!\n${stdout}"; safeDel "${WALLET_FOLDER}/${wallet_name}"; waitToProceed && continue
fi
jq '.description = "Stake Hardware Verification Key"' "${stake_vk_file}" > "${TMP_DIR}/$(basename "${stake_vk_file}").tmp" && mv -f "${TMP_DIR}/$(basename "${stake_vk_file}").tmp" "${stake_vk_file}"
getBaseAddress ${wallet_name}
@@ -648,7 +635,7 @@ function main {
println DEBUG " ${FG_LGRAY}>${NC} If restored wallet contain funds since before, send all ADA through Daedalus/Yoroi to address shown in CNTools"
println DEBUG " ${FG_LGRAY}>${NC} Only use the address shown in CNTools to receive funds"
println DEBUG " ${FG_LGRAY}>${NC} Only spend ADA from CNTools, if spent through Daedalus/Yoroi balance seen in CNTools wont match"
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
esac # wallet >> import sub OPERATION
done # Wallet >> Import loop
@@ -658,10 +645,10 @@ function main {
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> WALLET >> REGISTER"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println ERROR "${FG_RED}ERROR${NC}: CNTools started in offline mode, option not available!"
- waitForInput && continue
+ waitToProceed && continue
else
if ! selectOpMode; then continue; fi
fi
@@ -670,49 +657,47 @@ function main {
if [[ ${op_mode} = "online" ]]; then
selectWallet "non-reg" "${WALLET_PAY_VK_FILENAME}" "${WALLET_STAKE_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitForInput && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitToProceed && continue ;;
esac
else
selectWallet "non-reg" "${WALLET_PAY_VK_FILENAME}" "${WALLET_STAKE_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
fi
- getBaseAddress ${wallet_name}
- getBalance ${base_addr}
- if [[ ${assets[lovelace]} -gt 0 ]]; then
+ getWalletBalance ${wallet_name} true true false true
+ if [[ ${base_lovelace} -gt 0 ]]; then
if [[ -n ${wallet_count} && ${wallet_count} -gt ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
- println DEBUG "$(printf "%s\t${FG_LBLUE}%s${NC} ADA" "Funds in wallet:" "$(formatLovelace ${assets[lovelace]})")"
+ println DEBUG "$(printf "%s\t${FG_LBLUE}%s${NC} ADA" "Funds in wallet:" "$(formatLovelace ${base_lovelace})")"
fi
else
println ERROR "\n${FG_RED}ERROR${NC}: no funds available in base address for wallet ${FG_GREEN}${wallet_name}${NC}"
- stakeAddressDeposit=$(jq -r '.stakeAddressDeposit' <<< "${PROT_PARAMS}")
- println DEBUG "Funds for key deposit($(formatLovelace ${stakeAddressDeposit}) ADA) + transaction fee needed to register the wallet"
- waitForInput && continue
+ println DEBUG "Funds for key deposit($(formatLovelace ${KEY_DEPOSIT}) ADA) + transaction fee needed to register the wallet"
+ waitToProceed && continue
fi
if ! registerStakeWallet ${wallet_name} "true"; then
- waitForInput && continue
+ waitToProceed && continue
fi
println "\n${FG_GREEN}${wallet_name}${NC} successfully registered on chain!"
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
deregister)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> WALLET >> DE-REGISTER"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println ERROR "${FG_RED}ERROR${NC}: CNTools started in offline mode, option not available!"
- waitForInput && continue
+ waitToProceed && continue
else
if ! selectOpMode; then continue; fi
fi
@@ -721,44 +706,43 @@ function main {
if [[ ${op_mode} = "online" ]]; then
selectWallet "reg" "${WALLET_PAY_VK_FILENAME}" "${WALLET_STAKE_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitForInput && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitToProceed && continue ;;
esac
else
selectWallet "reg" "${WALLET_PAY_VK_FILENAME}" "${WALLET_STAKE_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
fi
- getRewards ${wallet_name}
+ getWalletRewards ${wallet_name}
if [[ "${reward_lovelace}" -gt 0 ]]; then
println "\n${FG_YELLOW}WARN${NC}: wallet has unclaimed rewards, please use 'Funds >> Withdraw Rewards' before de-registration to claim your rewards"
- waitForInput && continue
+ waitToProceed && continue
fi
- getBaseAddress ${wallet_name}
- getBalance ${base_addr}
- if [[ ${assets[lovelace]} -le 0 ]]; then
+ getWalletBalance ${wallet_name} true true false true
+ if [[ ${base_lovelace} -le 0 ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: no funds available in base address for wallet ${FG_GREEN}${wallet_name}${NC}"
println ERROR "Funds for transaction fee needed to deregister the wallet"
- waitForInput && continue
+ waitToProceed && continue
fi
if ! deregisterStakeWallet; then
[[ -f ${stake_dereg_file} ]] && rm -f ${stake_dereg_file}
- waitForInput && continue
+ waitToProceed && continue
fi
echo
- if ! verifyTx ${base_addr}; then waitForInput && continue; fi
+ if ! verifyTx ${base_addr}; then waitToProceed && continue; fi
echo
println "${FG_GREEN}${wallet_name}${NC} successfully de-registered from chain!"
- println "Key deposit fee that will be refunded : ${FG_LBLUE}$(formatLovelace ${stakeAddressDeposit})${NC} ADA"
- waitForInput && continue
+ println "Key deposit fee that will be refunded : ${FG_LBLUE}$(formatLovelace ${KEY_DEPOSIT})${NC} ADA"
+ waitToProceed && continue
;; ###################################################################
list)
clear
@@ -766,15 +750,42 @@ function main {
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> WALLET >> LIST"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println DEBUG "${FG_LGRAY}OFFLINE MODE${NC}: CNTools started in offline mode, wallet balance not shown!"
fi
+ if [[ -n ${KOIOS_API} ]]; then
+ tput sc
+ println OFF "\n${FG_YELLOW}> Querying Koios API for wallet information${NC}"
+ addr_list=()
+ reward_addr_list=()
+ while IFS= read -r -d '' wallet; do
+ wallet_name=$(basename ${wallet})
+ getBaseAddress ${wallet_name}
+ [[ -n ${base_addr} ]] && addr_list+=(${base_addr})
+ getPayAddress ${wallet_name}
+ [[ -n ${pay_addr} ]] && addr_list+=(${pay_addr})
+ getRewardAddress ${wallet_name}
+ [[ -n ${reward_addr} ]] && reward_addr_list+=(${reward_addr})
+ done < <(find "${WALLET_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0)
+ [[ ${#addr_list[@]} -gt 0 ]] && getBalanceKoios
+ [[ ${#reward_addr_list[@]} -gt 0 ]] && getRewardInfoKoios
+ tput rc && tput ed
+ fi
+
while IFS= read -r -d '' wallet; do
wallet_name=$(basename ${wallet})
enc_files=$(find "${wallet}" -mindepth 1 -maxdepth 1 -type f -name '*.gpg' -print0 | wc -c)
- if [[ ${CNTOOLS_MODE} = "CONNECTED" ]] && isWalletRegistered ${wallet_name}; then registered="yes"; else registered="no"; fi
+ if [[ ${CNTOOLS_MODE} != "OFFLINE" ]] && isWalletRegistered ${wallet_name}; then registered="yes"; else registered="no"; fi
echo
+ if [[ ${registered} = "yes" ]]; then
+ postfix="- ${FG_LBLUE}REGISTERED${NC}"
+ else
+ postfix="- ${FG_LGRAY}UNREGISTERED${NC}"
+ fi
+ getWalletType ${wallet_name}
+ [[ $? -eq 5 ]] && postfix="${postfix} (${FG_LGRAY}multi-sig${NC})"
+ [[ ${enc_files} -gt 0 ]] && postfix="${postfix} (${FG_YELLOW}encrypted${NC})"
if [[ ${enc_files} -gt 0 && ${registered} = "yes" ]]; then
println "${FG_GREEN}${wallet_name}${NC} - ${FG_LGRAY}REGISTERED${NC} (${FG_YELLOW}encrypted${NC})"
elif [[ ${registered} = "yes" ]]; then
@@ -786,46 +797,93 @@ function main {
fi
getBaseAddress ${wallet_name}
getPayAddress ${wallet_name}
- if [[ -z ${base_addr} && -z ${pay_addr} ]]; then
- println ERROR "${FG_RED}ERROR${NC}: wallet missing pay/base addr files or vkey files to generate them!"
+ getPayScriptAddress ${wallet_name}
+ if [[ -z ${base_addr} && -z ${pay_addr} && -z ${pay_script_addr} ]]; then
+ println ERROR "${FG_RED}ERROR${NC}: wallet missing pay/base/script addr files or vkey/script files to generate them!"
continue
fi
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
- [[ -n ${base_addr} ]] && println "$(printf "%-15s : ${FG_LGRAY}%s${NC}" "Address" "${base_addr}")"
- [[ -n ${pay_addr} ]] && println "$(printf "%-15s : ${FG_LGRAY}%s${NC}" "Enterprise Addr" "${pay_addr}")"
+ [[ -n ${base_addr} ]] && println "$(printf "%-15s : ${FG_LGRAY}%s${NC}" "Address" "${base_addr}")"
+ [[ -n ${pay_addr} ]] && println "$(printf "%-15s : ${FG_LGRAY}%s${NC}" "Enterprise Addr" "${pay_addr}")"
+ [[ -n ${pay_script_addr} ]] && println "$(printf "%-15s : ${FG_LGRAY}%s${NC}" "Script Addr" "${pay_script_addr}")"
else
if [[ -n ${base_addr} ]]; then
- getBalance ${base_addr}
- getPriceString ${assets[lovelace]}
+ lovelace=0
+ asset_cnt=0
+ if [[ -n ${KOIOS_API} ]]; then
+ for key in "${!assets[@]}"; do
+ [[ ${key} = "${base_addr},lovelace" ]] && lovelace=${assets["${base_addr},lovelace"]} && continue
+ [[ ${key} = "${base_addr},"* ]] && ((asset_cnt++))
+ done
+ else
+ getBalance ${base_addr}
+ lovelace=${assets[lovelace]}
+ asset_cnt=$(( ${#assets[@]} - 1 ))
+ fi
+ getPriceString ${lovelace}
println "$(printf "%-19s : ${FG_LGRAY}%s${NC}" "Address" "${base_addr}")"
- if [[ ${#assets[@]} -eq 1 ]]; then
- println "$(printf "%-19s : ${FG_LBLUE}%s${NC} ADA${price_str}" "Funds" "$(formatLovelace ${assets[lovelace]})")"
+ if [[ ${asset_cnt} -eq 0 ]]; then
+ println "$(printf "%-19s : ${FG_LBLUE}%s${NC} ADA${price_str}" "Funds" "$(formatLovelace ${lovelace})")"
else
- println "$(printf "%-19s : ${FG_LBLUE}%s${NC} ADA${price_str} - ${FG_LBLUE}%s${NC} additional asset(s) on address! [WALLET >> SHOW for details]" "Funds" "$(formatLovelace ${assets[lovelace]})" "$(( ${#assets[@]} - 1 ))")"
+ println "$(printf "%-19s : ${FG_LBLUE}%s${NC} ADA${price_str} - ${FG_LBLUE}%s${NC} additional asset(s) on address! [WALLET >> SHOW for details]" "Funds" "$(formatLovelace ${lovelace})" "${asset_cnt}")"
fi
fi
if [[ -n ${pay_addr} ]]; then
- getBalance ${pay_addr}
- getPriceString ${assets[lovelace]}
- if [[ ${assets[lovelace]} -gt 0 ]]; then
+ lovelace=0
+ asset_cnt=0
+ if [[ -n ${KOIOS_API} ]]; then
+ for key in "${!assets[@]}"; do
+ [[ ${key} = "${pay_addr},lovelace" ]] && lovelace=${assets["${pay_addr},lovelace"]} && continue
+ [[ ${key} = "${pay_addr},"* ]] && ((asset_cnt++))
+ done
+ else
+ getBalance ${pay_addr}
+ lovelace=${assets[lovelace]}
+ asset_cnt=$(( ${#assets[@]} - 1 ))
+ fi
+ getPriceString ${lovelace}
+ if [[ ${lovelace} -gt 0 ]]; then
println "$(printf "%-19s : ${FG_LGRAY}%s${NC}" "Enterprise Address" "${pay_addr}")"
- if [[ ${#assets[@]} -eq 1 ]]; then
- println "$(printf "%-19s : ${FG_LBLUE}%s${NC} ADA${price_str}" "Enterprise Funds" "$(formatLovelace ${assets[lovelace]})")"
+ if [[ ${asset_cnt} -eq 0 ]]; then
+ println "$(printf "%-19s : ${FG_LBLUE}%s${NC} ADA${price_str}" "Enterprise Funds" "$(formatLovelace ${lovelace})")"
else
- println "$(printf "%-19s : ${FG_LBLUE}%s${NC} ADA${price_str} - ${FG_LBLUE}%s${NC} additional asset(s) on address! [WALLET >> SHOW for details]" "Enterprise Funds" "$(formatLovelace ${assets[lovelace]})" "$(( ${#assets[@]} - 1 ))")"
+ println "$(printf "%-19s : ${FG_LBLUE}%s${NC} ADA${price_str} - ${FG_LBLUE}%s${NC} additional asset(s) on address! [WALLET >> SHOW for details]" "Enterprise Funds" "$(formatLovelace ${lovelace})" "${asset_cnt}")"
fi
fi
fi
- if [[ -z ${base_addr} && -z ${pay_addr} ]]; then
- println "${FG_RED}Not a supported wallet${NC} - genesis address?"
- println "Use an external script to send funds to a CNTools compatible wallet"
- continue
+ if [[ -n ${pay_script_addr} ]]; then
+ lovelace=0
+ asset_cnt=0
+ if [[ -n ${KOIOS_API} ]]; then
+ for key in "${!assets[@]}"; do
+ [[ ${key} = "${pay_script_addr},lovelace" ]] && lovelace=${assets["${pay_script_addr},lovelace"]} && continue
+ [[ ${key} = "${pay_script_addr},"* ]] && ((asset_cnt++))
+ done
+ else
+ getBalance ${pay_script_addr}
+ lovelace=${assets[lovelace]}
+ asset_cnt=$(( ${#assets[@]} - 1 ))
+ fi
+ getPriceString ${lovelace}
+ if [[ ${lovelace} -gt 0 ]]; then
+ println "$(printf "%-19s : ${FG_LGRAY}%s${NC}" "Script Address" "${pay_script_addr}")"
+ if [[ ${asset_cnt} -eq 0 ]]; then
+ println "$(printf "%-19s : ${FG_LBLUE}%s${NC} ADA${price_str}" "Script Funds" "$(formatLovelace ${lovelace})")"
+ else
+ println "$(printf "%-19s : ${FG_LBLUE}%s${NC} ADA${price_str} - ${FG_LBLUE}%s${NC} additional asset(s) on address! [WALLET >> SHOW for details]" "Script Funds" "$(formatLovelace ${lovelace})" "${asset_cnt}")"
+ fi
+ fi
+ fi
+ if [[ -n ${KOIOS_API} ]]; then
+ [[ -v rewards_available[${reward_addr}] ]] && reward_lovelace=${rewards_available[${reward_addr}]} || reward_lovelace=0
+ delegation_pool_id=${reward_pool[${reward_addr}]}
+ else
+ getWalletRewards ${wallet_name}
+ delegation_pool_id=$(jq -r '.[0].delegation // empty' <<< "${stake_address_info}")
fi
- getRewards ${wallet_name}
- if [[ "${reward_lovelace}" -ge 0 ]]; then
+ if [[ ${reward_lovelace} -gt 0 ]]; then
getPriceString ${reward_lovelace}
println "$(printf "%-19s : ${FG_LBLUE}%s${NC} ADA${price_str}" "Rewards" "$(formatLovelace ${reward_lovelace})")"
- delegation_pool_id=$(jq -r '.[0].delegation // empty' <<< "${stake_address_info}")
if [[ -n ${delegation_pool_id} ]]; then
unset poolName
while IFS= read -r -d '' pool; do
@@ -839,7 +897,7 @@ function main {
fi
fi
done < <(find "${WALLET_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z)
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
show)
clear
@@ -847,14 +905,14 @@ function main {
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> WALLET >> SHOW"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println DEBUG "${FG_LGRAY}OFFLINE MODE${NC}: CNTools started in offline mode, limited wallet info shown!"
fi
tput sc
selectWallet "none"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
tput rc && tput ed
@@ -866,127 +924,123 @@ function main {
fi
getBaseAddress ${wallet_name}
getPayAddress ${wallet_name}
- if [[ -z ${base_addr} && -z ${pay_addr} ]]; then
- println ERROR "\n${FG_RED}ERROR${NC}: wallet missing pay/base addr files or vkey files to generate them!"
- waitForInput && continue
+ getPayScriptAddress ${wallet_name}
+ if [[ -z ${base_addr} && -z ${pay_addr} && -z ${pay_script_addr} ]]; then
+ println ERROR "\n${FG_RED}ERROR${NC}: wallet missing pay/base/script addr files or vkey/script files to generate them!"
+ waitToProceed && continue
fi
+ getCredentials ${wallet_name}
getRewardAddress ${wallet_name}
- base_lovelace=0
- pay_lovelace=0
- declare -A token_data=()
- declare -A token_name=()
- declare -A assets_total=()
- if [[ ${CNTOOLS_MODE} = "CONNECTED" ]]; then
- # Token Metadata API URLs
- case ${NWMAGIC} in
- 764824073) token_meta_server="https://tokens.cardano.org/metadata/" ;; # mainnet
- *) token_meta_server="https://metadata.cardano-testnet.iohkdev.io/metadata/" ;; # other test networks
- esac
- for i in {1..2}; do
- if [[ $i -eq 1 ]]; then
+ if [[ -n ${KOIOS_API} ]]; then
+ tput sc
+ println OFF "\n${FG_YELLOW}> Querying Koios API for wallet information${NC}"
+ addr_list=()
+ [[ -n ${base_addr} ]] && addr_list+=("${base_addr}")
+ [[ -n ${pay_addr} ]] && addr_list+=("${pay_addr}")
+ [[ -n ${pay_script_addr} ]] && addr_list+=("${pay_script_addr}")
+ reward_addr_list=("${reward_addr}")
+ [[ ${#addr_list[@]} -gt 0 ]] && getBalanceKoios
+ [[ ${#reward_addr_list[@]} -gt 0 ]] && getRewardInfoKoios
+ tput rc && tput ed
+ fi
+ total_lovelace=0
+ if [[ ${CNTOOLS_MODE} != "OFFLINE" ]]; then
+ for i in {1..3}; do
+ if [[ $i -eq 1 ]]; then
+ [[ -z ${base_addr} ]] && continue
address_type="Base"
- getBalance ${base_addr}
- base_lovelace=${assets[lovelace]}
+ address=${base_addr}
+ if [[ -n ${KOIOS_API} ]]; then
+ base_lovelace=${assets["${base_addr},lovelace"]}
+ else
+ getBalance ${base_addr}
+ base_lovelace=${assets[lovelace]}
+ fi
total_lovelace=$((total_lovelace + base_lovelace))
- else
+ elif [[ $i -eq 2 ]]; then
+ [[ -z ${pay_addr} ]] && continue
address_type="Enterprise"
- getBalance ${pay_addr}
- pay_lovelace=${assets[lovelace]}
+ address=${pay_addr}
+ if [[ -n ${KOIOS_API} ]]; then
+ pay_lovelace=${assets["${pay_addr},lovelace"]}
+ [[ ${utxos_cnt["${pay_addr}"]:-0} -eq 0 ]] && continue # Dont print Enterprise if empty
+ else
+ getBalance ${pay_addr}
+ pay_lovelace=${assets[lovelace]}
+ [[ ${utxo_cnt} -eq 0 ]] && continue # Dont print Enterprise if empty
+ fi
total_lovelace=$((total_lovelace + pay_lovelace))
- fi
- [[ $i -eq 2 && ${utxo_cnt} -eq 0 ]] && continue # Dont print Enterprise if empty
-
- # loop all assets to query metadata register for token data
- for asset in "${!assets[@]}"; do
- assets_total[${asset}]=$(( assets_total[asset] + assets[asset] ))
- [[ ${asset} = "lovelace" ]] && continue
- IFS='.' read -ra asset_arr <<< "${asset}"
- [[ ${#asset_arr[@]} -eq 1 ]] && asset_name="" || asset_name="${asset_arr[1]}"
- tsubject="${asset_arr[0]}${asset_name}"
- if tdata=$(curl -sL -f -m ${CURL_TIMEOUT} ${token_meta_server}${tsubject}); then
- token_data[${asset}]="${tdata}"
- if tticker=$(jq -er .ticker.value <<< "${tdata}" 2>/dev/null); then token_name[${asset}]="${tticker}"
- elif tname=$(jq -er .name.value <<< "${tdata}" 2>/dev/null); then token_name[${asset}]="${tname}"
- fi
+ else
+ [[ -z ${pay_script_addr} ]] && continue
+ address_type="Script"
+ address=${pay_script_addr}
+ if [[ -n ${KOIOS_API} ]]; then
+ pay_script_lovelace=${assets["${pay_script_addr},lovelace"]}
+ [[ ${utxos_cnt["${pay_script_addr}"]:-0} -eq 0 ]] && continue # Dont print Script if empty
+ else
+ getBalance ${pay_script_addr}
+ pay_script_lovelace=${assets[lovelace]}
+ [[ ${utxo_cnt} -eq 0 ]] && continue # Dont print Script if empty
fi
- done
-
+ total_lovelace=$((total_lovelace + pay_script_lovelace))
+ fi
+
echo
+ if [[ -n ${KOIOS_API} ]]; then
+ utxo_cnt=${utxos_cnt["${address}"]:-0}
+ asset_name_maxlen=${asset_name_maxlen_arr["${address}"]:-5}
+ asset_amount_maxlen=${asset_amount_maxlen_arr["${address}"]:-12}
+ fi
println "${FG_LBLUE}${utxo_cnt} UTxO(s)${NC} found for ${FG_GREEN}${address_type}${NC} Address!"
if [[ ${utxo_cnt} -gt 0 ]]; then
echo
- println DEBUG "$(printf "%-67s ${FG_DGRAY}|${NC} %${asset_name_maxlen}s ${FG_DGRAY}|${NC} %-${asset_amount_maxlen}s\n" "UTxO Hash#Index" "Asset" "Amount")"
- println DEBUG "${FG_DGRAY}$(printf "%68s+%$((asset_name_maxlen+2))s+%$((asset_amount_maxlen+1))s\n" "" "" "" | tr " " "-")${NC}"
+ println DEBUG "$(printf "%-68s ${FG_DGRAY}|${NC} %${asset_name_maxlen}s ${FG_DGRAY}|${NC} %-${asset_amount_maxlen}s\n" "UTxO Hash#Index" "Asset" "Amount")"
+ println DEBUG "${FG_DGRAY}$(printf "%69s+%$((asset_name_maxlen+2))s+%$((asset_amount_maxlen+1))s\n" "" "" "" | tr " " "-")${NC}"
mapfile -d '' utxos_sorted < <(printf '%s\0' "${!utxos[@]}" | sort -z)
for utxo in "${utxos_sorted[@]}"; do
- IFS='.' read -ra utxo_arr <<< "${utxo}"
+ [[ -n ${KOIOS_API} && ${utxo} != "${address},"* ]] && continue
+ IFS='.' read -ra utxo_arr <<< "${utxo#*,}"
if [[ ${#utxo_arr[@]} -eq 2 && ${utxo_arr[1]} = " ADA" ]]; then
- println DEBUG "$(printf "%-67s ${FG_DGRAY}|${NC} ${FG_GREEN}%${asset_name_maxlen}s${NC} ${FG_DGRAY}|${NC} ${FG_LBLUE}%-${asset_amount_maxlen}s${NC}\n" "${utxo_arr[0]}" "ADA" "$(formatLovelace ${utxos["${utxo}"]})")"
+ println DEBUG "$(printf "%-68s ${FG_DGRAY}|${NC} ${FG_GREEN}%${asset_name_maxlen}s${NC} ${FG_DGRAY}|${NC} ${FG_LBLUE}%-${asset_amount_maxlen}s${NC}\n" "${utxo_arr[0]}" "ADA" "$(formatLovelace ${utxos["${utxo}"]})")"
else
[[ ${#utxo_arr[@]} -eq 3 ]] && asset_name="${utxo_arr[2]}" || asset_name=""
- if [[ -n ${token_name[${utxo_arr[1]}.${asset_name}]} ]]; then
- tname="${token_name[${utxo_arr[1]}.${asset_name}]}"
- else
- tname="$(hexToAscii ${asset_name})"
- fi
+ tname="$(hexToAscii ${asset_name})"
+ tname="${tname//[![:print:]]/}"
! assets_id_bech32=$(getAssetIDBech32 ${utxo_arr[1]} ${asset_name}) && continue 3
- println DEBUG "$(printf "${FG_DGRAY}%20s${NC}${FG_LGRAY}%-47s${NC} ${FG_DGRAY}|${NC} ${FG_MAGENTA}%${asset_name_maxlen}s${NC} ${FG_DGRAY}|${NC} ${FG_LBLUE}%-${asset_amount_maxlen}s${NC}\n" "Asset Fingerprint: " "${assets_id_bech32}" "${tname}" "$(formatAsset ${utxos["${utxo}"]})")"
+ println DEBUG "$(printf "${FG_DGRAY}%20s${NC}${FG_LGRAY}%-48s${NC} ${FG_DGRAY}|${NC} ${FG_MAGENTA}%${asset_name_maxlen}s${NC} ${FG_DGRAY}|${NC} ${FG_LBLUE}%-${asset_amount_maxlen}s${NC}\n" "Asset Fingerprint: " "${assets_id_bech32}" "${tname}" "$(formatAsset ${utxos["${utxo}"]})")"
fi
done
fi
- if [[ ${#assets[@]} -gt 0 ]]; then
- println "\nASSET SUMMARY: ${FG_LBLUE}${#assets[@]} Asset-Type(s)${NC} $([[ ${#assets[@]} -gt 1 ]] && echo -e "/ ${FG_LBLUE}${#policyIDs[@]} Unique Policy ID(s)${NC}")\n"
- println DEBUG "$(printf "%${asset_amount_maxlen}s ${FG_DGRAY}|${NC} %-${asset_name_maxlen}s%s\n" "Total Amount" "Asset" "$([[ ${#assets[@]} -gt 1 ]] && echo -e " ${FG_DGRAY}|${NC} Asset Fingerprint")")"
- println DEBUG "${FG_DGRAY}$(printf "%$((asset_amount_maxlen+1))s+%$((asset_name_maxlen+2))s%s\n" "" "" "$([[ ${#assets[@]} -gt 1 ]] && printf "+%57s" "")" | tr " " "-")${NC}"
- println DEBUG "$(printf "${FG_LBLUE}%${asset_amount_maxlen}s${NC} ${FG_DGRAY}|${NC} ${FG_GREEN}%-${asset_name_maxlen}s${NC}%s\n" "$(formatLovelace ${assets[lovelace]})" "ADA" "$([[ ${#assets[@]} -gt 1 ]] && echo -n " ${FG_DGRAY}|${NC}")")"
+ lovelace=0
+ asset_cnt=0
+ if [[ -n ${KOIOS_API} ]]; then
+ for key in "${!assets[@]}"; do
+ [[ ${key} = "${address},lovelace" ]] && lovelace=${assets["${address},lovelace"]}
+ [[ ${key} = "${address},"* ]] && ((asset_cnt++))
+ done
+ else
+ lovelace=${assets[lovelace]}
+ asset_cnt=${#assets[@]}
+ fi
+ if [[ ${asset_cnt} -gt 0 ]]; then
+ println "\nASSET SUMMARY: ${FG_LBLUE}${asset_cnt} Asset-Type(s)${NC}\n"
+ println DEBUG "$(printf "%${asset_amount_maxlen}s ${FG_DGRAY}|${NC} %-${asset_name_maxlen}s%s\n" "Total Amount" "Asset" "$([[ ${asset_cnt} -gt 1 ]] && echo -e " ${FG_DGRAY}|${NC} Asset Fingerprint")")"
+ println DEBUG "${FG_DGRAY}$(printf "%$((asset_amount_maxlen+1))s+%$((asset_name_maxlen+2))s%s\n" "" "" "$([[ ${asset_cnt} -gt 1 ]] && printf "+%57s" "")" | tr " " "-")${NC}"
+ println DEBUG "$(printf "${FG_LBLUE}%${asset_amount_maxlen}s${NC} ${FG_DGRAY}|${NC} ${FG_GREEN}%-${asset_name_maxlen}s${NC}%s\n" "$(formatLovelace ${lovelace})" "ADA" "$([[ ${asset_cnt} -gt 1 ]] && echo -n " ${FG_DGRAY}|${NC}")")"
mapfile -d '' assets_sorted < <(printf '%s\0' "${!assets[@]}" | sort -z)
for asset in "${assets_sorted[@]}"; do
- [[ ${asset} = "lovelace" ]] && continue
- IFS='.' read -ra asset_arr <<< "${asset}"
+ [[ ${asset} = *"lovelace" ]] && continue
+ IFS='.' read -ra asset_arr <<< "${asset#*,}"
[[ ${#asset_arr[@]} -eq 1 ]] && asset_name="" || asset_name="${asset_arr[1]}"
- if [[ -n ${token_name[${asset_arr[0]}.${asset_name}]} ]]; then
- tname="${token_name[${asset_arr[0]}.${asset_name}]}"
- else
- tname="$(hexToAscii ${asset_name})"
- fi
- ! assets_id_bech32=$(getAssetIDBech32 ${asset_arr[0]} ${asset_name}) && continue 2
+ ! assets_id_bech32=$(getAssetIDBech32 ${asset_arr[0]} ${asset_name}) && assets_id_bech32="?"
+ tname="$(hexToAscii ${asset_name})"
+ tname="${tname//[![:print:]]/}"
println DEBUG "$(printf "${FG_LBLUE}%${asset_amount_maxlen}s${NC} ${FG_DGRAY}|${NC} ${FG_MAGENTA}%-${asset_name_maxlen}s${NC} ${FG_DGRAY}|${NC} ${FG_LGRAY}%s${NC}\n" "$(formatAsset ${assets["${asset}"]})" "${tname}" "${assets_id_bech32}")"
done
fi
done
- if [[ ${#assets_total[@]} -gt 1 ]]; then
- echo -e "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" >&6
- println DEBUG "ASSET DETAILS & METADATA\n"
- i=1
- for asset in "${!assets_total[@]}"; do
- [[ ${asset} = "lovelace" ]] && continue
- IFS='.' read -ra asset_arr <<< "${asset}"
- [[ ${#asset_arr[@]} -eq 1 ]] && asset_name="" || asset_name="${asset_arr[1]}"
- ! assets_id_bech32=$(getAssetIDBech32 ${asset_arr[0]} ${asset_name}) && continue 2
- println DEBUG "$(printf "%20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Asset Fingerprint" "${assets_id_bech32}")"
- if [[ -n ${token_data[${asset}]} ]]; then
- if jq -er .ticker.value <<< "${token_data[${asset}]}" &>/dev/null; then MetaNameColor=${FG_LGRAY}; MetaTickerColor=${FG_MAGENTA}; else MetaNameColor=${FG_MAGENTA}; MetaTickerColor=${FG_LGRAY}; fi
- println DEBUG "$(printf "%20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "PolicyID.AssetName" "${asset}")"
- println DEBUG "$(printf "%-21s${FG_DGRAY}%s${NC}" "" ": # METADATA #")"
- println DEBUG " $(printf "%18s ${FG_DGRAY}:${NC} ${MetaNameColor}%s${NC}" "Name" "$(jq -r .name.value <<< "${token_data[${asset}]}")")"
- println DEBUG " $(printf "%18s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Description" "$(jq -r .description.value <<< "${token_data[${asset}]}")")"
- tticker=$(jq -er .ticker.value <<< "${token_data[${asset}]}") && println DEBUG " $(printf "%18s ${FG_DGRAY}:${NC} ${MetaTickerColor}%s${NC}" "Ticker" "${tticker}")"
- turl=$(jq -er .url.value <<< "${token_data[${asset}]}") && println DEBUG " $(printf "%18s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "URL" "${turl}")"
- if tlogo=$(jq -er .logo.value <<< "${token_data[${asset}]}"); then
- base64 --decode <<< "${tlogo}" 2>/dev/null > "${TMP_DIR}/${assets_id_bech32}.png"
- println DEBUG " $(printf "%18s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Logo" "Extracted to: ${TMP_DIR}/${assets_id_bech32}.png")"
- fi
- else
- println DEBUG "$(printf "%20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}$([[ -n ${asset_name} ]] && echo ".")${FG_LGRAY}%s${NC}$([[ -n ${asset_name} ]] && echo " (")${FG_MAGENTA}%s${NC}$([[ -n ${asset_name} ]] && echo ")")" "PolicyID.AssetName" "${asset_arr[0]}" "${asset_name}" "$(hexToAscii ${asset_name})")"
- println DEBUG "$(printf "${FG_DGRAY}%22s${NC} ${FG_YELLOW}%s${NC}" ":" "No metadata registered in Cardano token register for this asset")"
- fi
- ((i++))
- [[ ${#assets_total[@]} -gt $i ]] && println OFF "${FG_DGRAY} -------------------+---------------------------------------------${NC}"
- done
- fi
-
- echo -e "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" >&6
+ println DEBUG "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
if isWalletRegistered ${wallet_name}; then
println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_GREEN}%s${NC}" "Registered" "YES")"
else
@@ -996,23 +1050,59 @@ function main {
println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Registered" "Unknown")"
fi
- [[ -n ${base_addr} ]] && println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Address" "${base_addr}")"
- [[ -n ${pay_addr} ]] && println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Enterprise Address" "${pay_addr}")"
- [[ -n ${reward_addr} ]] && println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Reward/Stake Address" "${reward_addr}")"
- if [[ ${CNTOOLS_MODE} = "CONNECTED" ]]; then
+ getWalletType ${wallet_name}
+ case $? in
+ 0) println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Type" "Hardware")" ;;
+ 1) println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Type" "CLI")" ;;
+ 5) println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Type" "Multi-Sig")" ;;
+ esac
+
+ if [[ -f ${payment_script_file} ]]; then
+ if timelock_after=$(jq -er '.scripts[0].type' "${payment_script_file}") && [[ ${timelock_after} = "after" ]]; then
+ timelock_slot=$(jq -r '.scripts[0].slot' "${payment_script_file}")
+ timelock_date=$(getDateFromSlot ${timelock_slot} '%(%F %T %Z)T')
+ [[ $(getSlotTipRef) -gt ${timelock_slot} ]] && timelock_color="${FG_GREEN}" || timelock_color="${FG_YELLOW}"
+ println "$(printf "%-20s ${FG_DGRAY}:${NC} ${timelock_color}%s${NC}" "Time Locked Until" "${timelock_date}")"
+ fi
+ if atleast=$(jq -er '.scripts[1].type' "${payment_script_file}") && [[ ${atleast} = "atLeast" ]]; then
+ cred_header="Multi-Sig Creds ($(jq -r '.scripts[1].scripts|length' "${payment_script_file}"))"
+ while read -r _sig; do
+ unset wallet_str
+ while IFS= read -r -d '' wallet; do
+ getCredentials "$(basename ${wallet})"
+ if [[ ${pay_cred} = ${_sig} ]]; then
+ wallet_str=" (${FG_GREEN}$(basename ${wallet})${NC})" && break
+ fi
+ done < <(find "${WALLET_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z)
+ println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}%s" "${cred_header}" "${_sig}" "${wallet_str}")"
+ unset cred_header
+ done < <( jq -r '.scripts[1].scripts[].keyHash' "${payment_script_file}")
+ println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Required signers" "$(jq -r '.scripts[1].required' "${payment_script_file}")")"
+ fi
+ fi
+
+ [[ -n ${base_addr} ]] && println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Address" "${base_addr}")"
+ [[ -n ${pay_addr} ]] && println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Enterprise Address" "${pay_addr}")"
+ [[ -n ${pay_script_addr} ]] && println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Script Address" "${pay_script_addr}")"
+ [[ -n ${reward_addr} ]] && println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Reward/Stake Address" "${reward_addr}")"
+ [[ -n ${pay_cred} ]] && println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Payment Credential" "${pay_cred}")"
+ [[ -n ${stake_cred} ]] && println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Stake Credential" "${stake_cred}")"
+
+ if [[ ${CNTOOLS_MODE} != "OFFLINE" ]]; then
if [[ -n ${reward_addr} ]]; then
- getRewardsFromAddr ${reward_addr}
- if [[ "${reward_lovelace}" -ge 0 ]]; then
- total_lovelace=$((total_lovelace + reward_lovelace))
- getPriceString ${reward_lovelace}
- println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LBLUE}%s${NC} ADA${price_str}" "Rewards Available" "$(formatLovelace ${reward_lovelace})")"
+ if [[ -n ${KOIOS_API} ]]; then
+ [[ -v rewards_available[${reward_addr}] ]] && reward_lovelace=${rewards_available[${reward_addr}]} || reward_lovelace=0
+ delegation_pool_id=${reward_pool[${reward_addr}]}
+ else
+ getRewardsFromAddr ${reward_addr}
+ delegation_pool_id=$(jq -r '.[0].delegation // empty' <<< "${stake_address_info}")
fi
+ total_lovelace=$((total_lovelace + reward_lovelace))
+ getPriceString ${reward_lovelace}
+ println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LBLUE}%s${NC} ADA${price_str}" "Rewards Available" "$(formatLovelace ${reward_lovelace})")"
fi
getPriceString ${total_lovelace}
println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LBLUE}%s${NC} ADA${price_str}" "Funds + Rewards" "$(formatLovelace ${total_lovelace})")"
- if [[ -n ${base_addr} ]]; then getAddressInfo "${base_addr}"; else getAddressInfo "${pay_addr}"; fi
- println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Encoding" "$(jq -r '.encoding' <<< ${address_info})")"
- if [[ -n ${reward_addr} ]]; then delegation_pool_id=$(jq -r '.[0].delegation // empty' <<< "${stake_address_info}" 2>/dev/null); else unset delegation_pool_id; fi
if [[ -n ${delegation_pool_id} ]]; then
unset poolName
while IFS= read -r -d '' pool; do
@@ -1025,28 +1115,30 @@ function main {
println "${FG_RED}Delegated${NC} to ${FG_GREEN}${poolName}${NC} ${FG_LGRAY}(${delegation_pool_id})${NC}"
fi
fi
- if [[ -z ${pay_addr} || -z ${base_addr} || -z ${reward_addr} ]]; then
+ if [[ -z ${pay_addr} || -z ${pay_script_addr} || -z ${base_addr} || -z ${reward_addr} ]]; then
echo
- [[ -z ${pay_addr} ]] && println "${FG_YELLOW}INFO${NC}: '${FG_LGRAY}${WALLET_PAY_ADDR_FILENAME}${NC}' missing and '${FG_LGRAY}${WALLET_PAY_VK_FILENAME}${NC}' to generate it!"
+ if [[ -z ${pay_addr} && -z ${pay_script_addr} ]]; then
+ println "${FG_YELLOW}INFO${NC}: '${FG_LGRAY}${WALLET_PAY_ADDR_FILENAME}${NC}' missing and '${FG_LGRAY}${WALLET_PAY_VK_FILENAME}${NC}' to generate it!"
+ fi
[[ -z ${base_addr} ]] && println "${FG_YELLOW}INFO${NC}: '${FG_LGRAY}${WALLET_BASE_ADDR_FILENAME}${NC}' missing and '${FG_LGRAY}${WALLET_PAY_VK_FILENAME}${NC}/${FG_LGRAY}${WALLET_STAKE_VK_FILENAME}${NC}' to generate it!"
[[ -z ${reward_addr} ]] && println "${FG_YELLOW}INFO${NC}: '${FG_LGRAY}${WALLET_STAKE_ADDR_FILENAME}${NC}' missing and '${FG_LGRAY}${WALLET_STAKE_VK_FILENAME}${NC}' to generate it!"
fi
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
remove)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> WALLET >> REMOVE"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println DEBUG "${FG_LGRAY}OFFLINE MODE${NC}: CNTools started in offline mode, unable to verify wallet balance"
fi
echo
println DEBUG "# Select wallet to remove"
- selectWallet "none"
+ selectWallet "balance"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
echo
@@ -1059,7 +1151,7 @@ function main {
1) echo && println "skipped removal process for ${FG_GREEN}$wallet_name${NC}"
;;
esac
- waitForInput && continue
+ waitToProceed && continue
fi
if ! getBaseAddress ${wallet_name} && ! getPayAddress ${wallet_name}; then
println DEBUG "${FG_RED}WARN${NC}: unable to get address for wallet and do a balance check"
@@ -1071,21 +1163,10 @@ function main {
1) echo && println "skipped removal process for ${FG_GREEN}$wallet_name${NC}"
;;
esac
- waitForInput && continue
- fi
- if [[ -n ${base_addr} ]]; then
- getBalance ${base_addr}
- base_lovelace=${assets[lovelace]}
- else
- base_lovelace=0
- fi
- if [[ -n ${pay_addr} ]]; then
- getBalance ${pay_addr}
- pay_lovelace=${assets[lovelace]}
- else
- pay_lovelace=0
+ waitToProceed && continue
fi
- getRewards ${wallet_name}
+ getWalletBalance ${wallet_name}
+ getWalletRewards ${wallet_name}
if [[ ${base_lovelace} -eq 0 && ${pay_lovelace} -eq 0 && ${reward_lovelace} -le 0 ]]; then
println DEBUG "INFO: This wallet appears to be empty"
println DEBUG "${FG_RED}WARN${NC}: Deleting this wallet is final and you can not recover it unless you have a backup\n"
@@ -1113,7 +1194,7 @@ function main {
;;
esac
fi
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
decrypt)
clear
@@ -1121,11 +1202,11 @@ function main {
println " >> WALLET >> DECRYPT"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
println DEBUG "# Select wallet to decrypt"
selectWallet "encrypted"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
filesUnlocked=0
@@ -1143,7 +1224,7 @@ function main {
echo
if ! getPasswordCust; then # $password variable populated by getPasswordCust function
println "\n\n" && println ERROR "${FG_RED}ERROR${NC}: password input aborted!"
- waitForInput && continue
+ waitToProceed && continue
fi
while IFS= read -r -d '' file; do
decryptFile "${file}" "${password}" && \
@@ -1161,7 +1242,7 @@ function main {
println DEBUG "${FG_YELLOW}Wallet files are now unprotected${NC}"
println DEBUG "Use 'WALLET >> ENCRYPT' to re-lock"
fi
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
encrypt)
clear
@@ -1169,11 +1250,11 @@ function main {
println " >> WALLET >> ENCRYPT"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
println DEBUG "# Select wallet to encrypt"
selectWallet "encrypted"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
filesLocked=0
@@ -1184,7 +1265,7 @@ function main {
echo
if ! getPasswordCust confirm; then # $password variable populated by getPasswordCust function
println "\n\n" && println ERROR "${FG_RED}ERROR${NC}: password input aborted!"
- waitForInput && continue
+ waitToProceed && continue
fi
keyFiles=(
"${WALLET_FOLDER}/${wallet_name}/${WALLET_PAY_SK_FILENAME}"
@@ -1201,7 +1282,7 @@ function main {
else
echo
println DEBUG "${FG_YELLOW}NOTE${NC}: found GPG encrypted files in folder, please decrypt/unlock wallet files before encrypting"
- waitForInput && continue
+ waitToProceed && continue
fi
echo
println DEBUG "# Write protecting all wallet keys with 400 permission and if enabled 'chattr +i'"
@@ -1220,7 +1301,7 @@ function main {
println DEBUG "${FG_BLUE}INFO${NC}: wallet files are now protected"
println DEBUG "Use 'WALLET >> DECRYPT' to unlock"
fi
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
esac # wallet sub OPERATION
done # Wallet loop
@@ -1250,10 +1331,10 @@ function main {
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> FUNDS >> SEND"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println ERROR "${FG_RED}ERROR${NC}: CNTools started in offline mode, option not available!"
- waitForInput && continue
+ waitToProceed && continue
else
if ! selectOpMode; then continue; fi
fi
@@ -1264,18 +1345,18 @@ function main {
if [[ ${op_mode} = "online" ]]; then
selectWallet "balance" "${WALLET_PAY_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitForInput && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitToProceed && continue ;;
esac
else
selectWallet "balance" "${WALLET_PAY_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
@@ -1283,12 +1364,7 @@ function main {
s_wallet="${wallet_name}"
s_payment_vk_file="${payment_vk_file}"
s_payment_sk_file="${payment_sk_file}"
- getBaseAddress ${s_wallet}
- getPayAddress ${s_wallet}
- getBalance ${base_addr}
- base_lovelace=${assets[lovelace]}
- getBalance ${pay_addr}
- pay_lovelace=${assets[lovelace]}
+ getWalletBalance ${s_wallet} true true true true
if [[ ${pay_lovelace} -gt 0 && ${base_lovelace} -gt 0 ]]; then
# Both payment and base address available with funds, let user choose what to use
println DEBUG "Select source wallet address"
@@ -1315,7 +1391,7 @@ function main {
fi
else
println ERROR "${FG_RED}ERROR${NC}: no funds available for wallet ${FG_GREEN}${s_wallet}${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
# Destination
@@ -1323,9 +1399,9 @@ function main {
println DEBUG "# Select ${FG_YELLOW}destination${NC} type"
select_opt "[w] Wallet" "[a] Address" "[Esc] Cancel"
case $? in
- 0) selectWallet "balance"
+ 0) selectWallet "cache"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
d_wallet="${wallet_name}"
@@ -1345,10 +1421,10 @@ function main {
d_addr="${pay_addr}"
elif [[ "${base_addr}" = "${s_addr}" || "${pay_addr}" = "${s_addr}" ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: sending to same address as source not supported"
- waitForInput && continue
+ waitToProceed && continue
else
println ERROR "\n${FG_RED}ERROR${NC}: no address found for wallet ${FG_GREEN}${d_wallet}${NC} :("
- waitForInput && continue
+ waitToProceed && continue
fi
;;
1) getAnswerAnyCust d_addr "Address" ;;
@@ -1357,14 +1433,20 @@ function main {
# Destination could be empty, if so without getting a valid address
if [[ -z ${d_addr} ]]; then
println ERROR "${FG_RED}ERROR${NC}: destination address field empty"
- waitForInput && continue
+ waitToProceed && continue
fi
- getBalance ${s_addr}
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
+ getBalance ${s_addr} # need to re-fetch balance if CLI due to possibly being overwritten by payment balance lookup
+ unset index_prefix
+ else
+ index_prefix="${s_addr},"
+ fi
declare -gA assets_left=()
declare -gA assets_to_send=()
for asset in "${!assets[@]}"; do
- assets_left[${asset}]=${assets[${asset}]}
+ [[ -n ${index_prefix} && ${asset} != ${index_prefix}* ]] && continue
+ assets_left[${asset#*,}]=${assets[${asset}]}
done
# Add additional assets to transaction?
@@ -1410,7 +1492,6 @@ function main {
;;
2) continue ;;
esac
- echo
fi
# Amount
@@ -1432,9 +1513,9 @@ function main {
amountADA="${amountADA//,}"
echo
if [[ ${amountADA} != "all" ]]; then
- if ! amount_lovelace=$(ADAToLovelace "${amountADA}"); then waitForInput && continue; fi
- [[ ${amount_lovelace} -gt ${assets[lovelace]} ]] && println ERROR "${FG_RED}ERROR${NC}: not enough funds on address, ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA available but trying to send ${FG_LBLUE}$(formatLovelace ${amount_lovelace})${NC} ADA" && waitForInput && continue
- if [[ ${amount_lovelace} -lt ${assets[lovelace]} ]]; then
+ if ! amount_lovelace=$(ADAToLovelace "${amountADA}"); then waitToProceed && continue; fi
+ [[ ${amount_lovelace} -gt ${assets[${index_prefix}lovelace]} ]] && println ERROR "${FG_RED}ERROR${NC}: not enough funds on address, ${FG_LBLUE}$(formatLovelace ${assets[${index_prefix}lovelace]})${NC} ADA available but trying to send ${FG_LBLUE}$(formatLovelace ${amount_lovelace})${NC} ADA" && waitToProceed && continue
+ if [[ ${amount_lovelace} -lt ${assets[${index_prefix}lovelace]} ]]; then
println DEBUG "Fee payed by sender? [else amount sent is reduced]"
select_opt "[y] Yes" "[n] No" "[Esc] Cancel"
case $? in
@@ -1446,27 +1527,29 @@ function main {
include_fee="yes"
fi
else
- amount_lovelace=${assets[lovelace]}
+ amount_lovelace=${assets[${index_prefix}lovelace]}
println DEBUG "ADA to send set to total supply: ${FG_LBLUE}$(formatLovelace ${amount_lovelace})${NC}"
include_fee="yes"
fi
- echo
-
- if [[ ${amount_lovelace} -eq ${assets[lovelace]} ]]; then
+ if [[ ${amount_lovelace} -eq ${assets[${index_prefix}lovelace]} ]]; then
if [[ ${#assets_left[@]} -gt 1 ]]; then
- println DEBUG "All ADA selected to be sent, automatically add all tokens?"
+ println DEBUG "\nAll ADA selected to be sent, automatically add all tokens?"
select_opt "[y] Yes" "[n] No" "[Esc] Cancel"
case $? in
0) declare -gA assets_left=()
declare -gA assets_to_send=()
for asset in "${!assets[@]}"; do
- assets_to_send[${asset}]=${assets[${asset}]} # add all assets, e.g clone assets array to assets_to_send
+ [[ -n ${index_prefix} && ${asset} != ${index_prefix}* ]] && continue
+ assets_to_send[${asset#*,}]=${assets[${asset}]} # add all assets, e.g clone assets array to assets_to_send
done
;;
- 1) println ERROR "${FG_RED}ERROR${NC}: Unable to send all ADA as there are additional assets left on address not selected to be sent" && waitForInput && continue ;;
+ 1) println ERROR "${FG_RED}ERROR${NC}: Unable to send all ADA as there are additional assets left on address not selected to be sent" && waitToProceed && continue ;;
2) continue ;;
esac
+ else
+ unset assets_left
+ assets_to_send[lovelace]=${amount_lovelace}
fi
else
assets_left[lovelace]=$(( assets_left[lovelace] - amount_lovelace ))
@@ -1482,14 +1565,12 @@ function main {
DEFAULTEDITOR="$(command -v nano &>/dev/null && echo 'nano' || echo 'vi')"
println OFF "\nA maximum of 64 characters(bytes) is allowed per line."
println OFF "${FG_YELLOW}Please don't change default file path when saving.${NC}"
- exec >&6 2>&7 # normal stdout/stderr
- waitForInput "press any key to open '${FG_LGRAY}${DEFAULTEDITOR}${NC}' text editor"
+ waitToProceed "press any key to open '${FG_LGRAY}${DEFAULTEDITOR}${NC}' text editor"
${DEFAULTEDITOR} "${metafile}"
- exec >&8 2>&9 # custom stdout/stderr
if [[ ! -f "${metafile}" ]]; then
println ERROR "${FG_RED}ERROR${NC}: file not found"
println ERROR "File: ${FG_LGRAY}${metafile}${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
tput cuu 4 && tput ed
if [[ ! -s ${metafile} ]]; then
@@ -1511,26 +1592,24 @@ function main {
error="${FG_RED}ERROR${NC}: ${tx_msg}" && break
fi
done < "${metafile}"
- [[ -n ${error} ]] && println ERROR "${error}" && waitForInput && continue
+ [[ -n ${error} ]] && println ERROR "${error}" && waitToProceed && continue
jq -c . <<< "${tx_msg}" > "${metafile}"
- jq -r . "${metafile}" >&3 && echo
+ jq -r . "${metafile}" && echo
println LOG "Transaction message: ${tx_msg}"
fi
;;
esac
if ! sendAssets; then
- waitForInput && continue
+ waitToProceed && continue
fi
echo
- if ! verifyTx ${s_addr}; then waitForInput && continue; fi
- s_balance=${assets[lovelace]}
- getBalance ${d_addr}
- d_balance=${assets[lovelace]}
+ if ! verifyTx ${s_addr}; then waitToProceed && continue; fi
+ s_balance=${assets[${index_prefix}lovelace]}
+ getAddressBalance ${d_addr} true
+ d_balance=${lovelace}
getPayAddress ${s_wallet}
[[ "${pay_addr}" = "${s_addr}" ]] && s_wallet_type=" (Enterprise)" || s_wallet_type=""
- getPayAddress ${d_wallet}
- [[ "${pay_addr}" = "${d_addr}" ]] && d_wallet_type=" (Enterprise)" || d_wallet_type=""
echo
println "Transaction"
println " From : ${FG_GREEN}${s_wallet}${NC}${s_wallet_type}"
@@ -1540,6 +1619,8 @@ function main {
println " ${FG_LBLUE}$(formatAsset ${assets_to_send[${idx}]})${NC} ${FG_LGRAY}${idx}${NC}"
done
if [[ -n "${d_wallet}" ]]; then
+ getPayAddress ${d_wallet}
+ [[ "${pay_addr}" = "${d_addr}" ]] && d_wallet_type=" (Enterprise)" || d_wallet_type=""
println " To : ${FG_GREEN}${d_wallet}${NC}${d_wallet_type}"
else
println " To : ${FG_LGRAY}${d_addr}${NC}"
@@ -1548,17 +1629,17 @@ function main {
println " Balance"
println " - Source : ${FG_LBLUE}$(formatLovelace ${s_balance})${NC} ADA"
println " - Destination : ${FG_LBLUE}$(formatLovelace ${d_balance})${NC} ADA"
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
delegate)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> FUNDS >> DELEGATE"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println ERROR "${FG_RED}ERROR${NC}: CNTools started in offline mode, option not available!"
- waitForInput && continue
+ waitToProceed && continue
else
if ! selectOpMode; then continue; fi
fi
@@ -1567,41 +1648,41 @@ function main {
if [[ ${op_mode} = "online" ]]; then
selectWallet "delegate" "${WALLET_PAY_VK_FILENAME}" "${WALLET_STAKE_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitForInput && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitToProceed && continue ;;
esac
else
selectWallet "delegate" "${WALLET_PAY_VK_FILENAME}" "${WALLET_STAKE_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
fi
- getBaseAddress ${wallet_name}
- getBalance ${base_addr}
- if [[ ${assets[lovelace]} -gt 0 ]]; then
+ getWalletBalance ${wallet_name} true true false true
+ if [[ ${base_lovelace} -gt 0 ]]; then
if [[ -n ${wallet_count} && ${wallet_count} -gt ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
- println DEBUG "$(printf "%s\t${FG_LBLUE}%s${NC} ADA" "Funds in wallet:" "$(formatLovelace ${assets[lovelace]})")"
+ println DEBUG "$(printf "%s\t${FG_LBLUE}%s${NC} ADA" "Funds in wallet:" "$(formatLovelace ${base_lovelace})")"
fi
else
println ERROR "\n${FG_RED}ERROR${NC}: no funds available for wallet ${FG_GREEN}${wallet_name}${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
- getRewards ${wallet_name}
-
+ getWalletRewards ${wallet_name}
if [[ ${reward_lovelace} -eq -1 ]]; then
if [[ ${op_mode} = "online" ]]; then
- if ! registerStakeWallet ${wallet_name}; then waitForInput && continue; fi
+ if ! registerStakeWallet ${wallet_name}; then waitToProceed && continue; fi
+ # re-fetch balance to get a fresh set of utxos
+ getWalletBalance ${wallet_name} true true false true
else
println ERROR "\n${FG_YELLOW}The wallet is not a registered wallet on chain and CNTools run in hybrid mode${NC}"
println ERROR "Please first register the wallet using 'Wallet >> Register'"
- waitForInput && continue
+ waitToProceed && continue
fi
fi
echo
@@ -1610,7 +1691,7 @@ function main {
case $? in
0) selectPool "reg" "${POOL_COLDKEY_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getPoolID "${pool_name}"
@@ -1624,32 +1705,35 @@ function main {
stake_vk_file="${WALLET_FOLDER}/${wallet_name}/${WALLET_STAKE_VK_FILENAME}"
pool_delegcert_file="${WALLET_FOLDER}/${wallet_name}/${WALLET_DELEGCERT_FILENAME}"
println ACTION "${CCLI} ${NETWORK_ERA} stake-address stake-delegation-certificate --stake-verification-key-file ${stake_vk_file} --stake-pool-id ${pool_id} --out-file ${pool_delegcert_file}"
- ${CCLI} ${NETWORK_ERA} stake-address stake-delegation-certificate --stake-verification-key-file "${stake_vk_file}" --stake-pool-id "${pool_id}" --out-file "${pool_delegcert_file}"
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} stake-address stake-delegation-certificate --stake-verification-key-file "${stake_vk_file}" --stake-pool-id "${pool_id}" --out-file "${pool_delegcert_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during stake delegation certificate creation!\n${stdout}"; waitToProceed && continue
+ fi
if ! delegate; then
if [[ ${op_mode} = "online" ]]; then
echo && println ERROR "${FG_RED}ERROR${NC}: failure during delegation, removing newly created delegation certificate file"
rm -f "${pool_delegcert_file}"
fi
- waitForInput && continue
+ waitToProceed && continue
fi
echo
- if ! verifyTx ${base_addr}; then waitForInput && continue; fi
+ if ! verifyTx ${base_addr}; then waitToProceed && continue; fi
+ getWalletBalance ${wallet_name} true true false
echo
println "Delegation successfully registered"
println "Wallet : ${FG_GREEN}${wallet_name}${NC}"
println "Pool : ${FG_GREEN}${pool_name}${NC}"
- println "Amount : ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"
- waitForInput && continue
+ println "Amount : ${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA"
+ waitToProceed && continue
;; ###################################################################
withdrawrewards)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> FUNDS >> WITHDRAW REWARDS"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println ERROR "${FG_RED}ERROR${NC}: CNTools started in offline mode, option not available!"
- waitForInput && continue
+ waitToProceed && continue
else
if ! selectOpMode; then continue; fi
fi
@@ -1658,47 +1742,45 @@ function main {
if [[ ${op_mode} = "online" ]]; then
selectWallet "reward" "${WALLET_PAY_VK_FILENAME}" "${WALLET_STAKE_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitForInput && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitToProceed && continue ;;
esac
else
selectWallet "reward" "${WALLET_PAY_VK_FILENAME}" "${WALLET_STAKE_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
fi
echo
- getBaseAddress ${wallet_name}
- getBalance ${base_addr}
- getRewards ${wallet_name}
+ getWalletBalance ${wallet_name} true true false true
+ getWalletRewards ${wallet_name}
if [[ ${reward_lovelace} -le 0 ]]; then
println ERROR "Failed to locate any rewards associated with the chosen wallet, please try another one"
- waitForInput && continue
- elif [[ ${assets[lovelace]} -eq 0 ]]; then
+ waitToProceed && continue
+ elif [[ ${base_lovelace} -eq 0 ]]; then
println ERROR "${FG_YELLOW}WARN${NC}: No funds in base address, please send funds to base address of wallet to cover withdraw transaction fee"
- waitForInput && continue
+ waitToProceed && continue
fi
- println DEBUG "$(printf "%s\t${FG_LBLUE}%s${NC} ADA" "Funds" "$(formatLovelace ${assets[lovelace]})")"
+ println DEBUG "$(printf "%s\t${FG_LBLUE}%s${NC} ADA" "Funds" "$(formatLovelace ${base_lovelace})")"
println DEBUG "$(printf "%s\t${FG_LBLUE}%s${NC} ADA" "Rewards" "$(formatLovelace ${reward_lovelace})")"
if ! withdrawRewards; then
- waitForInput && continue
+ waitToProceed && continue
fi
echo
- if ! verifyTx ${base_addr}; then waitForInput && continue; fi
- getRewards ${wallet_name}
+ if ! verifyTx ${base_addr}; then waitToProceed && continue; fi
+ getWalletBalance ${wallet_name} true true false
echo
println "Rewards successfully withdrawn"
println "New Balance"
- println " Funds : ${FG_LBLUE}$(formatLovelace ${assets[lovelace]})${NC} ADA"
- println " Rewards : ${FG_LBLUE}$(formatLovelace ${reward_lovelace})${NC} ADA"
- waitForInput && continue
+ println " Funds : ${FG_LBLUE}$(formatLovelace ${base_lovelace})${NC} ADA"
+ waitToProceed && continue
;; ###################################################################
esac # funds sub OPERATION
done # Funds loop
@@ -1720,7 +1802,7 @@ function main {
" ) Rotate - rotate pool KES keys"\
" ) Decrypt - remove write protection and decrypt pool"\
" ) Encrypt - encrypt pool cold keys and make all files immutable"\
- " ) Vote - Cast a CIP-0094 Poll ballot"\
+ " ) Vote - cast a CIP-0094 Poll ballot"\
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println DEBUG " Select Pool Operation\n"
select_opt "[n] New" "[i] Import" "[r] Register" "[m] Modify" "[x] Retire" "[l] List" "[s] Show" "[o] Rotate" "[d] Decrypt" "[e] Encrypt" "[v] Vote" "[h] Home"
@@ -1750,7 +1832,7 @@ function main {
pool_name=${pool_name//[^[:alnum:]]/_}
if [[ -z "${pool_name}" ]]; then
println ERROR "${FG_RED}ERROR${NC}: Empty pool name, please retry!"
- waitForInput && continue
+ waitToProceed && continue
fi
mkdir -p "${POOL_FOLDER}/${pool_name}"
pool_hotkey_vk_file="${POOL_FOLDER}/${pool_name}/${POOL_HOTKEY_VK_FILENAME}"
@@ -1763,26 +1845,32 @@ function main {
if [[ -f "${pool_hotkey_vk_file}" ]]; then
println ERROR "${FG_RED}WARN${NC}: A pool ${FG_GREEN}$pool_name${NC} already exists"
println ERROR " Choose another name or delete the existing one"
- waitForInput && continue
+ waitToProceed && continue
fi
println ACTION "${CCLI} ${NETWORK_ERA} node key-gen-KES --verification-key-file ${pool_hotkey_vk_file} --signing-key-file ${pool_hotkey_sk_file}"
- ${CCLI} ${NETWORK_ERA} node key-gen-KES --verification-key-file "${pool_hotkey_vk_file}" --signing-key-file "${pool_hotkey_sk_file}"
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} node key-gen-KES --verification-key-file "${pool_hotkey_vk_file}" --signing-key-file "${pool_hotkey_sk_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during KES key creation!\n${stdout}"; waitToProceed && continue
+ fi
if [ -f "${POOL_FOLDER}-pregen/${pool_name}/${POOL_ID_FILENAME}" ]; then
mv ${POOL_FOLDER}'-pregen/'${pool_name}/* ${POOL_FOLDER}/${pool_name}/
rm -r ${POOL_FOLDER}'-pregen/'${pool_name}
else
println ACTION "${CCLI} ${NETWORK_ERA} node key-gen --cold-verification-key-file ${pool_coldkey_vk_file} --cold-signing-key-file ${pool_coldkey_sk_file} --operational-certificate-issue-counter-file ${pool_opcert_counter_file}"
- ${CCLI} ${NETWORK_ERA} node key-gen --cold-verification-key-file "${pool_coldkey_vk_file}" --cold-signing-key-file "${pool_coldkey_sk_file}" --operational-certificate-issue-counter-file "${pool_opcert_counter_file}"
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} node key-gen --cold-verification-key-file "${pool_coldkey_vk_file}" --cold-signing-key-file "${pool_coldkey_sk_file}" --operational-certificate-issue-counter-file "${pool_opcert_counter_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during operational certificate counter file creation!\n${stdout}"; waitToProceed && continue
+ fi
fi
println ACTION "${CCLI} ${NETWORK_ERA} node key-gen-VRF --verification-key-file ${pool_vrf_vk_file} --signing-key-file ${pool_vrf_sk_file}"
- ${CCLI} ${NETWORK_ERA} node key-gen-VRF --verification-key-file "${pool_vrf_vk_file}" --signing-key-file "${pool_vrf_sk_file}"
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} node key-gen-VRF --verification-key-file "${pool_vrf_vk_file}" --signing-key-file "${pool_vrf_sk_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during VRF key creation!\n${stdout}"; waitToProceed && continue
+ fi
chmod 600 "${POOL_FOLDER}/${pool_name}/"*
getPoolID ${pool_name}
echo
println "Pool: ${FG_GREEN}${pool_name}${NC}"
[[ -n ${pool_id} ]] && println "ID (hex) : ${pool_id}"
[[ -n ${pool_id_bech32} ]] && println "ID (bech32) : ${pool_id_bech32}"
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
import)
clear
@@ -1795,7 +1883,7 @@ function main {
pool_name=${pool_name//[^[:alnum:]]/_}
if [[ -z "${pool_name}" ]]; then
println ERROR "${FG_RED}ERROR${NC}: Empty pool name, please retry!"
- waitForInput && continue
+ waitToProceed && continue
fi
mkdir -p "${POOL_FOLDER}/${pool_name}"
pool_hotkey_vk_file="${POOL_FOLDER}/${pool_name}/${POOL_HOTKEY_VK_FILENAME}"
@@ -1808,18 +1896,25 @@ function main {
if [[ -f "${pool_hotkey_vk_file}" ]]; then
println ERROR "${FG_RED}WARN${NC}: A pool ${FG_GREEN}$pool_name${NC} already exists"
println ERROR " Choose another name or delete the existing one"
- waitForInput && continue
+ waitToProceed && continue
fi
println ACTION "${CCLI} ${NETWORK_ERA} node key-gen-KES --verification-key-file ${pool_hotkey_vk_file} --signing-key-file ${pool_hotkey_sk_file}"
- ${CCLI} ${NETWORK_ERA} node key-gen-KES --verification-key-file "${pool_hotkey_vk_file}" --signing-key-file "${pool_hotkey_sk_file}"
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} node key-gen-KES --verification-key-file "${pool_hotkey_vk_file}" --signing-key-file "${pool_hotkey_sk_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during KES key creation!\n${stdout}"; waitToProceed && continue
+ fi
println ACTION "${CCLI} ${NETWORK_ERA} node key-gen-VRF --verification-key-file ${pool_vrf_vk_file} --signing-key-file ${pool_vrf_sk_file}"
- ${CCLI} ${NETWORK_ERA} node key-gen-VRF --verification-key-file "${pool_vrf_vk_file}" --signing-key-file "${pool_vrf_sk_file}"
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} node key-gen-VRF --verification-key-file "${pool_vrf_vk_file}" --signing-key-file "${pool_vrf_sk_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during VRF key creation!\n${stdout}"; waitToProceed && continue
+ fi
- println ACTION "cardano-hw-cli node key-gen --path 1853H/1815H/0H/0H --hw-signing-file ${pool_coldkey_sk_file} --cold-verification-key-file ${pool_coldkey_kk_file} --operational-certificate-issue-counter-file ${pool_opcert_counter_file}"
if ! unlockHWDevice "export cold pub keys"; then safeDel "${POOL_FOLDER}/${pool_name}"; continue; fi
- cardano-hw-cli node key-gen --path "1853H/1815H/0H/0H" --hw-signing-file "${pool_coldkey_sk_file}" --cold-verification-key-file "${pool_coldkey_vk_file}" --operational-certificate-issue-counter-file "${pool_opcert_counter_file}"
+ println ACTION "cardano-hw-cli node key-gen --path 1853H/1815H/0H/0H --hw-signing-file ${pool_coldkey_sk_file} --cold-verification-key-file ${pool_coldkey_kk_file} --operational-certificate-issue-counter-file ${pool_opcert_counter_file}"
+ if ! stdout=$(cardano-hw-cli node key-gen --path "1853H/1815H/0H/0H" --hw-signing-file "${pool_coldkey_sk_file}" --cold-verification-key-file "${pool_coldkey_vk_file}" --operational-certificate-issue-counter-file "${pool_opcert_counter_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during HW key extraction!\n${stdout}"; waitToProceed && continue
+ fi
+
jq '.description = "Stake Pool Operator Hardware Verification Key"' "${pool_coldkey_vk_file}" > "${TMP_DIR}/$(basename "${pool_coldkey_vk_file}").tmp" && mv -f "${TMP_DIR}/$(basename "${pool_coldkey_vk_file}").tmp" "${pool_coldkey_vk_file}"
chmod 600 "${POOL_FOLDER}/${pool_name}/"*
@@ -1829,18 +1924,18 @@ function main {
println "Pool: ${FG_GREEN}${pool_name}${NC}"
[[ -n ${pool_id} ]] && println "ID (hex) : ${pool_id}"
[[ -n ${pool_id_bech32} ]] && println "ID (bech32) : ${pool_id_bech32}"
- waitForInput && continue
+ waitToProceed && continue
;; ##################################################################
register|modify)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> POOL >> ${SUBCOMMAND^^}"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No pools available!${NC}" && waitForInput && continue
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No pools available!${NC}" && waitToProceed && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println ERROR "${FG_RED}ERROR${NC}: CNTools started in offline mode, option not available!"
- waitForInput && continue
+ waitToProceed && continue
else
if ! selectOpMode; then continue; fi
fi
@@ -1852,19 +1947,19 @@ function main {
if [[ ${op_mode} = "online" ]]; then
selectPool "${pool_filter}" "${POOL_COLDKEY_VK_FILENAME}" "${POOL_VRF_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getPoolType ${pool_name}
case $? in
0) isHWpool=Y ;;
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: signing keys missing from pool!" && waitForInput && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: signing keys missing from pool!" && waitToProceed && continue ;;
esac
else
selectPool "${pool_filter}" "${POOL_COLDKEY_VK_FILENAME}" "${POOL_VRF_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getPoolType ${pool_name}
@@ -1890,7 +1985,7 @@ function main {
pledge_enter="${pledge_enter//,}"
if [[ -n "${pledge_enter}" ]]; then
if ! ADAToLovelace "${pledge_enter}" >/dev/null; then
- waitForInput && continue
+ waitToProceed && continue
fi
pledge_lovelace=$(ADAToLovelace "${pledge_enter}")
pledge_ada="${pledge_enter}"
@@ -1902,21 +1997,21 @@ function main {
getAnswerAnyCust margin_enter "Margin (in %, default: ${margin})"
if [[ -n "${margin_enter}" ]]; then
if ! pctToFraction "${margin_enter}" >/dev/null; then
- waitForInput && continue
+ waitToProceed && continue
fi
margin_fraction=$(pctToFraction "${margin_enter}")
margin="${margin_enter}"
else
margin_fraction=$(pctToFraction "${margin}")
fi
- minPoolCost=$(formatLovelace $(jq -r '.minPoolCost //0' <<< "${PROT_PARAMS}") normal) # convert to ADA
+ minPoolCost=$(formatLovelace ${MIN_POOL_COST} normal) # convert to ADA
[[ -f ${pool_config} ]] && cost_ada=$(jq -r '.costADA //0' "${pool_config}") || cost_ada=${minPoolCost} # default cost
[[ $(bc -l <<< "${cost_ada} < ${minPoolCost}") -eq 1 ]] && cost_ada=${minPoolCost} # raise old value to new minimum cost
getAnswerAnyCust cost_enter "Cost (in ADA, minimum: ${minPoolCost}, default: ${cost_ada})"
cost_enter="${cost_enter//,}"
if [[ -n "${cost_enter}" ]]; then
if ! ADAToLovelace "${cost_enter}" >/dev/null; then
- waitForInput && continue
+ waitToProceed && continue
fi
cost_lovelace=$(ADAToLovelace "${cost_enter}")
cost_ada="${cost_enter}"
@@ -1925,7 +2020,7 @@ function main {
fi
if [[ $(bc -l <<< "${cost_ada} < ${minPoolCost}") -eq 1 ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: cost set lower than allowed"
- waitForInput && continue
+ waitToProceed && continue
fi
println DEBUG "\n# Pool Metadata\n"
pool_meta_file="${POOL_FOLDER}/${pool_name}/poolmeta.json"
@@ -1934,17 +2029,17 @@ function main {
[[ -n "${json_url_enter}" ]] && meta_json_url="${json_url_enter}"
if [[ ! "${meta_json_url}" =~ https?://.* || ${#meta_json_url} -gt 64 ]]; then
println ERROR "${FG_RED}ERROR${NC}: invalid URL format or more than 64 chars in length"
- waitForInput && continue
+ waitToProceed && continue
fi
metadata_done=false
meta_tmp="${TMP_DIR}/url_poolmeta.json"
if curl -sL -f -m ${CURL_TIMEOUT} -o "${meta_tmp}" ${meta_json_url} && jq -er . "${meta_tmp}" &>/dev/null; then
- [[ $(wc -c <"${meta_tmp}") -gt 512 ]] && println ERROR "${FG_RED}ERROR${NC}: file at specified URL contain more than allowed 512b of data!" && waitForInput && continue
- echo && jq -r . "${meta_tmp}" >&3 && echo
- if ! jq -er .name "${meta_tmp}" &>/dev/null; then println ERROR "${FG_RED}ERROR${NC}: unable to get 'name' field from downloaded metadata file!" && waitForInput && continue; fi
- if ! jq -er .ticker "${meta_tmp}" &>/dev/null; then println ERROR "${FG_RED}ERROR${NC}: unable to get 'ticker' field from downloaded metadata file!" && waitForInput && continue; fi
- if ! jq -er .homepage "${meta_tmp}" &>/dev/null; then println ERROR "${FG_RED}ERROR${NC}: unable to get 'homepage' field from downloaded metadata file!" && waitForInput && continue; fi
- if ! jq -er .description "${meta_tmp}" &>/dev/null; then println ERROR "${FG_RED}ERROR${NC}: unable to get 'description' field from downloaded metadata file!" && waitForInput && continue; fi
+ [[ $(wc -c <"${meta_tmp}") -gt 512 ]] && println ERROR "${FG_RED}ERROR${NC}: file at specified URL contain more than allowed 512b of data!" && waitToProceed && continue
+ echo && jq -r . "${meta_tmp}" && echo
+ if ! jq -er .name "${meta_tmp}" &>/dev/null; then println ERROR "${FG_RED}ERROR${NC}: unable to get 'name' field from downloaded metadata file!" && waitToProceed && continue; fi
+ if ! jq -er .ticker "${meta_tmp}" &>/dev/null; then println ERROR "${FG_RED}ERROR${NC}: unable to get 'ticker' field from downloaded metadata file!" && waitToProceed && continue; fi
+ if ! jq -er .homepage "${meta_tmp}" &>/dev/null; then println ERROR "${FG_RED}ERROR${NC}: unable to get 'homepage' field from downloaded metadata file!" && waitToProceed && continue; fi
+ if ! jq -er .description "${meta_tmp}" &>/dev/null; then println ERROR "${FG_RED}ERROR${NC}: unable to get 'description' field from downloaded metadata file!" && waitToProceed && continue; fi
println DEBUG "Metadata exists at URL. Use existing data?"
select_opt "[y] Yes" "[n] No"
case $? in
@@ -1965,26 +2060,26 @@ function main {
[[ -n "${name_enter}" ]] && meta_name="${name_enter}"
if [[ ${#meta_name} -gt 50 ]]; then
println ERROR "${FG_RED}ERROR${NC}: Name cannot exceed 50 characters"
- waitForInput && continue
+ waitToProceed && continue
fi
getAnswerAnyCust ticker_enter "Enter Pool's Ticker , should be between 3-5 characters (default: ${meta_ticker})"
ticker_enter=${ticker_enter//[^[:alnum:]]/}
[[ -n "${ticker_enter}" ]] && meta_ticker="${ticker_enter^^}"
if [[ ${#meta_ticker} -lt 3 || ${#meta_ticker} -gt 5 ]]; then
println ERROR "${FG_RED}ERROR${NC}: ticker must be between 3-5 characters"
- waitForInput && continue
+ waitToProceed && continue
fi
getAnswerAnyCust desc_enter "Enter Pool's Description (default: ${meta_description})"
[[ -n "${desc_enter}" ]] && meta_description="${desc_enter}"
if [[ ${#meta_description} -gt 255 ]]; then
println ERROR "${FG_RED}ERROR${NC}: Description cannot exceed 255 characters"
- waitForInput && continue
+ waitToProceed && continue
fi
getAnswerAnyCust homepage_enter "Enter Pool's Homepage (default: ${meta_homepage})"
[[ -n "${homepage_enter}" ]] && meta_homepage="${homepage_enter}"
if [[ ! "${meta_homepage}" =~ https?://.* || ${#meta_homepage} -gt 64 ]]; then
println ERROR "${FG_RED}ERROR${NC}: invalid URL format or more than 64 chars in length"
- waitForInput && continue
+ waitToProceed && continue
fi
println DEBUG "\nOptionally set an extended metadata URL?"
select_opt "[n] No" "[y] Yes"
@@ -1995,7 +2090,7 @@ function main {
[[ -n "${extended_enter}" ]] && meta_extended="${extended_enter}"
if [[ ! "${meta_extended}" =~ https?://.* || ${#meta_extended} -gt 64 ]]; then
println ERROR "${FG_RED}ERROR${NC}: invalid extended URL format or more than 64 chars in length"
- waitForInput && continue
+ waitToProceed && continue
else
meta_extended_option=",\"extended\":\"${meta_extended}\""
fi
@@ -2006,19 +2101,19 @@ function main {
metadata_size=$(stat -c%s "${new_pool_meta_file}")
if [[ ${metadata_size} -gt 512 ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: Total metadata size cannot exceed 512 chars in length, current length: ${metadata_size}"
- waitForInput && continue
+ waitToProceed && continue
else
cp -f "${new_pool_meta_file}" "${pool_meta_file}"
fi
println DEBUG "\n${FG_YELLOW}Please host file ${pool_meta_file} as-is at ${meta_json_url}${NC}"
- waitForInput "Press any key to proceed with registration after metadata file is uploaded"
+ waitToProceed "Press any key to proceed with registration after metadata file is uploaded"
fi
relay_output=""
relay_array=()
println DEBUG "\n# Pool Relay Registration"
if [[ -f "${pool_config}" && $(jq '.relays | length' "${pool_config}") -gt 0 ]]; then
println DEBUG "\nPrevious relay configuration:\n"
- jq -r '["TYPE","ADDRESS","PORT"], (.relays[] | [.type //"-",.address //"-",.port //"-"]) | @tsv' "${pool_config}" | column -t >&3
+ jq -r '["TYPE","ADDRESS","PORT"], (.relays[] | [.type //"-",.address //"-",.port //"-"]) | @tsv' "${pool_config}" | column -t
println DEBUG "\nReuse previous relay configuration?"
select_opt "[y] Yes" "[n] No" "[Esc] Cancel"
case $? in
@@ -2138,33 +2233,32 @@ function main {
println ERROR "${FG_RED}ERROR${NC}: main/first pool owner can NOT be a hardware wallet!"
println ERROR "Use a CLI wallet as owner with enough funds to pay for pool deposit and registration transaction fee"
println ERROR "Add the hardware wallet as an additional multi-owner to the pool later in the pool registration wizard"
- waitForInput "Unable to reuse old configuration, please set new owner(s) & reward wallet" && owner_wallets=() && reward_wallet="" && reuse_wallets='N' && break
+ waitToProceed "Unable to reuse old configuration, please set new owner(s) & reward wallet" && owner_wallets=() && reward_wallet="" && reuse_wallets='N' && break
else hw_owner_wallets='Y'; fi ;;
2) if [[ ${op_mode} = "online" ]]; then
println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted for wallet ${FG_GREEN}${wallet_name}${NC}, please decrypt before use!"
- waitForInput && continue 2
+ waitToProceed && continue 2
fi ;;
3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet ${FG_GREEN}${wallet_name}${NC}!"
- waitForInput "Did you mean to run in Hybrid mode? press any key to return home!" && continue 2 ;;
+ waitToProceed "Did you mean to run in Hybrid mode? press any key to return home!" && continue 2 ;;
4) if [[ ${wallet_name} != "${owner_wallets[0]}" && ! -f "${WALLET_FOLDER}/${wallet_name}/${WALLET_STAKE_VK_FILENAME}" ]]; then # ignore if payment vkey is missing for multi-owner, only stake vkey important
println ERROR "${FG_RED}ERROR${NC}: stake verification key missing from wallet ${FG_GREEN}${wallet_name}${NC}!"
- waitForInput "Unable to reuse old configuration, please set new owner(s) & reward wallet" && owner_wallets=() && reward_wallet="" && reuse_wallets='N' && break
+ waitToProceed "Unable to reuse old configuration, please set new owner(s) & reward wallet" && owner_wallets=() && reward_wallet="" && reuse_wallets='N' && break
fi ;;
esac
if [[ ${wallet_name} = "${owner_wallets[0]}" ]] && ! isWalletRegistered ${wallet_name}; then # make sure at least main owner is registered
if [[ ${op_mode} = "hybrid" ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: wallet ${FG_GREEN}${wallet_name}${NC} not a registered wallet on chain and CNTools run in hybrid mode"
println ERROR "Please first register main owner wallet to use in pool registration using 'Wallet >> Register'"
- waitForInput && continue 2
+ waitToProceed && continue 2
fi
- getBaseAddress ${wallet_name}
- getBalance ${base_addr}
- if [[ ${assets[lovelace]} -eq 0 ]]; then
+ getWalletBalance ${wallet_name} true true false true
+ if [[ ${base_lovelace} -eq 0 ]]; then
println ERROR "${FG_RED}ERROR${NC}: no funds available in base address for wallet ${FG_GREEN}${wallet_name}${NC}, needed to pay for registration fee"
- waitForInput && continue 2
+ waitToProceed && continue 2
fi
println DEBUG "# Wallet Registration Transaction"
- if ! registerStakeWallet ${wallet_name}; then waitForInput && continue 2; fi
+ if ! registerStakeWallet ${wallet_name}; then waitToProceed && continue 2; fi
fi
done
@@ -2174,7 +2268,7 @@ function main {
0) hw_reward_wallet='Y' ;;
4) if [[ ! -f "${WALLET_FOLDER}/${wallet_name}/${WALLET_STAKE_VK_FILENAME}" ]]; then # ignore if payment vkey is missing for reward wallet, only stake vkey important
println ERROR "${FG_RED}ERROR${NC}: stake verification key missing from reward wallet ${FG_GREEN}${wallet_name}${NC}!"
- waitForInput "Unable to reuse old configuration, please set new owner(s) & reward wallet" && owner_wallets=() && reward_wallet="" && reuse_wallets='N'
+ waitToProceed "Unable to reuse old configuration, please set new owner(s) & reward wallet" && owner_wallets=() && reward_wallet="" && reuse_wallets='N'
fi ;;
esac
fi
@@ -2191,21 +2285,21 @@ function main {
println DEBUG "# Select main ${FG_YELLOW}owner/pledge${NC} wallet (normal CLI wallet)"
if [[ ${op_mode} = "online" ]]; then
if ! selectWallet "delegate" "${WALLET_PAY_VK_FILENAME}" "${WALLET_STAKE_VK_FILENAME}"; then # ${wallet_name} populated by selectWallet function
- [[ "${dir_name}" != "[Esc] Cancel" ]] && waitForInput; continue
+ [[ "${dir_name}" != "[Esc] Cancel" ]] && waitToProceed; continue
fi
getWalletType ${wallet_name}
case $? in
0) println ERROR "${FG_RED}ERROR${NC}: main pool owner can NOT be a hardware wallet!"
println ERROR "Use a CLI wallet as owner with enough funds to pay for pool deposit and registration transaction fee"
println ERROR "Add the hardware wallet as an additional multi-owner to the pool later in the pool registration wizard"
- waitForInput && continue ;;
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitForInput && continue ;;
+ waitToProceed && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitToProceed && continue ;;
esac
else
selectWallet "delegate" "${WALLET_PAY_VK_FILENAME}" "${WALLET_STAKE_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
@@ -2214,28 +2308,20 @@ function main {
if [[ ${op_mode} = "hybrid" ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: wallet ${FG_GREEN}${wallet_name}${NC} not a registered wallet on chain and CNTools run in hybrid mode"
println ERROR "Please first register the main CLI wallet to use in pool registration using 'Wallet >> Register'"
- waitForInput && continue
+ waitToProceed && continue
fi
- getBaseAddress ${wallet_name}
- getBalance ${base_addr}
- if [[ ${assets[lovelace]} -eq 0 ]]; then
+ getWalletBalance ${wallet_name} true true false true
+ if [[ ${base_lovelace} -eq 0 ]]; then
println ERROR "${FG_RED}ERROR${NC}: no funds available in base address for wallet ${FG_GREEN}${wallet_name}${NC}, needed to pay for registration fee"
- waitForInput && continue
+ waitToProceed && continue
fi
println DEBUG "# Wallet Registration Transaction"
- if ! registerStakeWallet ${wallet_name}; then waitForInput && continue; fi
+ if ! registerStakeWallet ${wallet_name}; then waitToProceed && continue; fi
fi
owner_wallets+=( "${wallet_name}" )
println DEBUG "Owner #1 : ${FG_GREEN}${wallet_name}${NC} added!"
fi
- getBaseAddress ${owner_wallets[0]}
- getBalance ${base_addr}
- if [[ ${assets[lovelace]} -eq 0 ]]; then
- println ERROR "\n${FG_RED}ERROR${NC}: no funds available in owner wallet ${FG_GREEN}${owner_wallets[0]}${NC}"
- waitForInput && continue
- fi
-
if [[ ${reuse_wallets} = 'N' ]]; then
println DEBUG "\nRegister a multi-owner pool (you need to have stake.vkey of any additional owner in a seperate wallet folder under $CNODE_HOME/priv/wallet)?"
while true; do
@@ -2248,10 +2334,10 @@ function main {
0) hw_owner_wallets='Y' ;;
2) if [[ ${op_mode} = "online" ]]; then
println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted for wallet ${FG_GREEN}${wallet_name}${NC}, please decrypt before use!"
- waitForInput && continue 2
+ waitToProceed && continue 2
fi ;;
3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet ${FG_GREEN}${wallet_name}${NC}!"
- waitForInput "Did you mean to run in Hybrid mode? press any key to return home!" && continue 2 ;;
+ waitToProceed "Did you mean to run in Hybrid mode? press any key to return home!" && continue 2 ;;
4) if [[ ! -f "${WALLET_FOLDER}/${wallet_name}/${WALLET_STAKE_VK_FILENAME}" ]]; then # ignore if payment vkey is missing
println ERROR "${FG_RED}ERROR${NC}: stake verification key missing from wallet ${FG_GREEN}${wallet_name}${NC}!"
println DEBUG "Add another owner?" && continue
@@ -2275,14 +2361,14 @@ function main {
case $? in
0) reward_wallet="${owner_wallets[0]}" ;;
1) if ! selectWallet "none" "${WALLET_STAKE_VK_FILENAME}" "${owner_wallets[0]}"; then # ${wallet_name} populated by selectWallet function
- [[ "${dir_name}" != "[Esc] Cancel" ]] && waitForInput; continue
+ [[ "${dir_name}" != "[Esc] Cancel" ]] && waitToProceed; continue
fi
reward_wallet="${wallet_name}"
getWalletType ${reward_wallet}
case $? in
0) hw_reward_wallet='Y' ;;
4) if [[ ! -f "${WALLET_FOLDER}/${wallet_name}/${WALLET_STAKE_VK_FILENAME}" ]]; then # ignore if payment vkey is missing
- println ERROR "${FG_RED}ERROR${NC}: stake verification key missing from wallet ${FG_GREEN}${wallet_name}${NC}!" && waitForInput && continue
+ println ERROR "${FG_RED}ERROR${NC}: stake verification key missing from wallet ${FG_GREEN}${wallet_name}${NC}!" && waitToProceed && continue
fi ;;
esac
;;
@@ -2290,6 +2376,12 @@ function main {
esac
fi
+ getWalletBalance ${owner_wallets[0]} true true false true
+ if [[ ${base_lovelace} -eq 0 ]]; then
+ println ERROR "\n${FG_RED}ERROR${NC}: no funds available in owner wallet ${FG_GREEN}${owner_wallets[0]}${NC}"
+ waitToProceed && continue
+ fi
+
multi_owner_output=""
for wallet_name in "${owner_wallets[@]}"; do
[[ "${wallet_name}" = "${owner_wallets[0]}" ]] && continue # skip main owner
@@ -2326,16 +2418,20 @@ function main {
if [[ ${isHWpool} = 'Y' ]]; then
if ! unlockHWDevice "issue the opcert"; then return 1; fi
println ACTION "cardano-hw-cli node issue-op-cert --kes-verification-key-file ${pool_hotkey_vk_file} --hw-signing-file ${pool_coldkey_sk_file} --operational-certificate-issue-counter-file ${pool_opcert_counter_file} --kes-period ${current_kes_period} --out-file ${pool_opcert_file}"
- ! cardano-hw-cli node issue-op-cert \
+ if ! stdout=$(cardano-hw-cli node issue-op-cert \
--kes-verification-key-file "${pool_hotkey_vk_file}" \
--hw-signing-file "${pool_coldkey_sk_file}" \
--operational-certificate-issue-counter-file "${pool_opcert_counter_file}" \
--kes-period "${current_kes_period}" \
- --out-file "${pool_opcert_file}" \
- && return 1
+ --out-file "${pool_opcert_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during HW operational certificate creation!\n${stdout}"
+ return 1
+ fi
else
println ACTION "${CCLI} ${NETWORK_ERA} node issue-op-cert --kes-verification-key-file ${pool_hotkey_vk_file} --cold-signing-key-file ${pool_coldkey_sk_file} --operational-certificate-issue-counter-file ${pool_opcert_counter_file} --kes-period ${current_kes_period} --out-file ${pool_opcert_file}"
- ${CCLI} ${NETWORK_ERA} node issue-op-cert --kes-verification-key-file "${pool_hotkey_vk_file}" --cold-signing-key-file "${pool_coldkey_sk_file}" --operational-certificate-issue-counter-file "${pool_opcert_counter_file}" --kes-period "${current_kes_period}" --out-file "${pool_opcert_file}"
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} node issue-op-cert --kes-verification-key-file "${pool_hotkey_vk_file}" --cold-signing-key-file "${pool_coldkey_sk_file}" --operational-certificate-issue-counter-file "${pool_opcert_counter_file}" --kes-period "${current_kes_period}" --out-file "${pool_opcert_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during operational certificate creation!\n${stdout}"; waitToProceed && continue
+ fi
fi
fi
@@ -2347,29 +2443,33 @@ function main {
println DEBUG "${FG_LGRAY}${pool_hotkey_sk_file}${NC}"
println DEBUG "${FG_LGRAY}${pool_opcert_file}${NC}"
println DEBUG "${FG_LGRAY}${pool_saved_kes_start}${NC}"
- waitForInput "press any key to continue"
+ waitToProceed "press any key to continue"
fi
fi
println LOG "creating registration certificate"
println ACTION "${CCLI} ${NETWORK_ERA} stake-pool registration-certificate --cold-verification-key-file ${pool_coldkey_vk_file} --vrf-verification-key-file ${pool_vrf_vk_file} --pool-pledge ${pledge_lovelace} --pool-cost ${cost_lovelace} --pool-margin ${margin_fraction} --pool-reward-account-verification-key-file ${reward_stake_vk_file} --pool-owner-stake-verification-key-file ${owner_stake_vk_file} ${multi_owner_output} --metadata-url ${meta_json_url} --metadata-hash \$\(${CCLI} ${NETWORK_ERA} stake-pool metadata-hash --pool-metadata-file ${pool_meta_file} \) ${relay_output} ${NETWORK_IDENTIFIER} --out-file ${pool_regcert_file}"
- ${CCLI} ${NETWORK_ERA} stake-pool registration-certificate --cold-verification-key-file "${pool_coldkey_vk_file}" --vrf-verification-key-file "${pool_vrf_vk_file}" --pool-pledge ${pledge_lovelace} --pool-cost ${cost_lovelace} --pool-margin ${margin_fraction} --pool-reward-account-verification-key-file "${reward_stake_vk_file}" --pool-owner-stake-verification-key-file "${owner_stake_vk_file}" ${multi_owner_output} --metadata-url "${meta_json_url}" --metadata-hash "$(${CCLI} ${NETWORK_ERA} stake-pool metadata-hash --pool-metadata-file ${pool_meta_file} )" ${relay_output} ${NETWORK_IDENTIFIER} --out-file "${pool_regcert_file}"
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} stake-pool registration-certificate --cold-verification-key-file "${pool_coldkey_vk_file}" --vrf-verification-key-file "${pool_vrf_vk_file}" --pool-pledge ${pledge_lovelace} --pool-cost ${cost_lovelace} --pool-margin ${margin_fraction} --pool-reward-account-verification-key-file "${reward_stake_vk_file}" --pool-owner-stake-verification-key-file "${owner_stake_vk_file}" ${multi_owner_output} --metadata-url "${meta_json_url}" --metadata-hash "$(${CCLI} ${NETWORK_ERA} stake-pool metadata-hash --pool-metadata-file ${pool_meta_file} )" ${relay_output} ${NETWORK_IDENTIFIER} --out-file "${pool_regcert_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during stake pool registration certificate creation!\n${stdout}"; waitToProceed && continue
+ fi
delegate_owner_wallet='N'
if [[ ${SUBCOMMAND} = "register" ]]; then
if [[ ${hw_owner_wallets} = 'Y' || ${hw_reward_wallet} = 'Y' || ${isHWpool} = 'Y' ]]; then
println DEBUG "\n${FG_BLUE}INFO${NC}: hardware wallet included as reward or multi-owner or hardware pool, automatic owner/reward wallet delegation disabled"
println DEBUG "${FG_BLUE}INFO${NC}: ${FG_YELLOW}please manually delegate all wallets to the pool!!!${NC}"
- waitForInput "press any key to continue"
+ waitToProceed "press any key to continue"
else
println LOG "creating delegation certificate for main owner wallet"
println ACTION "${CCLI} ${NETWORK_ERA} stake-address stake-delegation-certificate --stake-verification-key-file ${owner_stake_vk_file} --cold-verification-key-file ${pool_coldkey_vk_file} --out-file ${owner_delegation_cert_file}"
- ${CCLI} ${NETWORK_ERA} stake-address stake-delegation-certificate --stake-verification-key-file "${owner_stake_vk_file}" --cold-verification-key-file "${pool_coldkey_vk_file}" --out-file "${owner_delegation_cert_file}"
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} stake-address stake-delegation-certificate --stake-verification-key-file "${owner_stake_vk_file}" --cold-verification-key-file "${pool_coldkey_vk_file}" --out-file "${owner_delegation_cert_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during stake delegation certificate creation!\n${stdout}"; waitToProceed && continue
+ fi
delegate_owner_wallet='Y'
if [[ "${owner_wallets[0]}" != "${reward_wallet}" ]]; then
println DEBUG "\n${FG_BLUE}INFO${NC}: reward wallet not the same as owner, automatic reward wallet delegation disabled"
println DEBUG "${FG_BLUE}INFO${NC}: ${FG_YELLOW}please manually delegate reward wallet to the pool!!!${NC}"
- waitForInput "press any key to continue"
+ waitToProceed "press any key to continue"
fi
fi
fi
@@ -2394,7 +2494,7 @@ function main {
else
[[ -f "${pool_regcert_file}.tmp" ]] && mv -f "${pool_regcert_file}.tmp" "${pool_regcert_file}" # restore reg cert backup
fi
- [[ $rc -eq 1 ]] && waitForInput && continue
+ [[ $rc -eq 1 ]] && waitToProceed && continue
fi
# Save pool config
@@ -2420,7 +2520,7 @@ function main {
echo
if [[ ${op_mode} = "online" ]]; then
getBaseAddress ${owner_wallets[0]}
- if ! verifyTx ${base_addr}; then waitForInput && continue; fi
+ if ! verifyTx ${base_addr}; then waitToProceed && continue; fi
echo
if [[ ${SUBCOMMAND} = "register" ]]; then
println "Pool ${FG_GREEN}${pool_name}${NC} successfully registered!"
@@ -2448,13 +2548,30 @@ function main {
echo
if [[ ${op_mode} = "online" ]]; then
total_pledge=0
- for wallet_name in "${owner_wallets[@]}"; do
- getBaseAddress ${wallet_name}
- getBalance ${base_addr}
- total_pledge=$(( total_pledge + assets[lovelace] ))
- getRewards ${wallet_name}
- [[ ${reward_lovelace} -gt 0 ]] && total_pledge=$(( total_pledge + reward_lovelace ))
- done
+ if [[ -n ${KOIOS_API} ]]; then
+ addr_list=()
+ reward_addr_list=()
+ for wallet_name in "${owner_wallets[@]}"; do
+ getBaseAddress ${wallet_name} && addr_list+=(${base_addr})
+ getRewardAddress ${wallet_name} && reward_addr_list+=(${reward_addr})
+ done
+ [[ ${#addr_list[@]} -gt 0 ]] && getBalanceKoios false
+ [[ ${#reward_addr_list[@]} -gt 0 ]] && getRewardInfoKoios
+ for key in "${!assets[@]}"; do
+ [[ ${key} = *lovelace ]] && total_pledge=$(( total_pledge + assets[${key}] ))
+ done
+ for value in "${rewards_available[@]}"; do
+ [[ ${value} -gt 0 ]] && total_pledge=$(( total_pledge + value ))
+ done
+ else
+ for wallet_name in "${owner_wallets[@]}"; do
+ getBaseAddress ${wallet_name}
+ getBalance ${base_addr}
+ total_pledge=$(( total_pledge + assets[lovelace] ))
+ getWalletRewards ${wallet_name}
+ [[ ${reward_lovelace} -gt 0 ]] && total_pledge=$(( total_pledge + reward_lovelace ))
+ done
+ fi
println DEBUG "${FG_BLUE}INFO${NC}: Total balance in ${FG_LBLUE}${#owner_wallets[@]}${NC} owner/pledge wallet(s) are: ${FG_LBLUE}$(formatLovelace ${total_pledge})${NC} ADA"
if [[ ${total_pledge} -lt ${pledge_lovelace} ]]; then
println ERROR "${FG_YELLOW}Not enough funds in owner/pledge wallet(s) to meet set pledge, please manually verify!!!${NC}"
@@ -2467,18 +2584,18 @@ function main {
println DEBUG "${FG_BLUE}INFO${NC}: please verify that all owner/reward wallets are delegated to the pool, if not do so!"
fi
fi
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
retire)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> POOL >> RETIRE"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No pools available!${NC}" && waitForInput && continue
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available to pay for pool de-registration!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No pools available!${NC}" && waitToProceed && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available to pay for pool de-registration!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println ERROR "${FG_RED}ERROR${NC}: CNTools started in offline mode, option not available!"
- waitForInput && continue
+ waitToProceed && continue
else
if ! selectOpMode; then continue; fi
fi
@@ -2487,28 +2604,27 @@ function main {
if [[ ${op_mode} = "online" ]]; then
selectPool "${pool_filter}" "${POOL_COLDKEY_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getPoolType ${pool_name}
case $? in
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: signing keys missing from pool!" && waitForInput && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: signing keys missing from pool!" && waitToProceed && continue ;;
esac
else
selectPool "${pool_filter}" "${POOL_COLDKEY_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getPoolType ${pool_name}
fi
echo
epoch=$(getEpoch)
- poolRetireMaxEpoch=$(jq -r '.poolRetireMaxEpoch' <<< "${PROT_PARAMS}")
println DEBUG "Current epoch: ${FG_LBLUE}${epoch}${NC}"
epoch_start=$((epoch + 1))
- epoch_end=$((epoch + poolRetireMaxEpoch))
+ epoch_end=$((epoch + POOL_RETIRE_MAX_EPOCH))
println DEBUG "earliest epoch to retire pool is ${FG_LBLUE}${epoch_start}${NC} and latest ${FG_LBLUE}${epoch_end}${NC}"
echo
getAnswerAnyCust epoch_enter "Enter epoch in which to retire pool (blank for ${epoch_start})"
@@ -2516,38 +2632,33 @@ function main {
echo
if [[ ${epoch_enter} -lt ${epoch_start} || ${epoch_enter} -gt ${epoch_end} ]]; then
println ERROR "${FG_RED}ERROR${NC}: epoch invalid, valid range: ${epoch_start}-${epoch_end}"
- waitForInput && continue
+ waitToProceed && continue
fi
println DEBUG "# Select wallet for pool de-registration transaction fee"
if [[ ${op_mode} = "online" ]]; then
selectWallet "balance" "${WALLET_PAY_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet to pay for pool de-registration transaction fee!" && waitForInput && continue ;;
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitForInput && continue ;;
+ 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet to pay for pool de-registration transaction fee!" && waitToProceed && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitToProceed && continue ;;
esac
else
selectWallet "balance" "${WALLET_PAY_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet to pay for pool de-registration transaction fee!" && waitForInput && continue ;;
+ 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet to pay for pool de-registration transaction fee!" && waitToProceed && continue ;;
esac
fi
- getBaseAddress ${wallet_name}
- getPayAddress ${wallet_name}
- getBalance ${base_addr}
- base_lovelace=${assets[lovelace]}
- getBalance ${pay_addr}
- pay_lovelace=${assets[lovelace]}
+ getWalletBalance ${wallet_name} true true true true
if [[ ${pay_lovelace} -gt 0 && ${base_lovelace} -gt 0 ]]; then
# Both payment and base address available with funds, let user choose what to use
println DEBUG "\n# Select wallet address to use"
@@ -2557,47 +2668,51 @@ function main {
fi
select_opt "[b] Base (default)" "[e] Enterprise" "[Esc] Cancel"
case $? in
- 0) addr="${base_addr}" ;;
- 1) addr="${pay_addr}" ;;
+ 0) addr="${base_addr}"; lovelace=${base_lovelace} ;;
+ 1) addr="${pay_addr}"; lovelace=${pay_lovelace} ;;
2) continue ;;
esac
elif [[ ${pay_lovelace} -gt 0 ]]; then
addr="${pay_addr}"
+ lovelace=${pay_lovelace}
if [[ -n ${wallet_count} && ${wallet_count} -gt ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
println DEBUG "\n$(printf "%s\t${FG_LBLUE}%s${NC} ADA" "Enterprise Funds :" "$(formatLovelace ${pay_lovelace})")"
fi
elif [[ ${base_lovelace} -gt 0 ]]; then
addr="${base_addr}"
+ lovelace=${base_lovelace}
if [[ -n ${wallet_count} && ${wallet_count} -gt ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
println DEBUG "\n$(printf "%s\t\t${FG_LBLUE}%s${NC} ADA" "Funds :" "$(formatLovelace ${base_lovelace})")"
fi
else
println ERROR "\n${FG_RED}ERROR${NC}: no funds available for wallet ${FG_GREEN}${wallet_name}${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
pool_deregcert_file="${POOL_FOLDER}/${pool_name}/${POOL_DEREGCERT_FILENAME}"
pool_regcert_file="${POOL_FOLDER}/${pool_name}/${POOL_REGCERT_FILENAME}"
println LOG "creating de-registration cert"
println ACTION "${CCLI} ${NETWORK_ERA} stake-pool deregistration-certificate --cold-verification-key-file ${pool_coldkey_vk_file} --epoch ${epoch_enter} --out-file ${pool_deregcert_file}"
- ${CCLI} ${NETWORK_ERA} stake-pool deregistration-certificate --cold-verification-key-file ${pool_coldkey_vk_file} --epoch ${epoch_enter} --out-file ${pool_deregcert_file}
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} stake-pool deregistration-certificate --cold-verification-key-file ${pool_coldkey_vk_file} --epoch ${epoch_enter} --out-file ${pool_deregcert_file} 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during stake pool deregistration certificate creation!\n${stdout}"; waitToProceed && continue
+ fi
echo
if ! deRegisterPool; then
- waitForInput && continue
+ waitToProceed && continue
fi
[[ -f "${pool_regcert_file}" ]] && rm -f ${pool_regcert_file} # delete registration cert
echo
- if ! verifyTx ${addr}; then waitForInput && continue; fi
+ if ! verifyTx ${addr}; then waitToProceed && continue; fi
echo
println "Pool ${FG_GREEN}${pool_name}${NC} set to be retired in epoch ${FG_LBLUE}${epoch_enter}${NC}"
println "Pool deposit will be returned to owner reward address after its retired"
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
list)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> POOL >> LIST"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No pools available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No pools available!${NC}" && waitToProceed && continue
current_epoch=$(getEpoch)
while IFS= read -r -d '' pool; do
echo
@@ -2606,7 +2721,7 @@ function main {
pool_regcert_file="${pool}/${POOL_REGCERT_FILENAME}"
isPoolRegistered "${pool_name}"
case $? in
- 0) println "ERROR" "${FG_RED}KOIOS_API ERROR${NC}: ${error_msg}" && waitForInput && continue ;;
+ 0) println "ERROR" "${FG_RED}KOIOS_API ERROR${NC}: ${error_msg}" && waitToProceed && continue ;;
1) pool_registered="${FG_RED}NO${NC}" ;;
2) pool_registered="${FG_GREEN}YES${NC}" ;;
3) if [[ ${current_epoch} -lt ${p_retiring_epoch} ]]; then
@@ -2614,6 +2729,7 @@ function main {
else
pool_registered="${FG_RED}NO${NC} - Retired in epoch ${FG_LBLUE}${p_retiring_epoch}${NC}"
fi ;;
+ 4) pool_registered="${FG_RED}NO${NC} - Retired in epoch ${FG_LBLUE}${p_retiring_epoch}${NC}" ;;
esac
enc_files=$(find "${pool}" -mindepth 1 -maxdepth 1 -type f -name '*.gpg' -print0 | wc -c)
if [[ ${enc_files} -gt 0 ]]; then
@@ -2625,7 +2741,7 @@ function main {
[[ -n ${pool_id_bech32} ]] && println "$(printf "%-21s : ${FG_LGRAY}%s${NC}" "ID (bech32)" "${pool_id_bech32}")"
println "$(printf "%-21s : %s" "Registered" "${pool_registered}")"
unset pool_kes_start
- if [[ ${CNTOOLS_MODE} = "CONNECTED" ]]; then
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
getNodeMetrics
else
[[ -f "${pool}/${POOL_CURRENT_KES_START}" ]] && pool_kes_start="$(cat "${pool}/${POOL_CURRENT_KES_START}")"
@@ -2647,7 +2763,7 @@ function main {
fi
done < <(find "${POOL_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z)
echo
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
show)
clear
@@ -2655,47 +2771,50 @@ function main {
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> POOL >> SHOW"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No pools available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No pools available!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println DEBUG "${FG_LGRAY}OFFLINE MODE${NC}: CNTools started in offline mode, locally saved info shown!"
fi
tput sc
selectPool "all" "${POOL_ID_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
current_epoch=$(getEpoch)
getPoolID ${pool_name}
tput rc && tput ed
- if [[ ${CNTOOLS_MODE} = "CONNECTED" && -z ${KOIOS_API} ]]; then
- println DEBUG "Koios API disabled/unreachable, do you want to proceed querying pool parameters from node?"
- println DEBUG "This is a heavy process and requiring several gigabytes of memory on MainNet."
- select_opt "[y] Yes" "[n] No, abort"
- [[ $? -eq 1 ]] && continue
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
tput sc && println DEBUG "Quering pool parameters from node, can take a while...\n"
println ACTION "${CCLI} ${NETWORK_ERA} query pool-params --stake-pool-id ${pool_id_bech32} ${NETWORK_IDENTIFIER}"
if ! pool_params=$(${CCLI} ${NETWORK_ERA} query pool-params --stake-pool-id ${pool_id_bech32} ${NETWORK_IDENTIFIER} 2>&1); then
tput rc && tput ed
println ERROR "${FG_RED}ERROR${NC}: pool-params query failed: ${pool_params}"
- waitForInput && continue
+ waitToProceed && continue
fi
tput rc && tput ed
fi
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
pool_registered="${FG_LGRAY}status unavailable in offline mode${NC}"
- elif [[ -z ${KOIOS_API} ]]; then
- ledger_pParams=$(jq -r '.poolParams // empty' <<< ${pool_params})
- ledger_fPParams=$(jq -r '.futurePoolParams // empty' <<< ${pool_params})
- ledger_retiring=$(jq -r '.retiring // empty' <<< ${pool_params})
+ elif [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
+ ledger_pParams=$(jq -r '.[].poolParams // empty' <<< ${pool_params})
+ ledger_fPParams=$(jq -r '.[].futurePoolParams // empty' <<< ${pool_params})
+ ledger_retiring=$(jq -r '.[].retiring // empty' <<< ${pool_params})
[[ -z ${ledger_retiring} ]] && p_retiring_epoch=0 || p_retiring_epoch=${ledger_retiring}
[[ -z "${ledger_fPParams}" ]] && ledger_fPParams="${ledger_pParams}"
[[ -n "${ledger_pParams}" ]] && pool_registered="${FG_GREEN}YES${NC}" || pool_registered="${FG_RED}NO${NC}"
+ if [[ ${p_retiring_epoch} -gt 0 ]]; then
+ if [[ ${current_epoch} -lt ${p_retiring_epoch} ]]; then
+ pool_registered="${FG_YELLOW}YES${NC} - Retiring in epoch ${FG_LBLUE}${p_retiring_epoch}${NC}"
+ else
+ pool_registered="${FG_RED}NO${NC} - Retired in epoch ${FG_LBLUE}${p_retiring_epoch}${NC}"
+ fi
+ fi
else
- println DEBUG "\n${FG_YELLOW}> Querying Koios API for pool information (some data can have a delay of up to 10min)${NC}"
+ println OFF "\n${FG_YELLOW}> Querying Koios API for pool information (some data can have a small delay)${NC}"
isPoolRegistered ${pool_name} # variables set in isPoolRegistered [pool_info, error_msg, p_]
case $? in
- 0) println "ERROR" "\n${FG_RED}KOIOS_API ERROR${NC}: ${error_msg}" && waitForInput && continue ;;
+ 0) println "ERROR" "\n${FG_RED}KOIOS_API ERROR${NC}: ${error_msg}" && waitToProceed && continue ;;
1) pool_registered="${FG_RED}NO${NC}" ;;
2) pool_registered="${FG_GREEN}YES${NC}" ;;
3) if [[ ${current_epoch} -lt ${p_retiring_epoch} ]]; then
@@ -2703,6 +2822,7 @@ function main {
else
pool_registered="${FG_RED}NO${NC} - Retired in epoch ${FG_LBLUE}${p_retiring_epoch}${NC}"
fi ;;
+ 4) pool_registered="${FG_RED}NO${NC} - Retired in epoch ${FG_LBLUE}${p_retiring_epoch}${NC}" ;;
esac
fi
echo
@@ -2742,9 +2862,11 @@ function main {
println "$(printf " %-19s : ${FG_LGRAY}%s${NC}" "Description" "$(jq -r .description "$TMP_DIR/url_poolmeta.json")")"
println "$(printf " %-19s : ${FG_LGRAY}%s${NC}" "URL" "${meta_json_url}")"
println ACTION "${CCLI} ${NETWORK_ERA} stake-pool metadata-hash --pool-metadata-file ${TMP_DIR}/url_poolmeta.json"
- meta_hash_url="$( ${CCLI} ${NETWORK_ERA} stake-pool metadata-hash --pool-metadata-file "${TMP_DIR}/url_poolmeta.json" )"
+ if ! meta_hash_url=$(${CCLI} ${NETWORK_ERA} stake-pool metadata-hash --pool-metadata-file "${TMP_DIR}/url_poolmeta.json" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during metadata hash creation!\n${meta_hash_url}"; waitToProceed && continue
+ fi
println "$(printf " %-19s : ${FG_LGRAY}%s${NC}" "Hash URL" "${meta_hash_url}")"
- if [[ -z ${KOIOS_API} ]]; then
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
meta_hash_pParams=$(jq -r '.metadata.hash //empty' <<< "${ledger_pParams}")
meta_hash_fPParams=$(jq -r '.metadata.hash //empty' <<< "${ledger_fPParams}")
else
@@ -2783,7 +2905,7 @@ function main {
done < <(jq -r '.relays[] | "\(.type) \(.address) \(.port)"' "${pool_config}")
elif [[ ${pool_registered} = *YES* ]]; then
# get pledge
- if [[ -z ${KOIOS_API} ]]; then
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
pParams_pledge=$(jq -r '.pledge //0' <<< "${ledger_pParams}")
fPParams_pledge=$(jq -r '.pledge //0' <<< "${ledger_fPParams}")
else
@@ -2800,7 +2922,7 @@ function main {
[[ -n ${KOIOS_API} ]] && getPriceString ${p_live_pledge} && println "$(printf "%-21s : ${FG_LBLUE}%s${NC} ADA${price_str}" "Live Pledge" "$(formatLovelace "${p_live_pledge}")")"
# get margin
- if [[ -z ${KOIOS_API} ]]; then
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
pParams_margin=$(LC_NUMERIC=C printf "%.4f" "$(jq -r '.margin //0' <<< "${ledger_pParams}")")
fPParams_margin=$(LC_NUMERIC=C printf "%.4f" "$(jq -r '.margin //0' <<< "${ledger_fPParams}")")
else
@@ -2814,7 +2936,7 @@ function main {
fi
# get fixed cost
- if [[ -z ${KOIOS_API} ]]; then
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
pParams_cost=$(jq -r '.cost //0' <<< "${ledger_pParams}")
fPParams_cost=$(jq -r '.cost //0' <<< "${ledger_fPParams}")
else
@@ -2828,7 +2950,7 @@ function main {
fi
# get relays
- if [[ -z ${KOIOS_API} ]]; then
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
relays=$(jq -c '.relays[] //empty' <<< "${ledger_fPParams}")
if [[ ${relays} != $(jq -c '.relays[] //empty' <<< "${ledger_pParams}") ]]; then
println "$(printf "%-23s ${FG_YELLOW}%s${NC}" "" "Relay(s) updated, showing latest registered")"
@@ -2840,7 +2962,7 @@ function main {
if [[ -n "${relays}" ]]; then
while read -r relay; do
relay_addr=""; relay_port=""
- if [[ -z ${KOIOS_API} ]]; then
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
relay_addr="$(jq -r '."single host address".IPv4 //empty' <<< ${relay})"
if [[ -n ${relay_addr} ]]; then
relay_port="$(jq -r '."single host address".port //empty' <<< ${relay})"
@@ -2881,7 +3003,7 @@ function main {
fi
# get owners
- if [[ -z ${KOIOS_API} ]]; then
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
owners=$(jq -rc '.owners[] // empty' <<< "${ledger_fPParams}")
if [[ ${owners} != $(jq -rc '.owners[] // empty' <<< "${ledger_pParams}") ]]; then
println "$(printf "%-23s ${FG_YELLOW}%s${NC}" "" "Owner(s) updated, showing latest registered")"
@@ -2902,7 +3024,7 @@ function main {
done <<< "${owners}"
# get reward account
- if [[ -z ${KOIOS_API} ]]; then
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
reward_account=$(jq -r '.rewardAccount.credential."key hash" // empty' <<< "${ledger_fPParams}")
if [[ ${reward_account} != $(jq -r '.rewardAccount.credential."key hash" // empty' <<< "${ledger_pParams}") ]]; then
println "$(printf "%-23s ${FG_YELLOW}%s${NC}" "" "Reward account updated, showing latest registered")"
@@ -2920,7 +3042,7 @@ function main {
fi
fi
- if [[ -z ${KOIOS_API} ]]; then
+ if [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
# get stake distribution
println "ACTION" "LC_NUMERIC=C printf %.10f \$(${CCLI} ${NETWORK_ERA} query stake-distribution ${NETWORK_IDENTIFIER} | grep ${pool_id_bech32} | tr -s ' ' | cut -d ' ' -f 2))"
stake_pct=$(fractionToPCT "$(LC_NUMERIC=C printf "%.10f" "$(${CCLI} ${NETWORK_ERA} query stake-distribution ${NETWORK_IDENTIFIER} | grep "${pool_id_bech32}" | tr -s ' ' | cut -d ' ' -f 2)")")
@@ -2940,7 +3062,7 @@ function main {
if [[ -n ${KOIOS_API} ]]; then
[[ ${p_op_cert_counter} != null ]] && kes_counter_str="${FG_LBLUE}${p_op_cert_counter}${FG_LGRAY} - use counter ${FG_LBLUE}$((p_op_cert_counter+1))${FG_LGRAY} for rotation in offline mode.${NC}" || kes_counter_str="${FG_LGRAY}No blocks minted so far with active operational certificate. Use counter ${FG_LBLUE}0${FG_LGRAY} for rotation in offline mode.${NC}"
println "$(printf "%-21s : %s" "KES counter" "${kes_counter_str}")"
- elif [[ ${CNTOOLS_MODE} = "CONNECTED" ]]; then
+ elif [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then
pool_opcert_file="${POOL_FOLDER}/${pool_name}/${POOL_OPCERT_FILENAME}"
println ACTION "${CCLI} ${NETWORK_ERA} query kes-period-info --op-cert-file ${pool_opcert_file} ${NETWORK_IDENTIFIER}"
if ! kes_period_info=$(${CCLI} ${NETWORK_ERA} query kes-period-info --op-cert-file "${pool_opcert_file}" ${NETWORK_IDENTIFIER}); then
@@ -2973,7 +3095,7 @@ function main {
fi
fi
fi
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
rotate)
clear
@@ -2984,25 +3106,25 @@ function main {
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println DEBUG "${FG_LGRAY}OFFLINE MODE${NC}: CNTools started in offline mode, please grab correct counter value from online node using pool info!\n"
fi
- [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && println "${FG_YELLOW}No pools available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && println "${FG_YELLOW}No pools available!${NC}" && waitToProceed && continue
println DEBUG "# Select pool to rotate KES keys on"
selectPool "all" "${POOL_COLDKEY_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
getAnswerAnyCust new_counter "Enter new counter number"
if ! isNumber ${new_counter}; then
println ERROR "\n${FG_RED}ERROR${NC}: not a number"
- waitForInput && continue
+ waitToProceed && continue
fi
if ! rotatePoolKeys ${new_counter}; then
- waitForInput && continue
+ waitToProceed && continue
fi
else
if ! rotatePoolKeys; then
- waitForInput && continue
+ waitToProceed && continue
fi
fi
echo
@@ -3017,7 +3139,7 @@ function main {
echo
fi
println DEBUG "Restart your pool node for changes to take effect"
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
decrypt)
clear
@@ -3025,11 +3147,11 @@ function main {
println " >> POOL >> DECRYPT"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo
- [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && println "${FG_YELLOW}No pools available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && println "${FG_YELLOW}No pools available!${NC}" && waitToProceed && continue
println DEBUG "# Select pool to decrypt"
selectPool "encrypted"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
filesUnlocked=0
@@ -3046,7 +3168,7 @@ function main {
println "# Decrypting GPG encrypted pool files"
if ! getPasswordCust; then # $password variable populated by getPasswordCust function
println "\n\n" && println ERROR "${FG_RED}ERROR${NC}: password input aborted!"
- waitForInput && continue
+ waitToProceed && continue
fi
while IFS= read -r -d '' file; do
decryptFile "${file}" "${password}" && \
@@ -3064,7 +3186,7 @@ function main {
println DEBUG "${FG_YELLOW}Pool files are now unprotected${NC}"
println DEBUG "Use 'POOL >> ENCRYPT / LOCK' to re-lock"
fi
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
encrypt)
clear
@@ -3072,11 +3194,11 @@ function main {
println " >> POOL >> ENCRYPT"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo
- [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && println "${FG_YELLOW}No pools available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && println "${FG_YELLOW}No pools available!${NC}" && waitToProceed && continue
println DEBUG "# Select pool to encrypt"
selectPool "encrypted"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
filesLocked=0
@@ -3086,7 +3208,7 @@ function main {
println DEBUG "# Encrypting sensitive pool keys with GPG"
if ! getPasswordCust confirm; then # $password variable populated by getPasswordCust function
println "\n\n" && println ERROR "${FG_RED}ERROR${NC}: password input aborted!"
- waitForInput && continue
+ waitToProceed && continue
fi
keyFiles=(
"${POOL_FOLDER}/${pool_name}/${POOL_COLDKEY_SK_FILENAME}"
@@ -3102,7 +3224,7 @@ function main {
else
echo
println DEBUG "${FG_YELLOW}NOTE${NC}: found GPG encrypted files in folder, please decrypt/unlock pool files before encrypting"
- waitForInput && continue
+ waitToProceed && continue
fi
echo
println DEBUG "# Write protecting all pool files with 400 permission and if enabled 'chattr +i'"
@@ -3120,7 +3242,7 @@ function main {
println DEBUG "${FG_BLUE}INFO${NC}: pool files are now protected"
println DEBUG "Use 'POOL >> DECRYPT / UNLOCK' to unlock"
fi
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
vote)
clear
@@ -3131,14 +3253,14 @@ function main {
if ! cmdAvailable "xxd"; then
myExit 1 "xxd is a hexdump tool to generate the CBOR encoded poll answer"
fi
- [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No pools available!${NC}" && waitForInput && continue
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available to pay for poll ballot casts!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${POOL_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No pools available!${NC}" && waitToProceed && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available to pay for poll ballot casts!${NC}" && waitToProceed && continue
if [[ -z ${KOIOS_API} ]]; then
- echo && println ERROR "${FG_YELLOW}Koios API required!${NC}" && waitForInput && continue
+ echo && println ERROR "${FG_YELLOW}Koios API required!${NC}" && waitToProceed && continue
fi
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println ERROR "${FG_RED}ERROR${NC}: CNTools started in offline mode, option not available!"
- waitForInput && continue
+ waitToProceed && continue
else
if ! selectOpMode; then continue; fi
fi
@@ -3148,7 +3270,9 @@ function main {
NETWORK_NAME_LOWER=$(echo "$NETWORK_NAME" | awk '{print tolower($0)}')
println LOG "Query ${NETWORK_NAME} polls ..."
println ACTION "curl -sSL -f -H \"Content-Type: application/json\" ${CIP0094_POLL_URL}"
- ! polls=$(curl -sSL -f -H "Content-Type: application/json" "${CIP0094_POLL_URL}" | jq -r .networks.${NETWORK_NAME_LOWER} 2>&1) && waitForInput && continue
+ if ! polls=$(curl -sSL -f -H "Content-Type: application/json" "${CIP0094_POLL_URL}" | jq -r .networks.${NETWORK_NAME_LOWER} 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during CIP0094 poll query!\n${polls}"; waitToProceed && continue
+ fi
poll_index=$(echo $polls | jq '. | length')
if [[ "$poll_index" -gt 0 ]]; then
poll_index_act=0
@@ -3182,18 +3306,18 @@ function main {
if [[ ${op_mode} = "online" ]]; then
selectPool "${pool_filter}" "${POOL_COLDKEY_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getPoolType ${pool_name}
case $? in
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: signing keys missing from pool!" && waitForInput && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: signing keys missing from pool!" && waitToProceed && continue ;;
esac
else
selectPool "${pool_filter}" "${POOL_COLDKEY_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getPoolType ${pool_name}
@@ -3203,32 +3327,27 @@ function main {
if [[ ${op_mode} = "online" ]]; then
selectWallet "balance" "${WALLET_PAY_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet to pay for transaction fee!" && waitForInput && continue ;;
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitForInput && continue ;;
+ 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet to pay for transaction fee!" && waitToProceed && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitToProceed && continue ;;
esac
else
selectWallet "balance" "${WALLET_PAY_VK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet to pay for transaction fee!" && waitForInput && continue ;;
+ 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet to pay for transaction fee!" && waitToProceed && continue ;;
esac
fi
- getBaseAddress ${wallet_name}
- getPayAddress ${wallet_name}
- getBalance ${base_addr}
- base_lovelace=${assets[lovelace]}
- getBalance ${pay_addr}
- pay_lovelace=${assets[lovelace]}
+ getWalletBalance ${wallet_name} true true true true
if [[ ${pay_lovelace} -gt 0 && ${base_lovelace} -gt 0 ]]; then
# Both payment and base address available with funds, let user choose what to use
println DEBUG "\n# Select wallet address to use"
@@ -3238,28 +3357,32 @@ function main {
fi
select_opt "[b] Base (default)" "[e] Enterprise" "[Esc] Cancel"
case $? in
- 0) addr="${base_addr}" ;;
- 1) addr="${pay_addr}" ;;
+ 0) addr="${base_addr}"; lovelace=${base_lovelace} ;;
+ 1) addr="${pay_addr}"; lovelace=${pay_lovelace} ;;
2) continue ;;
esac
elif [[ ${pay_lovelace} -gt 0 ]]; then
addr="${pay_addr}"
+ lovelace=${pay_lovelace}
if [[ -n ${wallet_count} && ${wallet_count} -gt ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
println DEBUG "\n$(printf "%s\t${FG_LBLUE}%s${NC} ADA" "Enterprise Funds :" "$(formatLovelace ${pay_lovelace})")"
fi
elif [[ ${base_lovelace} -gt 0 ]]; then
addr="${base_addr}"
+ lovelace=${base_lovelace}
if [[ -n ${wallet_count} && ${wallet_count} -gt ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
println DEBUG "\n$(printf "%s\t\t${FG_LBLUE}%s${NC} ADA" "Funds :" "$(formatLovelace ${base_lovelace})")"
fi
else
println ERROR "\n${FG_RED}ERROR${NC}: no funds available for wallet ${FG_GREEN}${wallet_name}${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
echo
echo "Query ${NETWORK_NAME} ${poll_txId} metadata from Koios API..."
println ACTION "curl -sSL -f -X POST -H \"Content-Type: application/json\" -d '{\"_tx_hashes\":[\"${poll_txId}\"]}' ${KOIOS_API}/tx_metadata"
- ! tx=$(curl -sSL -f -X POST -H "Content-Type: application/json" -d '{"_tx_hashes":["'${poll_txId}'"]}' "${KOIOS_API}/tx_metadata" 2>&1) && error_msg=${tx} && waitForInput && continue
+ if ! tx=$(curl -sSL -f -X POST -H "Content-Type: application/json" -d '{"_tx_hashes":["'${poll_txId}'"]}' "${KOIOS_API}/tx_metadata" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during Koios tx metadata query!\n${tx}"; waitToProceed && continue
+ fi
tx_meta=$(echo ${tx} | jq -r ".[0].metadata.\"94\" // empty" 2> /dev/null )
if [[ ! -z ${tx_meta} ]]; then
echo "OK: Metadata has a CIP-0094 label"
@@ -3276,7 +3399,7 @@ function main {
#Add QuestionStrings
questionStrLength=$(jq -r ".\"0\" | length" <<< ${tx_meta} 2> /dev/null)
if [[ ${questionStrLength} -eq 0 ]]; then
- echo -e "\n${FG_RED}ERROR - No question string included\n${NC}" && waitForInput && continue
+ echo -e "\n${FG_RED}ERROR - No question string included\n${NC}" && waitToProceed && continue
fi
cborStr+=$(to_cbor "array" ${questionStrLength}) #array with the number of entries
for (( tmpCnt=0; tmpCnt<${questionStrLength}; tmpCnt++ ))
@@ -3289,7 +3412,7 @@ function main {
#Add OptionsStrings
optionsStrLength=$(jq -r ".\"1\" | length" <<< ${tx_meta} 2> /dev/null)
if [[ ${optionsStrLength} -eq 0 ]]; then
- echo -e "\n${FG_RED}ERROR - No option strings included\n${NC}" && waitForInput && continue
+ echo -e "\n${FG_RED}ERROR - No option strings included\n${NC}" && waitToProceed && continue
fi
cborStr+=$(to_cbor "array" ${optionsStrLength}) #array with the number of options
@@ -3320,7 +3443,7 @@ function main {
do
read -p $'Please indicate an answer (by index): ' answer
if [[ ${answer} == "" ]]; then
- echo && println "${FG_YELLOW}No answer${NC}" && waitForInput && continue
+ echo && println "${FG_YELLOW}No answer${NC}" && waitToProceed && continue
fi
done
echo
@@ -3351,14 +3474,12 @@ function main {
DEFAULTEDITOR="$(command -v nano &>/dev/null && echo 'nano' || echo 'vi')"
println OFF "\nA maximum of 64 characters(bytes) is allowed per line."
println OFF "${FG_YELLOW}Please don't change default file path when saving.${NC}"
- exec >&6 2>&7 # normal stdout/stderr
- waitForInput "press any key to open '${FG_LGRAY}${DEFAULTEDITOR}${NC}' text editor"
+ waitToProceed "press any key to open '${FG_LGRAY}${DEFAULTEDITOR}${NC}' text editor"
${DEFAULTEDITOR} "${metafile}"
- exec >&8 2>&9 # custom stdout/stderr
if [[ ! -f "${metafile}" ]]; then
println ERROR "${FG_RED}ERROR${NC}: file not found"
println ERROR "File: ${FG_LGRAY}${metafile}${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
tput cuu 4 && tput ed
if [[ ! -s ${metafile} ]]; then
@@ -3380,27 +3501,27 @@ function main {
error="${FG_RED}ERROR${NC}: ${tx_msg}" && break
fi
done < "${metafile}"
- [[ -n ${error} ]] && println ERROR "${error}" && waitForInput && continue
+ [[ -n ${error} ]] && println ERROR "${error}" && waitToProceed && continue
jq -c . <<< "${tx_msg}" > "${metafile}"
- jq -r . "${metafile}" >&3 && echo
+ jq -r . "${metafile}" && echo
println LOG "Transaction message: ${tx_msg}"
fi
;;
esac
if ! submitPoll; then
- waitForInput && continue
+ waitToProceed && continue
fi
else
echo && println "${FG_YELLOW}Cannot find valid metadata for this transaction${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
else
echo && println "${FG_YELLOW}There are currently no active polls in ${NETWORK_NAME}${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
else
echo && println "${FG_YELLOW}There are currently no polls in ${NETWORK_NAME}${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
;; ###################################################################
esac # pool sub OPERATION
@@ -3435,18 +3556,18 @@ function main {
[[ -z "${offline_tx}" ]] && continue
if [[ ! -f "${offline_tx}" ]]; then
println ERROR "${FG_RED}ERROR${NC}: file not found: ${offline_tx}"
- waitForInput && continue
+ waitToProceed && continue
elif ! offlineJSON=$(jq -erc . "${offline_tx}"); then
println ERROR "${FG_RED}ERROR${NC}: invalid JSON file: ${offline_tx}"
- waitForInput && continue
+ waitToProceed && continue
fi
- if ! otx_type="$(jq -er '.type' <<< ${offlineJSON})"; then println ERROR "${FG_RED}ERROR${NC}: field 'type' not found in: ${offline_tx}" && waitForInput && continue; fi
- if ! otx_date_created="$(jq -er '."date-created"' <<< ${offlineJSON})"; then println ERROR "${FG_RED}ERROR${NC}: field 'date-created' not found in: ${offline_tx}" && waitForInput && continue; fi
- if ! otx_date_expire="$(jq -er '."date-expire"' <<< ${offlineJSON})"; then println ERROR "${FG_RED}ERROR${NC}: field 'date-expire' not found in: ${offline_tx}" && waitForInput && continue; fi
- if ! otx_txFee=$(jq -er '.txFee' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'txFee' not found in: ${offline_tx}" && waitForInput && continue; fi
- if ! otx_txBody=$(jq -er '.txBody' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'txBody' not found in: ${offline_tx}" && waitForInput && continue; fi
+ if ! otx_type="$(jq -er '.type' <<< ${offlineJSON})"; then println ERROR "${FG_RED}ERROR${NC}: field 'type' not found in: ${offline_tx}" && waitToProceed && continue; fi
+ if ! otx_date_created="$(jq -er '."date-created"' <<< ${offlineJSON})"; then println ERROR "${FG_RED}ERROR${NC}: field 'date-created' not found in: ${offline_tx}" && waitToProceed && continue; fi
+ if ! otx_date_expire="$(jq -er '."date-expire"' <<< ${offlineJSON})"; then println ERROR "${FG_RED}ERROR${NC}: field 'date-expire' not found in: ${offline_tx}" && waitToProceed && continue; fi
+ if ! otx_txFee=$(jq -er '.txFee' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'txFee' not found in: ${offline_tx}" && waitToProceed && continue; fi
+ if ! otx_txBody=$(jq -er '.txBody' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'txBody' not found in: ${offline_tx}" && waitToProceed && continue; fi
echo -e "${otx_txBody}" > "${TMP_DIR}"/tx.raw
- [[ $(jq -r '."signed-txBody" | length' <<< ${offlineJSON}) -gt 0 ]] && println ERROR "${FG_RED}ERROR${NC}: transaction already signed, please submit transaction to complete!" && waitForInput && continue
+ [[ $(jq -r '."signed-txBody" | length' <<< ${offlineJSON}) -gt 0 ]] && println ERROR "${FG_RED}ERROR${NC}: transaction already signed, please submit transaction to complete!" && waitToProceed && continue
println DEBUG "Transaction type : ${FG_GREEN}${otx_type}${NC}"
if wallet_name=$(jq -er '."wallet-name"' <<< ${offlineJSON}); then
println DEBUG "Transaction fee : ${FG_LBLUE}$(formatLovelace ${otx_txFee})${NC} ADA, payed by ${FG_GREEN}${wallet_name}${NC}"
@@ -3458,7 +3579,7 @@ function main {
if [[ $(date '+%s' --date="${otx_date_expire}") -lt $(date '+%s') ]]; then
println DEBUG "Expire : ${FG_RED}$(date '+%F %T %Z' --date="${otx_date_expire}")${NC}"
println ERROR "\n${FG_RED}ERROR${NC}: offline transaction expired! please create a new one with long enough Time To Live (TTL)"
- waitForInput && continue
+ waitToProceed && continue
else
println DEBUG "Expire : ${FG_LGRAY}$(date '+%F %T %Z' --date="${otx_date_expire}")${NC}"
fi
@@ -3545,34 +3666,38 @@ function main {
elif [[ ${otx_signing_name} = "Asset "* ]]; then dialog_start_path="${POOL_FOLDER}"
else dialog_start_path="${WALLET_FOLDER}"; fi
fileDialog "\nEnter path to ${otx_signing_name}" "${dialog_start_path}/"
- [[ ! -f "${file}" ]] && println ERROR "${FG_RED}ERROR${NC}: file not found: ${file}" && waitForInput && continue 2
+ [[ ! -f "${file}" ]] && println ERROR "${FG_RED}ERROR${NC}: file not found: ${file}" && waitToProceed && continue 2
if [[ ${file} = "${ASSET_POLICY_SCRIPT_FILENAME}" ]]; then
if ! grep -q "$(_jq '.script.keyHash')" "${file}"; then
println ERROR "${FG_RED}ERROR${NC}: script file provided doesn't match with script hash in offline transaction for: ${otx_signing_name}"
println ERROR "Provided asset script keyHash: $(jq -r '.keyHash' "${file}")"
println ERROR "Transaction asset script keyHash: $(_jq '.script.keyHash')"
- waitForInput && continue 2
+ waitToProceed && continue 2
fi
elif [[ $(jq -er '.description' "${file}" 2>/dev/null) = *"Hardware"* ]]; then
if ! grep -q "${otx_vkey_cborHex:4}" "${file}"; then # strip 5820 prefix
println ERROR "${FG_RED}ERROR${NC}: signing key provided doesn't match with verification key in offline transaction for: ${otx_signing_name}"
println ERROR "Provided hardware signing key's verification cborXPubKeyHex: $(jq -r .cborXPubKeyHex "${file}")"
println ERROR "Transaction verification cborHex: ${otx_vkey_cborHex:4}"
- waitForInput && continue 2
+ waitToProceed && continue 2
fi
else
println ACTION "${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file ${file} --verification-key-file ${TMP_DIR}/tmp.vkey"
- if ! ${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file "${file}" --verification-key-file "${TMP_DIR}"/tmp.vkey; then waitForInput && continue 2; fi
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file "${file}" --verification-key-file "${TMP_DIR}"/tmp.vkey 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during verification key creation!\n${stdout}"; waitToProceed && continue 2
+ fi
if [[ $(jq -r '.type' "${file}") = *"Extended"* ]]; then
println ACTION "${CCLI} ${NETWORK_ERA} key non-extended-key --extended-verification-key-file ${TMP_DIR}/tmp.vkey --verification-key-file ${TMP_DIR}/tmp2.vkey"
- if ! ${CCLI} ${NETWORK_ERA} key non-extended-key --extended-verification-key-file "${TMP_DIR}/tmp.vkey" --verification-key-file "${TMP_DIR}/tmp2.vkey"; then waitForInput && continue 2; fi
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} key non-extended-key --extended-verification-key-file "${TMP_DIR}/tmp.vkey" --verification-key-file "${TMP_DIR}/tmp2.vkey" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during non-extended verification key creation!\n${stdout}"; waitToProceed && continue 2
+ fi
mv -f "${TMP_DIR}/tmp2.vkey" "${TMP_DIR}/tmp.vkey"
fi
if [[ ${otx_vkey_cborHex} != $(jq -r .cborHex "${TMP_DIR}"/tmp.vkey) ]]; then
println ERROR "${FG_RED}ERROR${NC}: signing key provided doesn't match with verification key in offline transaction for: ${otx_signing_name}"
println ERROR "Provided signing key's verification cborHex: $(jq -r .cborHex "${TMP_DIR}"/tmp.vkey)"
println ERROR "Transaction verification cborHex: ${otx_vkey_cborHex}"
- waitForInput && continue 2
+ waitToProceed && continue 2
fi
fi
@@ -3580,8 +3705,8 @@ function main {
tx_sign_files+=( "${file}" )
done
if [[ ${#tx_sign_files[@]} -gt 0 ]]; then
- if ! witnessTx "${TMP_DIR}/tx.raw" "${tx_sign_files[@]}"; then waitForInput && continue; fi
- if ! assembleTx "${TMP_DIR}/tx.raw"; then waitForInput && continue; fi
+ if ! witnessTx "${TMP_DIR}/tx.raw" "${tx_sign_files[@]}"; then waitToProceed && continue; fi
+ if ! assembleTx "${TMP_DIR}/tx.raw"; then waitToProceed && continue; fi
echo
if jq ". += { \"signed-txBody\": $(jq -c . "${tx_signed}") }" <<< "${offlineJSON}" > "${offline_tx}"; then
println "Offline transaction successfully signed"
@@ -3636,7 +3761,7 @@ function main {
println DEBUG "\nFound a match for ${otx_signing_name}, use this file ? : ${FG_LGRAY}${skey_path}${NC}"
select_opt "[y] Yes" "[n] No, continue with manual selection" "[s] Skip"
case $? in
- 0) if ! witnessTx "${TMP_DIR}/tx.raw" "${skey_path}"; then waitForInput && continue 2; fi
+ 0) if ! witnessTx "${TMP_DIR}/tx.raw" "${skey_path}"; then waitToProceed && continue 2; fi
if ! offlineJSON=$(jq ".witness += [{ name: \"${otx_signing_name}\", witnessBody: $(jq -c . "${tx_witness_files[0]}") }]" <<< ${offlineJSON}); then return 1; fi
jq -r . <<< "${offlineJSON}" > "${offline_tx}" # save this witness to disk
continue ;;
@@ -3652,30 +3777,34 @@ function main {
case ${selection} in
0) [[ ${otx_signing_name} = "Pool "* ]] && dialog_start_path="${POOL_FOLDER}" || dialog_start_path="${WALLET_FOLDER}"
fileDialog "Enter path to ${otx_signing_name}" "${dialog_start_path}/"
- [[ ! -f "${file}" ]] && println ERROR "${FG_RED}ERROR${NC}: file not found: ${file}" && waitForInput && continue 2
+ [[ ! -f "${file}" ]] && println ERROR "${FG_RED}ERROR${NC}: file not found: ${file}" && waitToProceed && continue 2
if [[ $(jq -r '.description' "${file}") = *"Hardware"* ]]; then
if ! grep -q "${otx_vkey_cborHex:4}" "${file}"; then # strip 5820 prefix
println ERROR "${FG_RED}ERROR${NC}: signing key provided doesn't match with verification key in offline transaction for: ${otx_signing_name}"
println ERROR "Provided hardware signing key's verification cborXPubKeyHex: $(jq -r .cborXPubKeyHex "${file}")"
println ERROR "Transaction verification cborHex: ${otx_vkey_cborHex:4}"
- waitForInput && continue 2
+ waitToProceed && continue 2
fi
else
println ACTION "${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file ${file} --verification-key-file ${TMP_DIR}/tmp.vkey"
- if ! ${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file "${file}" --verification-key-file "${TMP_DIR}"/tmp.vkey; then waitForInput && continue 2; fi
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} key verification-key --signing-key-file "${file}" --verification-key-file "${TMP_DIR}"/tmp.vkey 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during verification key creation!\n${stdout}"; waitToProceed && continue 2
+ fi
if [[ $(jq -r '.type' "${file}") = *"Extended"* ]]; then
println ACTION "${CCLI} ${NETWORK_ERA} key non-extended-key --extended-verification-key-file ${TMP_DIR}/tmp.vkey --verification-key-file ${TMP_DIR}/tmp2.vkey"
- if ! ${CCLI} ${NETWORK_ERA} key non-extended-key --extended-verification-key-file "${TMP_DIR}/tmp.vkey" --verification-key-file "${TMP_DIR}/tmp2.vkey"; then waitForInput && continue 2; fi
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} key non-extended-key --extended-verification-key-file "${TMP_DIR}/tmp.vkey" --verification-key-file "${TMP_DIR}/tmp2.vkey" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during non-extended verification key creation!\n${stdout}"; waitToProceed && continue 2
+ fi
mv -f "${TMP_DIR}/tmp2.vkey" "${TMP_DIR}/tmp.vkey"
fi
if [[ ${otx_vkey_cborHex} != $(jq -r .cborHex "${TMP_DIR}"/tmp.vkey) ]]; then
println ERROR "${FG_RED}ERROR${NC}: signing key provided doesn't match with verification key in offline transaction for: ${otx_signing_name}"
println ERROR "Provided signing key's verification cborHex: $(jq -r .cborHex "${TMP_DIR}"/tmp.vkey)"
println ERROR "Transaction verification cborHex: ${otx_vkey_cborHex}"
- waitForInput && continue 2
+ waitToProceed && continue 2
fi
fi
- if ! witnessTx "${TMP_DIR}/tx.raw" "${file}"; then waitForInput && continue 2; fi
+ if ! witnessTx "${TMP_DIR}/tx.raw" "${file}"; then waitToProceed && continue 2; fi
if ! offlineJSON=$(jq ".witness += [{ name: \"${otx_signing_name}\", witnessBody: $(jq -c . "${tx_witness_files[0]}") }]" <<< ${offlineJSON}); then return 1; fi
jq -r . <<< "${offlineJSON}" > "${offline_tx}" # save this witness to disk
;;
@@ -3691,7 +3820,7 @@ function main {
jq -r . <<< "$(_jq '.witnessBody')" > "${tx_witness}"
tx_witness_files+=( "${tx_witness}" )
done
- if ! assembleTx "${TMP_DIR}/tx.raw"; then waitForInput && continue; fi
+ if ! assembleTx "${TMP_DIR}/tx.raw"; then waitToProceed && continue; fi
if jq ". += { \"signed-txBody\": $(jq -c . "${tx_signed}") }" <<< "${offlineJSON}" > "${offline_tx}"; then
println "Offline transaction successfully assembled and signed by all signing keys"
println "please move ${offline_tx} back to online node and submit before ${FG_LGRAY}$(date '+%F %T %Z' --date="${otx_date_expire}")${NC}!"
@@ -3702,9 +3831,9 @@ function main {
println "Offline transaction need to be signed by ${FG_LBLUE}$(jq -r '."signing-file" | length' <<< "${offlineJSON}")${NC} signing keys, signed by ${FG_LBLUE}$(jq -r '.witness | length' <<< "${offlineJSON}")${NC} so far!"
fi
;;
- *) println ERROR "${FG_RED}ERROR${NC}: unsupported offline tx type: ${otx_type}" && waitForInput && continue ;;
+ *) println ERROR "${FG_RED}ERROR${NC}: unsupported offline tx type: ${otx_type}" && waitToProceed && continue ;;
esac
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
submit)
clear
@@ -3713,7 +3842,7 @@ function main {
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println ERROR "${FG_RED}ERROR${NC}: CNTools started in offline mode, option not available!"
- waitForInput && continue
+ waitToProceed && continue
fi
echo
fileDialog "Enter path to offline tx file to submit" "${TMP_DIR}/" && echo
@@ -3721,17 +3850,17 @@ function main {
[[ -z "${offline_tx}" ]] && continue
if [[ ! -f "${offline_tx}" ]]; then
println ERROR "${FG_RED}ERROR${NC}: file not found: ${offline_tx}"
- waitForInput && continue
+ waitToProceed && continue
elif ! offlineJSON=$(jq -erc . "${offline_tx}"); then
println ERROR "${FG_RED}ERROR${NC}: invalid JSON file: ${offline_tx}"
- waitForInput && continue
- fi
- if ! otx_type=$(jq -er '.type' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'type' not found in: ${offline_tx}" && waitForInput && continue; fi
- if ! otx_date_created=$(jq -er '."date-created"' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'date-created' not found in: ${offline_tx}" && waitForInput && continue; fi
- if ! otx_date_expire=$(jq -er '."date-expire"' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'date-expire' not found in: ${offline_tx}" && waitForInput && continue; fi
- if ! otx_txFee=$(jq -er '.txFee' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'txFee' not found in: ${offline_tx}" && waitForInput && continue; fi
- if ! otx_signed_txBody=$(jq -er '."signed-txBody"' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'signed-txBody' not found in: ${offline_tx}" && waitForInput && continue; fi
- [[ $(jq 'length' <<< ${otx_signed_txBody}) -eq 0 ]] && println ERROR "${FG_RED}ERROR${NC}: transaction not signed, please sign transaction first!" && waitForInput && continue
+ waitToProceed && continue
+ fi
+ if ! otx_type=$(jq -er '.type' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'type' not found in: ${offline_tx}" && waitToProceed && continue; fi
+ if ! otx_date_created=$(jq -er '."date-created"' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'date-created' not found in: ${offline_tx}" && waitToProceed && continue; fi
+ if ! otx_date_expire=$(jq -er '."date-expire"' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'date-expire' not found in: ${offline_tx}" && waitToProceed && continue; fi
+ if ! otx_txFee=$(jq -er '.txFee' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'txFee' not found in: ${offline_tx}" && waitToProceed && continue; fi
+ if ! otx_signed_txBody=$(jq -er '."signed-txBody"' <<< ${offlineJSON}); then println ERROR "${FG_RED}ERROR${NC}: field 'signed-txBody' not found in: ${offline_tx}" && waitToProceed && continue; fi
+ [[ $(jq 'length' <<< ${otx_signed_txBody}) -eq 0 ]] && println ERROR "${FG_RED}ERROR${NC}: transaction not signed, please sign transaction first!" && waitToProceed && continue
println DEBUG "Transaction type : ${FG_YELLOW}${otx_type}${NC}"
if jq -er '."wallet-name"' &>/dev/null <<< ${offlineJSON}; then
println DEBUG "Transaction fee : ${FG_LBLUE}$(formatLovelace ${otx_txFee})${NC} ADA, payed by ${FG_GREEN}$(jq -r '."wallet-name"' <<< ${offlineJSON})${NC}"
@@ -3742,7 +3871,7 @@ function main {
if [[ $(date '+%s' --date="${otx_date_expire}") -lt $(date '+%s') ]]; then
println DEBUG "Expire : ${FG_RED}$(date '+%F %T %Z' --date="${otx_date_expire}")${NC}"
println ERROR "\n${FG_RED}ERROR${NC}: offline transaction expired! please create a new one with long enough Time To Live (TTL)"
- waitForInput && continue
+ waitToProceed && continue
else
println DEBUG "Expire : ${FG_LGRAY}$(date '+%F %T %Z' --date="${otx_date_expire}")${NC}"
fi
@@ -3794,7 +3923,7 @@ function main {
1) continue ;;
esac
echo -e "${otx_signed_txBody}" > "${tx_signed}"
- if ! submitTx "${tx_signed}"; then waitForInput && continue; fi
+ if ! submitTx "${tx_signed}"; then waitToProceed && continue; fi
if [[ ${otx_type} = "Pool Registration" || ${otx_type} = "Pool Update" ]]; then
if otx_pool_name=$(jq -er '."pool-name"' <<< ${offlineJSON}); then
if ! jq '."pool-reg-cert"' <<< "${offlineJSON}" > "${POOL_FOLDER}/${otx_pool_name}/${POOL_REGCERT_FILENAME}"; then println ERROR "${FG_RED}ERROR${NC}: failed to write pool cert to disk"; fi
@@ -3813,9 +3942,9 @@ function main {
1) : ;;
esac
;;
- *) println ERROR "${FG_RED}ERROR${NC}: unsupported offline tx type: ${otx_type}" && waitForInput && continue ;;
+ *) println ERROR "${FG_RED}ERROR${NC}: unsupported offline tx type: ${otx_type}" && waitToProceed && continue ;;
esac
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
esac # transaction sub OPERATION
done # Transaction loop
@@ -3827,7 +3956,7 @@ function main {
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
if ! command -v sqlite3 >/dev/null; then
println ERROR "${FG_RED}ERROR${NC}: sqlite3 not found!"
- waitForInput && continue
+ waitToProceed && continue
fi
current_epoch=$(getEpoch)
println DEBUG "Current epoch: ${FG_LBLUE}${current_epoch}${NC}\n"
@@ -3838,7 +3967,7 @@ function main {
epoch_enter=${epoch_enter:-10}
if ! isNumber ${epoch_enter}; then
println ERROR "\n${FG_RED}ERROR${NC}: not a number"
- waitForInput && continue
+ waitToProceed && continue
fi
view=1; view_output="${FG_YELLOW}[b] Block View${NC} | [i] Info"
while true; do
@@ -3856,9 +3985,9 @@ function main {
[[ ${ideal_len} -lt 5 ]] && ideal_len=5
luck_len=$(sqlite3 "${BLOCKLOG_DB}" "SELECT LENGTH(max_performance) FROM epochdata WHERE epoch BETWEEN ${first_epoch} and ${current_epoch} ORDER BY LENGTH(max_performance) DESC LIMIT 1;")
[[ $((luck_len+1)) -le 4 ]] && luck_len=4 || luck_len=$((luck_len+1))
- printf '|' >&3; printf "%$((5+6+ideal_len+luck_len+7+9+6+7+6+7+27+2))s" | tr " " "=" >&3; printf '|\n' >&3
- printf "| %-5s | %-6s | %-${ideal_len}s | %-${luck_len}s | ${FG_LBLUE}%-7s${NC} | ${FG_GREEN}%-9s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} |\n" "Epoch" "Leader" "Ideal" "Luck" "Adopted" "Confirmed" "Missed" "Ghosted" "Stolen" "Invalid" >&3
- printf '|' >&3; printf "%$((5+6+ideal_len+luck_len+7+9+6+7+6+7+27+2))s" | tr " " "=" >&3; printf '|\n' >&3
+ printf '|'; printf "%$((5+6+ideal_len+luck_len+7+9+6+7+6+7+27+2))s" | tr " " "="; printf '|\n'
+ printf "| %-5s | %-6s | %-${ideal_len}s | %-${luck_len}s | ${FG_LBLUE}%-7s${NC} | ${FG_GREEN}%-9s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} |\n" "Epoch" "Leader" "Ideal" "Luck" "Adopted" "Confirmed" "Missed" "Ghosted" "Stolen" "Invalid"
+ printf '|'; printf "%$((5+6+ideal_len+luck_len+7+9+6+7+6+7+27+2))s" | tr " " "="; printf '|\n'
while [[ ${current_epoch} -gt ${first_epoch} ]]; do
invalid_cnt=$(sqlite3 "${BLOCKLOG_DB}" "SELECT COUNT(*) FROM blocklog WHERE epoch=${current_epoch} AND status='invalid';" 2>/dev/null)
missed_cnt=$(sqlite3 "${BLOCKLOG_DB}" "SELECT COUNT(*) FROM blocklog WHERE epoch=${current_epoch} AND status='missed';" 2>/dev/null)
@@ -3873,10 +4002,10 @@ function main {
else
epoch_stats[1]="${epoch_stats[1]}%"
fi
- printf "| ${FG_LGRAY}%-5s${NC} | ${FG_LGRAY}%-6s${NC} | ${FG_LGRAY}%-${ideal_len}s${NC} | ${FG_LGRAY}%-${luck_len}s${NC} | ${FG_LBLUE}%-7s${NC} | ${FG_GREEN}%-9s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} |\n" "${current_epoch}" "${leader_cnt}" "${epoch_stats[0]}" "${epoch_stats[1]}" "${adopted_cnt}" "${confirmed_cnt}" "${missed_cnt}" "${ghosted_cnt}" "${stolen_cnt}" "${invalid_cnt}" >&3
+ printf "| ${FG_LGRAY}%-5s${NC} | ${FG_LGRAY}%-6s${NC} | ${FG_LGRAY}%-${ideal_len}s${NC} | ${FG_LGRAY}%-${luck_len}s${NC} | ${FG_LBLUE}%-7s${NC} | ${FG_GREEN}%-9s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} |\n" "${current_epoch}" "${leader_cnt}" "${epoch_stats[0]}" "${epoch_stats[1]}" "${adopted_cnt}" "${confirmed_cnt}" "${missed_cnt}" "${ghosted_cnt}" "${stolen_cnt}" "${invalid_cnt}"
((current_epoch--))
done
- printf '|' >&3; printf "%$((5+6+ideal_len+luck_len+7+9+6+7+6+7+27+2))s" | tr " " "=" >&3; printf '|\n' >&3
+ printf '|'; printf "%$((5+6+ideal_len+luck_len+7+9+6+7+6+7+27+2))s" | tr " " "="; printf '|\n'
else
println OFF "Block Status:\n"
println OFF "Leader - Scheduled to make block at this slot"
@@ -3909,7 +4038,7 @@ function main {
[[ -z "${epoch_enter}" ]] && epoch_enter=${current_epoch}
if [[ $(sqlite3 "${BLOCKLOG_DB}" "SELECT EXISTS(SELECT 1 FROM blocklog WHERE epoch=${epoch_enter} LIMIT 1);" 2>/dev/null) -eq 0 ]]; then
println "No blocks in epoch ${epoch_enter}"
- waitForInput && continue
+ waitToProceed && continue
fi
view=1; view_output="${FG_YELLOW}[1] View 1${NC} | [2] View 2 | [3] View 3 | [i] Info"
while true; do
@@ -3935,11 +4064,11 @@ function main {
fi
[[ ${#epoch_stats[0]} -gt 5 ]] && ideal_len=${#epoch_stats[0]} || ideal_len=5
[[ ${#epoch_stats[1]} -gt 4 ]] && luck_len=${#epoch_stats[1]} || luck_len=4
- printf '|' >&3; printf "%$((6+ideal_len+luck_len+7+9+6+7+6+7+24+2))s" | tr " " "=" >&3; printf '|\n' >&3
- printf "| %-6s | %-${ideal_len}s | %-${luck_len}s | ${FG_LBLUE}%-7s${NC} | ${FG_GREEN}%-9s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} |\n" "Leader" "Ideal" "Luck" "Adopted" "Confirmed" "Missed" "Ghosted" "Stolen" "Invalid" >&3
- printf '|' >&3; printf "%$((6+ideal_len+luck_len+7+9+6+7+6+7+24+2))s" | tr " " "=" >&3; printf '|\n' >&3
- printf "| ${FG_LGRAY}%-6s${NC} | ${FG_LGRAY}%-${ideal_len}s${NC} | ${FG_LGRAY}%-${luck_len}s${NC} | ${FG_LBLUE}%-7s${NC} | ${FG_GREEN}%-9s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} |\n" "${leader_cnt}" "${epoch_stats[0]}" "${epoch_stats[1]}" "${adopted_cnt}" "${confirmed_cnt}" "${missed_cnt}" "${ghosted_cnt}" "${stolen_cnt}" "${invalid_cnt}" >&3
- printf '|' >&3; printf "%$((6+ideal_len+luck_len+7+9+6+7+6+7+24+2))s" | tr " " "=" >&3; printf '|\n' >&3
+ printf '|'; printf "%$((6+ideal_len+luck_len+7+9+6+7+6+7+24+2))s" | tr " " "="; printf '|\n'
+ printf "| %-6s | %-${ideal_len}s | %-${luck_len}s | ${FG_LBLUE}%-7s${NC} | ${FG_GREEN}%-9s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} |\n" "Leader" "Ideal" "Luck" "Adopted" "Confirmed" "Missed" "Ghosted" "Stolen" "Invalid"
+ printf '|'; printf "%$((6+ideal_len+luck_len+7+9+6+7+6+7+24+2))s" | tr " " "="; printf '|\n'
+ printf "| ${FG_LGRAY}%-6s${NC} | ${FG_LGRAY}%-${ideal_len}s${NC} | ${FG_LGRAY}%-${luck_len}s${NC} | ${FG_LBLUE}%-7s${NC} | ${FG_GREEN}%-9s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} | ${FG_RED}%-6s${NC} | ${FG_RED}%-7s${NC} |\n" "${leader_cnt}" "${epoch_stats[0]}" "${epoch_stats[1]}" "${adopted_cnt}" "${confirmed_cnt}" "${missed_cnt}" "${ghosted_cnt}" "${stolen_cnt}" "${invalid_cnt}"
+ printf '|'; printf "%$((6+ideal_len+luck_len+7+9+6+7+6+7+24+2))s" | tr " " "="; printf '|\n'
echo
# print block table
block_cnt=1
@@ -3957,40 +4086,40 @@ function main {
hash_len=$(sqlite3 "${BLOCKLOG_DB}" "SELECT LENGTH(hash) FROM blocklog WHERE epoch=${epoch_enter} ORDER BY LENGTH(hash) DESC LIMIT 1;")
[[ ${hash_len} -lt 4 ]] && hash_len=4
if [[ ${view} -eq 1 ]]; then
- printf '|' >&3; printf "%$((${#leader_cnt}+status_len+block_len+slot_len+slot_in_epoch_len+at_len+17))s" | tr " " "=" >&3; printf '|\n' >&3
- printf "| %-${#leader_cnt}s | %-${status_len}s | %-${block_len}s | %-${slot_len}s | %-${slot_in_epoch_len}s | %-${at_len}s |\n" "#" "Status" "Block" "Slot" "SlotInEpoch" "Scheduled At" >&3
- printf '|' >&3; printf "%$((${#leader_cnt}+status_len+block_len+slot_len+slot_in_epoch_len+at_len+17))s" | tr " " "=" >&3; printf '|\n' >&3
+ printf '|'; printf "%$((${#leader_cnt}+status_len+block_len+slot_len+slot_in_epoch_len+at_len+17))s" | tr " " "="; printf '|\n'
+ printf "| %-${#leader_cnt}s | %-${status_len}s | %-${block_len}s | %-${slot_len}s | %-${slot_in_epoch_len}s | %-${at_len}s |\n" "#" "Status" "Block" "Slot" "SlotInEpoch" "Scheduled At"
+ printf '|'; printf "%$((${#leader_cnt}+status_len+block_len+slot_len+slot_in_epoch_len+at_len+17))s" | tr " " "="; printf '|\n'
while IFS='|' read -r status block slot slot_in_epoch at; do
at=$(TZ="${BLOCKLOG_TZ}" date '+%F %T %Z' --date="${at}")
[[ ${block} -eq 0 ]] && block="-"
- printf "| ${FG_LGRAY}%-${#leader_cnt}s${NC} | ${FG_LGRAY}%-${status_len}s${NC} | ${FG_LGRAY}%-${block_len}s${NC} | ${FG_LGRAY}%-${slot_len}s${NC} | ${FG_LGRAY}%-${slot_in_epoch_len}s${NC} | ${FG_LGRAY}%-${at_len}s${NC} |\n" "${block_cnt}" "${status}" "${block}" "${slot}" "${slot_in_epoch}" "${at}" >&3
+ printf "| ${FG_LGRAY}%-${#leader_cnt}s${NC} | ${FG_LGRAY}%-${status_len}s${NC} | ${FG_LGRAY}%-${block_len}s${NC} | ${FG_LGRAY}%-${slot_len}s${NC} | ${FG_LGRAY}%-${slot_in_epoch_len}s${NC} | ${FG_LGRAY}%-${at_len}s${NC} |\n" "${block_cnt}" "${status}" "${block}" "${slot}" "${slot_in_epoch}" "${at}"
((block_cnt++))
done < <(sqlite3 "${BLOCKLOG_DB}" "SELECT status, block, slot, slot_in_epoch, at FROM blocklog WHERE epoch=${epoch_enter} ORDER BY slot;" 2>/dev/null)
- printf '|' >&3; printf "%$((${#leader_cnt}+status_len+block_len+slot_len+slot_in_epoch_len+at_len+17))s" | tr " " "=" >&3; printf '|\n' >&3
+ printf '|'; printf "%$((${#leader_cnt}+status_len+block_len+slot_len+slot_in_epoch_len+at_len+17))s" | tr " " "="; printf '|\n'
elif [[ ${view} -eq 2 ]]; then
- printf '|' >&3; printf "%$((${#leader_cnt}+status_len+slot_len+size_len+hash_len+14))s" | tr " " "=" >&3; printf '|\n' >&3
- printf "| %-${#leader_cnt}s | %-${status_len}s | %-${slot_len}s | %-${size_len}s | %-${hash_len}s |\n" "#" "Status" "Slot" "Size" "Hash" >&3
- printf '|' >&3; printf "%$((${#leader_cnt}+status_len+slot_len+size_len+hash_len+14))s" | tr " " "=" >&3; printf '|\n' >&3
+ printf '|'; printf "%$((${#leader_cnt}+status_len+slot_len+size_len+hash_len+14))s" | tr " " "="; printf '|\n'
+ printf "| %-${#leader_cnt}s | %-${status_len}s | %-${slot_len}s | %-${size_len}s | %-${hash_len}s |\n" "#" "Status" "Slot" "Size" "Hash"
+ printf '|'; printf "%$((${#leader_cnt}+status_len+slot_len+size_len+hash_len+14))s" | tr " " "="; printf '|\n'
while IFS='|' read -r status slot size hash; do
[[ ${size} -eq 0 ]] && size="-"
[[ -z ${hash} ]] && hash="-"
- printf "| ${FG_LGRAY}%-${#leader_cnt}s${NC} | ${FG_LGRAY}%-${status_len}s${NC} | ${FG_LGRAY}%-${slot_len}s${NC} | ${FG_LGRAY}%-${size_len}s${NC} | ${FG_LGRAY}%-${hash_len}s${NC} |\n" "${block_cnt}" "${status}" "${slot}" "${size}" "${hash}" >&3
+ printf "| ${FG_LGRAY}%-${#leader_cnt}s${NC} | ${FG_LGRAY}%-${status_len}s${NC} | ${FG_LGRAY}%-${slot_len}s${NC} | ${FG_LGRAY}%-${size_len}s${NC} | ${FG_LGRAY}%-${hash_len}s${NC} |\n" "${block_cnt}" "${status}" "${slot}" "${size}" "${hash}"
((block_cnt++))
done < <(sqlite3 "${BLOCKLOG_DB}" "SELECT status, slot, size, hash FROM blocklog WHERE epoch=${epoch_enter} ORDER BY slot;" 2>/dev/null)
- printf '|' >&3; printf "%$((${#leader_cnt}+status_len+slot_len+size_len+hash_len+14))s" | tr " " "=" >&3; printf '|\n' >&3
+ printf '|'; printf "%$((${#leader_cnt}+status_len+slot_len+size_len+hash_len+14))s" | tr " " "="; printf '|\n'
elif [[ ${view} -eq 3 ]]; then
- printf '|' >&3; printf "%$((${#leader_cnt}+status_len+block_len+slot_len+slot_in_epoch_len+at_len+size_len+hash_len+23))s" | tr " " "=" >&3; printf '|\n' >&3
- printf "| %-${#leader_cnt}s | %-${status_len}s | %-${block_len}s | %-${slot_len}s | %-${slot_in_epoch_len}s | %-${at_len}s | %-${size_len}s | %-${hash_len}s |\n" "#" "Status" "Block" "Slot" "SlotInEpoch" "Scheduled At" "Size" "Hash" >&3
- printf '|' >&3; printf "%$((${#leader_cnt}+status_len+block_len+slot_len+slot_in_epoch_len+at_len+size_len+hash_len+23))s" | tr " " "=" >&3; printf '|\n' >&3
+ printf '|'; printf "%$((${#leader_cnt}+status_len+block_len+slot_len+slot_in_epoch_len+at_len+size_len+hash_len+23))s" | tr " " "="; printf '|\n'
+ printf "| %-${#leader_cnt}s | %-${status_len}s | %-${block_len}s | %-${slot_len}s | %-${slot_in_epoch_len}s | %-${at_len}s | %-${size_len}s | %-${hash_len}s |\n" "#" "Status" "Block" "Slot" "SlotInEpoch" "Scheduled At" "Size" "Hash"
+ printf '|'; printf "%$((${#leader_cnt}+status_len+block_len+slot_len+slot_in_epoch_len+at_len+size_len+hash_len+23))s" | tr " " "="; printf '|\n'
while IFS='|' read -r status block slot slot_in_epoch at size hash; do
at=$(TZ="${BLOCKLOG_TZ}" date '+%F %T %Z' --date="${at}")
[[ ${block} -eq 0 ]] && block="-"
[[ ${size} -eq 0 ]] && size="-"
[[ -z ${hash} ]] && hash="-"
- printf "| ${FG_LGRAY}%-${#leader_cnt}s${NC} | ${FG_LGRAY}%-${status_len}s${NC} | ${FG_LGRAY}%-${block_len}s${NC} | ${FG_LGRAY}%-${slot_len}s${NC} | ${FG_LGRAY}%-${slot_in_epoch_len}s${NC} | ${FG_LGRAY}%-${at_len}s${NC} | ${FG_LGRAY}%-${size_len}s${NC} | ${FG_LGRAY}%-${hash_len}s${NC} |\n" "${block_cnt}" "${status}" "${block}" "${slot}" "${slot_in_epoch}" "${at}" "${size}" "${hash}" >&3
+ printf "| ${FG_LGRAY}%-${#leader_cnt}s${NC} | ${FG_LGRAY}%-${status_len}s${NC} | ${FG_LGRAY}%-${block_len}s${NC} | ${FG_LGRAY}%-${slot_len}s${NC} | ${FG_LGRAY}%-${slot_in_epoch_len}s${NC} | ${FG_LGRAY}%-${at_len}s${NC} | ${FG_LGRAY}%-${size_len}s${NC} | ${FG_LGRAY}%-${hash_len}s${NC} |\n" "${block_cnt}" "${status}" "${block}" "${slot}" "${slot_in_epoch}" "${at}" "${size}" "${hash}"
((block_cnt++))
done < <(sqlite3 "${BLOCKLOG_DB}" "SELECT status, block, slot, slot_in_epoch, at, size, hash FROM blocklog WHERE epoch=${epoch_enter} ORDER BY slot;" 2>/dev/null)
- printf '|' >&3; printf "%$((${#leader_cnt}+status_len+block_len+slot_len+slot_in_epoch_len+at_len+size_len+hash_len+23))s" | tr " " "=" >&3; printf '|\n' >&3
+ printf '|'; printf "%$((${#leader_cnt}+status_len+block_len+slot_len+slot_in_epoch_len+at_len+size_len+hash_len+23))s" | tr " " "="; printf '|\n'
elif [[ ${view} -eq 4 ]]; then
println OFF "Block Status:\n"
println OFF "Leader - Scheduled to make block at this slot"
@@ -4022,7 +4151,7 @@ function main {
;;
2) continue ;;
esac
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
backup)
clear
@@ -4040,9 +4169,9 @@ function main {
[[ "${dir}" != */ ]] && backup_path="${dir}/" || backup_path="${dir}"
if [[ ! "${backup_path}" =~ ^/[-0-9A-Za-z_]+ ]]; then
println ERROR "${FG_RED}ERROR${NC}: invalid path, please specify the full path to backup directory (space not allowed)"
- waitForInput && continue
+ waitToProceed && continue
fi
- if ! mkdir -p "${backup_path}"; then println ERROR "${FG_RED}ERROR${NC}: failed to create backup directory:\n${backup_path}" && waitForInput && continue; fi
+ if ! mkdir -p "${backup_path}"; then println ERROR "${FG_RED}ERROR${NC}: failed to create backup directory:\n${backup_path}" && waitToProceed && continue; fi
missing_keys="false"
excluded_files=()
[[ -d "${ASSET_FOLDER}" ]] && asset_out=" and asset ${ASSET_POLICY_SK_FILENAME}" || asset_out=""
@@ -4083,19 +4212,19 @@ function main {
((backup_cnt++))
done < <(find "${item}" -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null | sort -z)
done
- [[ ${backup_cnt} -eq 0 ]] && println "\nNo folders found to include in backup :(" && waitForInput && continue
+ [[ ${backup_cnt} -eq 0 ]] && println "\nNo folders found to include in backup :(" && waitToProceed && continue
echo
if [[ ${#excluded_files[@]} -gt 0 ]]; then
println ACTION "tar ${excluded_files[*]} -cf ${backup_file} ${backup_list[*]}"
- if ! output=$(tar "${excluded_files[@]}" -cf "${backup_file}" "${backup_list[@]}" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: during tarball creation:\n${output}" && waitForInput && continue; fi
+ if ! stdout=$(tar "${excluded_files[@]}" -cf "${backup_file}" "${backup_list[@]}" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: during tarball creation:\n${stdout}" && waitToProceed && continue; fi
println ACTION "gzip ${backup_file}"
- if ! output=$(gzip "${backup_file}" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: gzip error:\n${output}" && waitForInput && continue; fi
+ if ! stdout=$(gzip "${backup_file}" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: gzip error:\n${stdout}" && waitToProceed && continue; fi
backup_file+=".gz"
else
println ACTION "tar -cf ${backup_file} ${backup_list[*]}"
- if ! output=$(tar -cf "${backup_file}" "${backup_list[@]}" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: during tarball creation:\n${output}" && waitForInput && continue; fi
+ if ! stdout=$(tar -cf "${backup_file}" "${backup_list[@]}" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: during tarball creation:\n${stdout}" && waitToProceed && continue; fi
println ACTION "gzip ${backup_file}"
- if ! output=$(gzip "${backup_file}" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: gzip error:\n${output}" && waitForInput && continue; fi
+ if ! stdout=$(gzip "${backup_file}" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: gzip error:\n${stdout}" && waitToProceed && continue; fi
backup_file+=".gz"
while IFS= read -r -d '' wallet; do # check for missing signing keys
wallet_name=$(basename ${wallet})
@@ -4138,9 +4267,9 @@ function main {
backup_file=${file}
if [[ ! -f "${backup_file}" ]]; then
println ERROR "${FG_RED}ERROR${NC}: file not found: ${backup_file}"
- waitForInput && continue
+ waitToProceed && continue
fi
- if ! restore_path="$(mktemp -d "${TMP_DIR}/restore_XXXXXXXXXX")"; then println ERROR "${FG_RED}ERROR${NC}: failed to create restore directory:\n${restore_path}" && waitForInput && continue; fi
+ if ! restore_path="$(mktemp -d "${TMP_DIR}/restore_XXXXXXXXXX")"; then println ERROR "${FG_RED}ERROR${NC}: failed to create restore directory:\n${restore_path}" && waitToProceed && continue; fi
tmp_bkp_file=""
if [ "${backup_file##*.}" = "gpg" ]; then
println DEBUG "Backup GPG encrypted, enter password to decrypt"
@@ -4153,11 +4282,11 @@ function main {
echo
else
println ERROR "\n${FG_RED}ERROR${NC}: password input aborted!"
- waitForInput && continue
+ waitToProceed && continue
fi
fi
println ACTION "tar xfzk ${backup_file} -C ${restore_path}"
- if ! output=$(tar xfzk "${backup_file}" -C "${restore_path}" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: during tarball extraction:\n${output}" && waitForInput && continue; fi
+ if ! stdout=$(tar xfzk "${backup_file}" -C "${restore_path}" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: during tarball extraction:\n${stdout}" && waitToProceed && continue; fi
[[ -n "${tmp_bkp_file}" ]] && mv -f "${tmp_bkp_file}" "${backup_file}.gpg" && rm -f "${backup_file}" # restore original encrypted backup file
restore_source=(
"${restore_path}${WALLET_FOLDER}"
@@ -4176,7 +4305,7 @@ function main {
((restore_cnt++))
done < <(find "${item}" -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null | sort -z)
done
- [[ ${restore_cnt} -eq 0 ]] && println "\nNothing in backup file to restore :(" && waitForInput && continue
+ [[ ${restore_cnt} -eq 0 ]] && println "\nNothing in backup file to restore :(" && waitToProceed && continue
echo
println DEBUG "Continue with restore?"
select_opt "[n] No" "[y] Yes"
@@ -4202,10 +4331,10 @@ function main {
done
if [[ ${source_cnt} -gt 0 ]]; then
archive_dest="${CNODE_HOME}/priv/archive"
- if ! mkdir -p "${archive_dest}"; then println ERROR "${FG_RED}ERROR${NC}: failed to create archive directory:\n${archive_dest}" && waitForInput && continue; fi
+ if ! mkdir -p "${archive_dest}"; then println ERROR "${FG_RED}ERROR${NC}: failed to create archive directory:\n${archive_dest}" && waitToProceed && continue; fi
archive_file="${archive_dest}/archive_$(date '+%Y%m%d%H%M%S').tar.gz"
println ACTION "tar cfz ${archive_file} ${archive_list[*]}"
- if ! output=$(tar cfz "${archive_file}" "${archive_list[@]}" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: during archive/backup:\n${output}" && waitForInput && continue; fi
+ if ! stdout=$(tar cfz "${archive_file}" "${archive_list[@]}" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: during archive/backup:\n${stdout}" && waitToProceed && continue; fi
println DEBUG "An archive of current priv folder has been taken and stored in ${FG_LGRAY}${archive_file}${NC}"
println DEBUG "Please set a password to GPG encrypt the archive"
if getPasswordCust confirm; then # $password variable populated by getPasswordCust function
@@ -4224,13 +4353,13 @@ function main {
unlockFile "${file}"
done < <(find "${dest_path}" -mindepth 1 -maxdepth 1 -type f -print0 2>/dev/null)
println ACTION "cp -rf ${item} $(dirname "${dest_path}")"
- cp -rf "${item}" "$(dirname "${dest_path}")"
+ if ! stdout=$(cp -rf "${item}" "$(dirname "${dest_path}")" 2>&1); then println ERROR "${FG_RED}ERROR${NC}: during retore copy:\n${stdout}" && waitToProceed && continue; fi
done
println "Backup ${FG_LGRAY}$(basename "${backup_file}")${NC} successfully restored!"
;;
2) continue ;;
esac
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
advanced)
@@ -4242,8 +4371,14 @@ function main {
println OFF " Developer & Advanced features\n"\
" ) Metadata - create and optionally post metadata on-chain"\
" ) Multi-Asset - multi-asset nanagement"\
- " ) Delete Keys - Delete all sign/cold keys from CNTools (wallet|pool|asset)"\
+ " ) Delete Keys - delete all sign/cold keys from CNTools (wallet|pool|asset)"\
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+ #println OFF " Developer & Advanced features\n"\
+# " ) Metadata - create and optionally post metadata on-chain"\
+# " ) Multi-Asset - multi-asset nanagement"\
+# " ) Multi-Sig - create a multi-sig/native script wallet"\
+# " ) Delete Keys - delete all sign/cold keys from CNTools (wallet|pool|asset)"\
+# "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println DEBUG " Select Operation\n"
select_opt "[m] Metadata" "[a] Multi-Asset" "[x] Delete Private Keys" "[h] Home"
case $? in
@@ -4252,16 +4387,24 @@ function main {
2) SUBCOMMAND="del-keys" ;;
3) break ;;
esac
+ #select_opt "[m] Metadata" "[a] Multi-Asset" "[s] Multi-Sig" "[x] Delete Private Keys" "[h] Home"
+ #case $? in
+ # 0) SUBCOMMAND="metadata" ;;
+ # 1) SUBCOMMAND="multi-asset" ;;
+ # 2) SUBCOMMAND="multi-sig" ;;
+ # 3) SUBCOMMAND="del-keys" ;;
+ # 4) break ;;
+ #esac
case $SUBCOMMAND in
metadata)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> ADVANCED >> METADATA"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available to pay for transaction fee!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available to pay for transaction fee!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println ERROR "\n${FG_RED}ERROR${NC}: CNTools started in offline mode, option not available!"
- waitForInput && continue
+ waitToProceed && continue
else
if ! selectOpMode; then continue; fi
fi
@@ -4286,7 +4429,7 @@ function main {
metafile="${file}"
if [[ ! -f "${metafile}" ]] || ! jq -er . "${metafile}" &>/dev/null; then
println ERROR "${FG_RED}ERROR${NC}: invalid JSON format or file not found"
- waitForInput && continue
+ waitToProceed && continue
fi
println DEBUG "$(cat "${metafile}")\n"
;;
@@ -4294,11 +4437,11 @@ function main {
getAnswerAnyCust meta_json_url "Enter URL to JSON metadata file"
if [[ ! "${meta_json_url}" =~ https?://.* ]]; then
println ERROR "${FG_RED}ERROR${NC}: invalid URL format"
- waitForInput && continue
+ waitToProceed && continue
fi
if ! curl -sL -m ${CURL_TIMEOUT} -o "${metafile}" ${meta_json_url} || ! jq -er . "${metafile}" &>/dev/null; then
println ERROR "${FG_RED}ERROR${NC}: metadata download failed, please make sure the URL point to a valid JSON file!"
- waitForInput && continue
+ waitToProceed && continue
fi
tput rc && tput ed
println "Metadata file successfully downloaded to: ${FG_LGRAY}${metafile}${NC}"
@@ -4313,14 +4456,12 @@ function main {
DEFAULTEDITOR="$(command -v nano &>/dev/null && echo 'nano' || echo 'vi')"
println OFF "\nPaste or enter the metadata text, opening text editor ${FG_LGRAY}${DEFAULTEDITOR}${NC}"
println OFF "${FG_YELLOW}Please don't change default file path when saving${NC}"
- exec >&6 2>&7 # normal stdout/stderr
- waitForInput "press any key to open ${DEFAULTEDITOR}"
+ waitToProceed "press any key to open ${DEFAULTEDITOR}"
${DEFAULTEDITOR} "${metafile}"
- exec >&8 2>&9 # custom stdout/stderr
if [[ ! -f "${metafile}" ]] || ! jq -er . "${metafile}" &>/dev/null; then
println ERROR "${FG_RED}ERROR${NC}: file not found or invalid JSON format"
println ERROR "File: ${FG_LGRAY}${metafile}${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
tput rc && tput ed
println "Metadata file successfully saved to: ${FG_LGRAY}${metafile}${NC}"
@@ -4337,33 +4478,28 @@ function main {
if [[ ${op_mode} = "online" ]]; then
selectWallet "balance" "${WALLET_PAY_SK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet to pay for metadata transaction fee!" && waitForInput && continue ;;
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitForInput && continue ;;
+ 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet to pay for metadata transaction fee!" && waitToProceed && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitToProceed && continue ;;
esac
else
selectWallet "balance"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet to pay for metadata transaction fee!" && waitForInput && continue ;;
+ 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet to pay for metadata transaction fee!" && waitToProceed && continue ;;
esac
fi
echo
- getBaseAddress ${wallet_name}
- getPayAddress ${wallet_name}
- getBalance ${base_addr}
- base_lovelace=${assets[lovelace]}
- getBalance ${pay_addr}
- pay_lovelace=${assets[lovelace]}
+ getWalletBalance ${wallet_name} true true true true
if [[ ${pay_lovelace} -gt 0 && ${base_lovelace} -gt 0 ]]; then
# Both payment and base address available with funds, let user choose what to use
println DEBUG "Select source wallet address"
@@ -4374,32 +4510,34 @@ function main {
echo
select_opt "[b] Base (default)" "[e] Enterprise" "[Esc] Cancel"
case $? in
- 0) addr="${base_addr}" ;;
- 1) addr="${pay_addr}" ;;
+ 0) addr="${base_addr}"; lovelace=${base_lovelace} ;;
+ 1) addr="${pay_addr}"; lovelace=${pay_lovelace} ;;
2) continue ;;
esac
elif [[ ${pay_lovelace} -gt 0 ]]; then
addr="${pay_addr}"
+ lovelace=${pay_lovelace}
if [[ -n ${wallet_count} && ${wallet_count} -gt ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
println DEBUG "$(printf "%s\t${FG_LBLUE}%s${NC} ADA" "Enterprise Funds :" "$(formatLovelace ${pay_lovelace})")"
fi
elif [[ ${base_lovelace} -gt 0 ]]; then
addr="${base_addr}"
+ lovelace=${base_lovelace}
if [[ -n ${wallet_count} && ${wallet_count} -gt ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
println DEBUG "$(printf "%s\t\t${FG_LBLUE}%s${NC} ADA" "Funds :" "$(formatLovelace ${base_lovelace})")"
fi
else
println ERROR "${FG_RED}ERROR${NC}: no funds available for wallet ${FG_GREEN}${wallet_name}${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
if ! sendMetadata; then
- waitForInput && continue
+ waitToProceed && continue
fi
echo
- if ! verifyTx ${addr}; then waitForInput && continue; fi
+ if ! verifyTx ${addr}; then waitToProceed && continue; fi
echo
println "Metadata successfully posted on-chain"
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
multi-asset)
while true; do # Multi-Asset loop
@@ -4443,13 +4581,13 @@ function main {
policy_name=${policy_name//[^[:alnum:]]/_}
if [[ -z "${policy_name}" ]]; then
println ERROR "${FG_RED}ERROR${NC}: Empty policy name, please retry!"
- waitForInput && continue
+ waitToProceed && continue
fi
policy_folder="${ASSET_FOLDER}/${policy_name}"
echo
if ! mkdir -p "${policy_folder}"; then
println ERROR "${FG_RED}ERROR${NC}: Failed to create directory for policy:\n${policy_folder}"
- waitForInput && continue
+ waitToProceed && continue
fi
# Policy filenames
policy_sk_file="${policy_folder}/${ASSET_POLICY_SK_FILENAME}"
@@ -4459,15 +4597,15 @@ function main {
if [[ $(find "${policy_folder}" -type f -print0 | wc -c) -gt 0 ]]; then
println "${FG_RED}WARN${NC}: A policy ${FG_GREEN}${policy_name}${NC} already exist!"
println " Choose another name or delete the existing one"
- waitForInput && continue
+ waitToProceed && continue
fi
println ACTION "${CCLI} ${NETWORK_ERA} address key-gen --verification-key-file ${policy_vk_file} --signing-key-file ${policy_sk_file}"
- if ! ${CCLI} ${NETWORK_ERA} address key-gen --verification-key-file "${policy_vk_file}" --signing-key-file "${policy_sk_file}"; then
- println ERROR "${FG_RED}ERROR${NC}: failure during policy key creation!"; safeDel "${policy_folder}"; waitForInput && continue
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} address key-gen --verification-key-file "${policy_vk_file}" --signing-key-file "${policy_sk_file}" 2>&1); then
+ println ERROR "${FG_RED}ERROR${NC}: failure during policy key creation!\n${stdout}"; safeDel "${policy_folder}"; waitToProceed && continue
fi
println ACTION "${CCLI} ${NETWORK_ERA} address key-hash --payment-verification-key-file ${policy_vk_file}"
- if ! policy_key_hash=$(${CCLI} ${NETWORK_ERA} address key-hash --payment-verification-key-file "${policy_vk_file}"); then
- println ERROR "${FG_RED}ERROR${NC}: failure during policy verification key hashing!"; safeDel "${policy_folder}"; waitForInput && continue
+ if ! policy_key_hash=$(${CCLI} ${NETWORK_ERA} address key-hash --payment-verification-key-file "${policy_vk_file}" 2>&1); then
+ println ERROR "${FG_RED}ERROR${NC}: failure during policy verification key hashing!\n${policy_key_hash}"; safeDel "${policy_folder}"; waitToProceed && continue
fi
println DEBUG "How long do you want the policy to be valid? (0/blank=unlimited)"
println DEBUG "${FG_YELLOW}Setting a limit will prevent you from minting/burning assets after the policy expire !!\nLeave blank/unlimited if unsure and just press enter${NC}"
@@ -4475,7 +4613,7 @@ function main {
ttl_enter=${ttl_enter:-0}
if ! isNumber ${ttl_enter}; then
println ERROR "\n${FG_RED}ERROR${NC}: invalid TTL number, non digit characters found: ${ttl_enter}"
- safeDel "${policy_folder}"; waitForInput && continue
+ safeDel "${policy_folder}"; waitToProceed && continue
fi
if [[ ${ttl_enter} -eq 0 ]]; then
echo "{ \"keyHash\": \"${policy_key_hash}\", \"type\": \"sig\" }" > "${policy_script_file}"
@@ -4484,8 +4622,8 @@ function main {
echo "{ \"type\": \"all\", \"scripts\": [ { \"slot\": ${ttl}, \"type\": \"before\" }, { \"keyHash\": \"${policy_key_hash}\", \"type\": \"sig\" } ] }" > "${policy_script_file}"
fi
println ACTION "${CCLI} ${NETWORK_ERA} transaction policyid --script-file ${policy_script_file}"
- if ! policy_id=$(${CCLI} ${NETWORK_ERA} transaction policyid --script-file "${policy_script_file}"); then
- println ERROR "${FG_RED}ERROR${NC}: failure during policy ID generation!"; safeDel "${policy_folder}"; waitForInput && continue
+ if ! policy_id=$(${CCLI} ${NETWORK_ERA} transaction policyid --script-file "${policy_script_file}" 2>&1); then
+ println ERROR "${FG_RED}ERROR${NC}: failure during policy ID generation!\n${policy_id}"; safeDel "${policy_folder}"; waitToProceed && continue
fi
echo "${policy_id}" > "${policy_id_file}"
chmod 600 "${policy_folder}/"*
@@ -4494,14 +4632,14 @@ function main {
println "Policy ID : ${FG_LGRAY}${policy_id}${NC}"
println "Policy Expire : $([[ ${ttl_enter} -eq 0 ]] && echo "${FG_LGRAY}unlimited${NC}" || echo "${FG_LGRAY}$(getDateFromSlot ${ttl} '%(%F %T %Z)T')${NC}, ${FG_LGRAY}$(timeLeft $((ttl-$(getSlotTipRef))))${NC} remaining")"
println DEBUG "\nYou can now start minting your custom assets using this Policy!"
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
list-assets)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> ADVANCED >> MULTI-ASSET >> LIST ASSETS"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${ASSET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No policies or assets found!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${ASSET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No policies or assets found!${NC}" && waitToProceed && continue
while IFS= read -r -d '' policy; do
echo
println "Policy Name : ${FG_GREEN}$(basename "${policy}")${NC}"
@@ -4525,18 +4663,18 @@ function main {
println "Asset : ${FG_LGRAY}No assets minted for this policy!${NC}"
fi
done < <(find "${ASSET_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z)
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
show-asset)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> ADVANCED >> MULTI-ASSET >> SHOW ASSET"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${ASSET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No policies or assets found!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${ASSET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No policies or assets found!${NC}" && waitToProceed && continue
println DEBUG "# Select minted asset to show information for"
selectAsset
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
echo
@@ -4573,7 +4711,7 @@ function main {
a_last_action=$(jq -er '.lastAction //"-"' "${asset_file}")
println "Last Updated : ${FG_LGRAY}${a_last_update}${NC}"
println "Last Action : ${FG_LGRAY}${a_last_action}${NC}"
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
decrypt-policy)
clear
@@ -4581,11 +4719,11 @@ function main {
println " >> ADVANCED >> MULTI-ASSET >> DECRYPT / UNLOCK POLICY"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo
- [[ ! $(ls -A "${ASSET_FOLDER}" 2>/dev/null) ]] && println "${FG_YELLOW}No policies available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${ASSET_FOLDER}" 2>/dev/null) ]] && println "${FG_YELLOW}No policies available!${NC}" && waitToProceed && continue
println DEBUG "# Select policy to decrypt"
selectPolicy "encrypted"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
filesUnlocked=0
@@ -4605,7 +4743,7 @@ function main {
println "# Decrypting GPG encrypted policy key"
if ! getPasswordCust; then # $password variable populated by getPasswordCust function
println "\n\n" && println ERROR "${FG_RED}ERROR${NC}: password input aborted!"
- waitForInput && continue
+ waitToProceed && continue
fi
while IFS= read -r -d '' file; do
decryptFile "${file}" "${password}" && \
@@ -4623,7 +4761,7 @@ function main {
println DEBUG "${FG_YELLOW}Policy files are now unprotected${NC}"
println DEBUG "Use 'ADVANCED >> MULTI-ASSET >> ENCRYPT / LOCK POLICY' to re-lock"
fi
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
encrypt-policy)
clear
@@ -4631,11 +4769,11 @@ function main {
println " >> ADVANCED >> MULTI-ASSET >> ENCRYPT / LOCK POLICY"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo
- [[ ! $(ls -A "${ASSET_FOLDER}" 2>/dev/null) ]] && println "${FG_YELLOW}No policies available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${ASSET_FOLDER}" 2>/dev/null) ]] && println "${FG_YELLOW}No policies available!${NC}" && waitToProceed && continue
println DEBUG "# Select policy to encrypt"
selectPolicy "encrypted"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
filesLocked=0
@@ -4645,7 +4783,7 @@ function main {
println DEBUG "# Encrypting policy signing key with GPG"
if ! getPasswordCust confirm; then # $password variable populated by getPasswordCust function
println "\n\n" && println ERROR "${FG_RED}ERROR${NC}: password input aborted!"
- waitForInput && continue
+ waitToProceed && continue
fi
keyFiles=(
"${ASSET_FOLDER}/${policy_name}/${ASSET_POLICY_SK_FILENAME}"
@@ -4661,7 +4799,7 @@ function main {
else
echo
println DEBUG "${FG_YELLOW}NOTE${NC}: found GPG encrypted files in folder, please decrypt/unlock policy files before encrypting"
- waitForInput && continue
+ waitToProceed && continue
fi
echo
println DEBUG "# Write protecting all policy files with 400 permission and if enabled 'chattr +i'"
@@ -4682,26 +4820,26 @@ function main {
println DEBUG "${FG_BLUE}INFO${NC}: policy files are now protected"
println DEBUG "Use 'ADVANCED >> MULTI-ASSET >> DECRYPT / UNLOCK POLICY' to unlock"
fi
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
mint-asset)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> ADVANCED >> MULTI-ASSET >> MINT ASSET"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println ERROR "${FG_RED}ERROR${NC}: CNTools started in offline mode, option not available!"
- waitForInput && continue
+ waitToProceed && continue
else
if ! selectOpMode; then continue; fi
fi
echo
- [[ ! $(ls -A "${ASSET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No policies found!${NC}\n\nPlease first create a policy to mint asset with" && waitForInput && continue
+ [[ ! $(ls -A "${ASSET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No policies found!${NC}\n\nPlease first create a policy to mint asset with" && waitToProceed && continue
println DEBUG "# Select the policy to use when minting the asset"
selectPolicy "all" "${ASSET_POLICY_SK_FILENAME}" "${ASSET_POLICY_VK_FILENAME}" "${ASSET_POLICY_SCRIPT_FILENAME}" "${ASSET_POLICY_ID_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
policy_folder="${ASSET_FOLDER}/${policy_name}"
@@ -4712,7 +4850,7 @@ function main {
policy_id_file="${policy_folder}/${ASSET_POLICY_ID_FILENAME}"
policy_id="$(cat "${policy_id_file}")"
policy_ttl=$(jq -r '.scripts[0].slot //0' "${policy_script_file}")
- [[ ${policy_ttl} -gt 0 && ${policy_ttl} -lt $(getSlotTipRef) ]] && println ERROR "${FG_RED}ERROR${NC}: Policy expired!" && waitForInput && continue
+ [[ ${policy_ttl} -gt 0 && ${policy_ttl} -lt $(getSlotTipRef) ]] && println ERROR "${FG_RED}ERROR${NC}: Policy expired!" && waitToProceed && continue
echo
if [[ $(find "${policy_folder}" -type f -name '*.asset' -print0 | wc -c) -gt 0 ]]; then
println DEBUG "# Assets minted for this Policy\n"
@@ -4734,14 +4872,14 @@ function main {
println DEBUG "\nEnter an existing AssetName to mint more tokens or enter a new name to create a new Asset for this Policy"
fi
getAnswerAnyCust asset_name "Asset Name (empty valid)"
- [[ ${asset_name} =~ ^[^[:alnum:]]$ ]] && println ERROR "${FG_RED}ERROR${NC}: Asset name should only contain alphanummeric chars!" && waitForInput && continue
- [[ ${#asset_name} -gt 32 ]] && println ERROR "${FG_RED}ERROR${NC}: Asset name is limited to 32 chars in length!" && waitForInput && continue
+ [[ ${asset_name} =~ ^[^[:alnum:]]$ ]] && println ERROR "${FG_RED}ERROR${NC}: Asset name should only contain alphanummeric chars!" && waitToProceed && continue
+ [[ ${#asset_name} -gt 32 ]] && println ERROR "${FG_RED}ERROR${NC}: Asset name is limited to 32 chars in length!" && waitToProceed && continue
asset_file="${policy_folder}/${asset_name// /_}.asset"
echo
getAnswerAnyCust assets_to_mint "Amount (commas allowed as thousand separator)"
assets_to_mint="${assets_to_mint//,}"
- [[ -z "${assets_to_mint}" ]] && println ERROR "${FG_RED}ERROR${NC}: Amount empty, please set a valid integer number!" && waitForInput && continue
- if ! isNumber ${assets_to_mint}; then println ERROR "${FG_RED}ERROR${NC}: Invalid number, should be an integer number. Decimals not allowed!" && waitForInput && continue; fi
+ [[ -z "${assets_to_mint}" ]] && println ERROR "${FG_RED}ERROR${NC}: Amount empty, please set a valid integer number!" && waitToProceed && continue
+ if ! isNumber ${assets_to_mint}; then println ERROR "${FG_RED}ERROR${NC}: Invalid number, should be an integer number. Decimals not allowed!" && waitToProceed && continue; fi
[[ -f "${asset_file}" ]] && asset_minted=$(( $(jq -r .minted "${asset_file}") + assets_to_mint )) || asset_minted=${assets_to_mint}
metafile_param=""
println DEBUG "\nDo you want to attach a metadata JSON file to the minting transaction?"
@@ -4750,9 +4888,9 @@ function main {
0) : ;; # do nothing
1) fileDialog "Enter path to metadata JSON file" "${TMP_DIR}/" && echo
metafile=${file}
- [[ -z "${metafile}" ]] && println ERROR "${FG_RED}ERROR${NC}: Metadata file path empty!" && waitForInput && continue
- [[ ! -f "${metafile}" ]] && println ERROR "${FG_RED}ERROR${NC}: File not found: ${metafile}" && waitForInput && continue
- if ! jq -er . "${metafile}"; then println ERROR "${FG_RED}ERROR${NC}: Metadata file not a valid json file!" && waitForInput && continue; fi
+ [[ -z "${metafile}" ]] && println ERROR "${FG_RED}ERROR${NC}: Metadata file path empty!" && waitToProceed && continue
+ [[ ! -f "${metafile}" ]] && println ERROR "${FG_RED}ERROR${NC}: File not found: ${metafile}" && waitToProceed && continue
+ if ! jq -er . "${metafile}"; then println ERROR "${FG_RED}ERROR${NC}: Metadata file not a valid json file!" && waitToProceed && continue; fi
metafile_param="--metadata-json-file ${metafile}"
;;
esac
@@ -4760,28 +4898,23 @@ function main {
if [[ ${op_mode} = "online" ]]; then
selectWallet "balance" "${WALLET_PAY_SK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitForInput && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitToProceed && continue ;;
esac
else
selectWallet "balance"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
fi
echo
- getBaseAddress ${wallet_name}
- getPayAddress ${wallet_name}
- getBalance ${base_addr}
- base_lovelace=${assets[lovelace]}
- getBalance ${pay_addr}
- pay_lovelace=${assets[lovelace]}
+ getWalletBalance ${wallet_name} true true true true
if [[ ${pay_lovelace} -gt 0 && ${base_lovelace} -gt 0 ]]; then
# Both payment and base address available with funds, let user choose what to use
println DEBUG "Select source wallet address"
@@ -4792,33 +4925,35 @@ function main {
echo
select_opt "[b] Base (default)" "[e] Enterprise" "[Esc] Cancel"
case $? in
- 0) addr="${base_addr}" ;;
- 1) addr="${pay_addr}" ;;
+ 0) addr="${base_addr}"; lovelace=${base_lovelace} ;;
+ 1) addr="${pay_addr}" ; lovelace=${pay_lovelace} ;;
2) continue ;;
esac
echo
elif [[ ${pay_lovelace} -gt 0 ]]; then
addr="${pay_addr}"
+ lovelace=${pay_lovelace}
if [[ -n ${wallet_count} && ${wallet_count} -gt ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
println DEBUG "$(printf "%s\t${FG_LBLUE}%s${NC} ADA\n" "Enterprise Funds :" "$(formatLovelace ${pay_lovelace})")"
fi
elif [[ ${base_lovelace} -gt 0 ]]; then
addr="${base_addr}"
+ lovelace=${base_lovelace}
if [[ -n ${wallet_count} && ${wallet_count} -gt ${WALLET_SELECTION_FILTER_LIMIT} ]]; then
println DEBUG "$(printf "%s\t\t${FG_LBLUE}%s${NC} ADA\n" "Funds :" "$(formatLovelace ${base_lovelace})")"
fi
else
println ERROR "${FG_RED}ERROR${NC}: no funds available for wallet ${FG_GREEN}${wallet_name}${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
if ! mintAsset; then
- waitForInput && continue
+ waitToProceed && continue
fi
if [[ ! -f "${asset_file}" ]]; then echo "{}" > "${asset_file}"; fi
assetJSON=$( jq ". += {minted: \"${asset_minted}\", name: \"${asset_name}\", policyID: \"${policy_id}\", assetName: \"$(asciiToHex "${asset_name}")\", policyValidBeforeSlot: \"${policy_ttl}\", lastUpdate: \"$(date -R)\", lastAction: \"Minted $(formatAsset ${assets_to_mint})\"}" < "${asset_file}")
echo -e "${assetJSON}" > "${asset_file}"
echo
- if ! verifyTx ${addr}; then waitForInput && continue; fi
+ if ! verifyTx ${addr}; then waitToProceed && continue; fi
echo
println "Assets successfully minted!"
println "Policy Name : ${FG_GREEN}${policy_name}${NC}"
@@ -4837,17 +4972,17 @@ function main {
println "In Circulation : ${FG_LBLUE}$(formatAsset ${asset_minted})${NC} (local tracking)" ;;
esac
println DEBUG "\n${FG_YELLOW}Please note that it can take a couple of minutes before minted asset show in wallet${NC}"
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
burn-asset)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
println " >> ADVANCED >> MULTI-ASSET >> BURN ASSET"
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitForInput && continue
+ [[ ! $(ls -A "${WALLET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No wallets available!${NC}" && waitToProceed && continue
if [[ ${CNTOOLS_MODE} = "OFFLINE" ]]; then
println ERROR "${FG_RED}ERROR${NC}: CNTools started in offline mode, option not available!"
- waitForInput && continue
+ waitToProceed && continue
else
if ! selectOpMode; then continue; fi
fi
@@ -4856,40 +4991,35 @@ function main {
if [[ ${op_mode} = "online" ]]; then
selectWallet "balance" "${WALLET_PAY_SK_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet for asset burning!" && waitForInput && continue ;;
- 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitForInput && continue ;;
- 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitForInput && continue ;;
+ 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet for asset burning!" && waitToProceed && continue ;;
+ 2) println ERROR "${FG_RED}ERROR${NC}: signing keys encrypted, please decrypt before use!" && waitToProceed && continue ;;
+ 3) println ERROR "${FG_RED}ERROR${NC}: payment and/or stake signing keys missing from wallet!" && waitToProceed && continue ;;
esac
else
selectWallet "balance"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
getWalletType ${wallet_name}
case $? in
- 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet for asset burning!" && waitForInput && continue ;;
+ 0) println ERROR "${FG_RED}ERROR${NC}: please use a CLI wallet for asset burning!" && waitToProceed && continue ;;
esac
fi
# Let user choose asset on wallet to burn, both base and enterprise, fee payed with same address
assets_on_wallet=()
- getBaseAddress ${wallet_name}
- getBalance ${base_addr}
- declare -gA base_assets=(); for idx in "${!assets[@]}"; do base_assets[${idx}]=${assets[${idx}]}; done
+ getWalletBalance ${wallet_name} true true true true
for asset in "${!base_assets[@]}"; do
[[ ${asset} = "lovelace" ]] && continue
IFS='.' read -ra asset_arr <<< "${asset}"
[[ -z ${asset_arr[1]} ]] && asset_ascii_name="" || asset_ascii_name=$(hexToAscii ${asset_arr[1]})
assets_on_wallet+=( "${asset} (${asset_ascii_name}) [base addr]" )
done
- getPayAddress ${wallet_name}
- getBalance ${pay_addr}
- declare -gA pay_assets=(); for idx in "${!assets[@]}"; do pay_assets[${idx}]=${assets[${idx}]}; done
for asset in "${!pay_assets[@]}"; do
[[ ${asset} = "lovelace" ]] && continue
IFS='.' read -ra asset_arr <<< "${asset}"
@@ -4897,7 +5027,7 @@ function main {
assets_on_wallet+=( "${asset} (${asset_ascii_name}) [enterprise addr]" )
done
echo
- [[ ${#assets_on_wallet[@]} -eq 0 ]] && println ERROR "${FG_RED}ERROR${NC}: Wallet doesn't contain any assets!" && waitForInput && continue
+ [[ ${#assets_on_wallet[@]} -eq 0 ]] && println ERROR "${FG_RED}ERROR${NC}: Wallet doesn't contain any assets!" && waitToProceed && continue
println DEBUG "# Select Asset to burn"
select_opt "${assets_on_wallet[@]}" "[Esc] Cancel"
selection=$?
@@ -4910,10 +5040,12 @@ function main {
addr=${base_addr}
wallet_source="base"
curr_asset_amount=${base_assets[${asset}]}
+ lovelace=${base_assets[lovelace]}
else
addr=${pay_addr}
wallet_source="enterprise"
curr_asset_amount=${pay_assets[${asset}]}
+ lovelace=${pay_assets[lovelace]}
fi
echo
@@ -4922,7 +5054,7 @@ function main {
while IFS= read -r -d '' file; do
[[ ${asset_arr[0]} = "$(jq -r .policyID ${file})" ]] && asset_file="${file}" && break
done < <(find "${ASSET_FOLDER}" -mindepth 2 -maxdepth 2 -type f -name '*.asset' -print0)
- [[ -z "${asset_file}" ]] && println ERROR "${FG_RED}ERROR${NC}: Searched all available policies in '${ASSET_FOLDER}' for matching '.asset' file but non found!" && waitForInput && continue
+ [[ -z "${asset_file}" ]] && println ERROR "${FG_RED}ERROR${NC}: Searched all available policies in '${ASSET_FOLDER}' for matching '.asset' file but non found!" && waitToProceed && continue
[[ ${#asset_arr[@]} -eq 1 ]] && asset_name="" || asset_name="${asset_arr[1]}"
@@ -4935,14 +5067,14 @@ function main {
policy_id_file="${policy_folder}/${ASSET_POLICY_ID_FILENAME}"
policy_id="$(cat "${policy_id_file}")"
policy_ttl=$(jq -r '.scripts[0].slot //0' "${policy_script_file}")
- [[ ${policy_ttl} -gt 0 && ${policy_ttl} -lt $(getSlotTipRef) ]] && println ERROR "${FG_RED}ERROR${NC}: Policy expired!" && waitForInput && continue
+ [[ ${policy_ttl} -gt 0 && ${policy_ttl} -lt $(getSlotTipRef) ]] && println ERROR "${FG_RED}ERROR${NC}: Policy expired!" && waitToProceed && continue
# ask amount to burn
println DEBUG "Available assets to burn: ${FG_LBLUE}$(formatAsset "${curr_asset_amount}")${NC}\n"
getAnswerAnyCust assets_to_burn "Amount (commas allowed as thousand separator)"
assets_to_burn="${assets_to_burn//,}"
[[ ${assets_to_burn} = "all" ]] && assets_to_burn=${curr_asset_amount}
- if ! isNumber ${assets_to_burn}; then println ERROR "${FG_RED}ERROR${NC}: Invalid number, should be an integer number. Decimals not allowed!" && waitForInput && continue; fi
- [[ ${assets_to_burn} -gt ${curr_asset_amount} ]] && println ERROR "${FG_RED}ERROR${NC}: Amount exceeding assets in address, you can only burn ${FG_LBLUE}$(formatAsset "${asset_amount}")${NC}" && waitForInput && continue
+ if ! isNumber ${assets_to_burn}; then println ERROR "${FG_RED}ERROR${NC}: Invalid number, should be an integer number. Decimals not allowed!" && waitToProceed && continue; fi
+ [[ ${assets_to_burn} -gt ${curr_asset_amount} ]] && println ERROR "${FG_RED}ERROR${NC}: Amount exceeding assets in address, you can only burn ${FG_LBLUE}$(formatAsset "${asset_amount}")${NC}" && waitToProceed && continue
asset_minted=$(( $(jq -r .minted "${asset_file}") - assets_to_burn ))
# Attach metadata?
metafile_param=""
@@ -4952,23 +5084,23 @@ function main {
0) : ;; # do nothing
1) fileDialog "Enter path to metadata JSON file" "${TMP_DIR}/" && echo
metafile=${file}
- [[ -z "${metafile}" ]] && println ERROR "${FG_RED}ERROR${NC}: Metadata file path empty!" && waitForInput && continue
- [[ ! -f "${metafile}" ]] && println ERROR "${FG_RED}ERROR${NC}: File not found: ${metafile}" && waitForInput && continue
- if ! jq -er . "${metafile}"; then println ERROR "${FG_RED}ERROR${NC}: Metadata file not a valid json file!" && waitForInput && continue; fi
+ [[ -z "${metafile}" ]] && println ERROR "${FG_RED}ERROR${NC}: Metadata file path empty!" && waitToProceed && continue
+ [[ ! -f "${metafile}" ]] && println ERROR "${FG_RED}ERROR${NC}: File not found: ${metafile}" && waitToProceed && continue
+ if ! jq -er . "${metafile}"; then println ERROR "${FG_RED}ERROR${NC}: Metadata file not a valid json file!" && waitToProceed && continue; fi
metafile_param="--metadata-json-file ${metafile}"
;;
esac
echo
# Call burn helper function
if ! burnAsset; then
- waitForInput && continue
+ waitToProceed && continue
fi
- # TODO: Update asset file
+ # Update asset file
if [[ ! -f "${asset_file}" ]]; then echo "{}" > "${asset_file}"; fi
assetJSON=$( jq ". += {minted: \"${asset_minted}\", name: \"$(hexToAscii "${asset_name}")\", policyID: \"${policy_id}\", policyValidBeforeSlot: \"${policy_ttl}\", lastUpdate: \"$(date -R)\", lastAction: \"Burned $(formatAsset ${assets_to_burn})\"}" < "${asset_file}")
echo -e "${assetJSON}" > "${asset_file}"
echo
- if ! verifyTx ${addr}; then waitForInput && continue; fi
+ if ! verifyTx ${addr}; then waitToProceed && continue; fi
echo
println "Assets successfully burned!"
println "Policy Name : ${FG_GREEN}${policy_name}${NC}"
@@ -4988,7 +5120,7 @@ function main {
println "In Circulation : ${FG_LBLUE}$(formatAsset ${asset_minted})${NC} (local tracking)" ;;
esac
println DEBUG "\n${FG_YELLOW}Please note that burned assets can take a couple of minutes before being reflected in wallet${NC}"
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
register-asset)
clear
@@ -4999,13 +5131,13 @@ function main {
if ! cmdAvailable "token-metadata-creator"; then
println ERROR "Please follow instructions on Guild Operators site to download or build the tool:"
println ERROR "${FG_YELLOW}https://cardano-community.github.io/guild-operators/Build/offchain-metadata-tools/${NC}"
- waitForInput && continue
+ waitToProceed && continue
fi
- [[ ! $(ls -A "${ASSET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No policies found!${NC}\n\nPlease first create a policy to use for Cardano Token Registry" && waitForInput && continue
+ [[ ! $(ls -A "${ASSET_FOLDER}" 2>/dev/null) ]] && echo && println "${FG_YELLOW}No policies found!${NC}\n\nPlease first create a policy to use for Cardano Token Registry" && waitToProceed && continue
println DEBUG "# Select the policy to use for Cardano Token Registry"
selectPolicy "all" "${ASSET_POLICY_SK_FILENAME}" "${ASSET_POLICY_SCRIPT_FILENAME}" "${ASSET_POLICY_ID_FILENAME}"
case $? in
- 1) waitForInput; continue ;;
+ 1) waitToProceed; continue ;;
2) continue ;;
esac
policy_folder="${ASSET_FOLDER}/${policy_name}"
@@ -5036,8 +5168,8 @@ function main {
fi
println "Please enter the asset name as part of PolicyID.AssetName to create registry file for, either a previously minted coin or new"
getAnswerAnyCust asset_name "Asset Name (empty valid)"
- [[ ${asset_name} =~ ^[^[:alnum:]]$ ]] && println ERROR "${FG_RED}ERROR${NC}: Asset name should only contain alphanummeric chars!" && waitForInput && continue
- [[ ${#asset_name} -gt 32 ]] && println ERROR "${FG_RED}ERROR${NC}: Asset name is limited to 32 chars in length!" && waitForInput && continue
+ [[ ${asset_name} =~ ^[^[:alnum:]]$ ]] && println ERROR "${FG_RED}ERROR${NC}: Asset name should only contain alphanummeric chars!" && waitToProceed && continue
+ [[ ${#asset_name} -gt 32 ]] && println ERROR "${FG_RED}ERROR${NC}: Asset name is limited to 32 chars in length!" && waitToProceed && continue
asset_file="${policy_folder}/${asset_name}.asset"
echo
sequence_number=0
@@ -5051,21 +5183,21 @@ function main {
fi
println DEBUG "# Enter metadata (optional fields can be left empty)"
getAnswerAnyCust meta_name "Name [${FG_RED}required${NC}] (Max. 50 chars) "
- [[ -z ${meta_name} || ${#meta_name} -gt 50 ]] && println ERROR "\n${FG_RED}ERROR${NC}: Metadata name is a required field and limited to 50 chars in length!" && waitForInput && continue
+ [[ -z ${meta_name} || ${#meta_name} -gt 50 ]] && println ERROR "\n${FG_RED}ERROR${NC}: Metadata name is a required field and limited to 50 chars in length!" && waitToProceed && continue
getAnswerAnyCust meta_desc "Description [${FG_RED}required${NC}] (Max. 500 chars)"
- [[ -z ${meta_desc} || ${#meta_desc} -gt 500 ]] && println ERROR "\n${FG_RED}ERROR${NC}: Metadata description is a required field and limited to 500 chars in length!" && waitForInput && continue
+ [[ -z ${meta_desc} || ${#meta_desc} -gt 500 ]] && println ERROR "\n${FG_RED}ERROR${NC}: Metadata description is a required field and limited to 500 chars in length!" && waitToProceed && continue
getAnswerAnyCust meta_ticker "Ticker [${FG_YELLOW}optional${NC}] (3-9 chars) "
- [[ -n ${meta_ticker} && ( ${#meta_ticker} -lt 3 || ${#meta_ticker} -gt 9 ) ]] && println ERROR "\n${FG_RED}ERROR${NC}: Metadata ticker is limited to 3-9 chars in length!" && waitForInput && continue
+ [[ -n ${meta_ticker} && ( ${#meta_ticker} -lt 3 || ${#meta_ticker} -gt 9 ) ]] && println ERROR "\n${FG_RED}ERROR${NC}: Metadata ticker is limited to 3-9 chars in length!" && waitToProceed && continue
getAnswerAnyCust meta_url "URL [${FG_YELLOW}optional${NC}] (Max. 250 chars)"
- [[ -n ${meta_url} && ( ! ${meta_url} =~ https://.* || ${#meta_url} -gt 250 ) ]] && println ERROR "\n${FG_RED}ERROR${NC}: Invalid metadata URL format or greater than 250 char limit!" && waitForInput && continue
+ [[ -n ${meta_url} && ( ! ${meta_url} =~ https://.* || ${#meta_url} -gt 250 ) ]] && println ERROR "\n${FG_RED}ERROR${NC}: Invalid metadata URL format or greater than 250 char limit!" && waitToProceed && continue
getAnswerAnyCust meta_decimals "Decimals [${FG_YELLOW}optional${NC}]"
- [[ -n ${meta_decimals} ]] && ! isNumber ${meta_decimals} && println ERROR "\n${FG_RED}ERROR${NC}: Invalid decimal number" && waitForInput && continue
+ [[ -n ${meta_decimals} ]] && ! isNumber ${meta_decimals} && println ERROR "\n${FG_RED}ERROR${NC}: Invalid decimal number" && waitToProceed && continue
fileDialog "Logo/Icon [${FG_YELLOW}optional${NC}] (PNG, <64kb) " "${TMP_DIR}/"
meta_logo="${file}"
if [[ -n ${meta_logo} ]]; then
- [[ ! -f ${meta_logo} ]] && println ERROR "\n${FG_RED}ERROR${NC}: Logo not found!" && waitForInput && continue
- [[ $(wc -c ${meta_logo} | cut -d' ' -f1) -gt 64000 ]] && println ERROR "\n${FG_RED}ERROR${NC}: Logo more than 64kb in size!" && waitForInput && continue
- [[ $(file -b ${meta_logo}) != "PNG"* ]] && println ERROR "\n${FG_RED}ERROR${NC}: Logo not of PNG image type!" && waitForInput && continue
+ [[ ! -f ${meta_logo} ]] && println ERROR "\n${FG_RED}ERROR${NC}: Logo not found!" && waitToProceed && continue
+ [[ $(wc -c ${meta_logo} | cut -d' ' -f1) -gt 64000 ]] && println ERROR "\n${FG_RED}ERROR${NC}: Logo more than 64kb in size!" && waitToProceed && continue
+ [[ $(file -b ${meta_logo}) != "PNG"* ]] && println ERROR "\n${FG_RED}ERROR${NC}: Logo not of PNG image type!" && waitToProceed && continue
fi
asset_subject="${policy_id}$(asciiToHex "${asset_name}")"
@@ -5083,33 +5215,33 @@ function main {
[[ -n ${meta_decimals} && ${meta_decimals} -gt 0 ]] && cmd_args+=( "--decimals" "${meta_decimals}" )
[[ -n ${meta_logo} ]] && cmd_args+=( "--logo" "${meta_logo}" )
- pushd ${policy_folder} &>/dev/null || { println ERROR "\n${FG_RED}ERROR${NC}: unable to change directory to: ${policy_folder}" && waitForInput && continue; }
+ pushd ${policy_folder} &>/dev/null || { println ERROR "\n${FG_RED}ERROR${NC}: unable to change directory to: ${policy_folder}" && waitToProceed && continue; }
# Create JSON draft
println DEBUG false "\nCreating Cardano Metadata Registry JSON draft file ..."
- ! meta_file=$(token-metadata-creator "${cmd_args[@]}" 2>&1) && println ERROR "\n${FG_RED}ERROR${NC}: failure during token-metadata-creator draft:\n${meta_file}" && popd >/dev/null && waitForInput && continue
+ ! meta_file=$(token-metadata-creator "${cmd_args[@]}" 2>&1) && println ERROR "\n${FG_RED}ERROR${NC}: failure during token-metadata-creator draft:\n${meta_file}" && popd >/dev/null && waitToProceed && continue
println DEBUG " ${FG_GREEN}OK${NC}!"
# Update the sequence number if needed
if [[ ${sequence_number} -ne 0 ]]; then
println DEBUG false "Updating sequence number to ${FG_LBLUE}${sequence_number}${NC} ..."
- ! sed -i "s/\"sequenceNumber\":\ .*,/\"sequenceNumber\":\ ${sequence_number},/g" ${meta_file} && popd >/dev/null && waitForInput && continue
+ ! sed -i "s/\"sequenceNumber\":\ .*,/\"sequenceNumber\":\ ${sequence_number},/g" ${meta_file} && popd >/dev/null && waitToProceed && continue
println DEBUG " ${FG_GREEN}OK${NC}!"
fi
# Signing draft file with policy signing key
println DEBUG false "Signing draft file with policy signing key ..."
- ! meta_file=$(token-metadata-creator entry ${asset_subject} -a "${policy_sk_file}" 2>&1) && println ERROR "\n${FG_RED}ERROR${NC}: failure during token-metadata-creator signing:\n${meta_file}" && popd >/dev/null && waitForInput && continue
+ ! meta_file=$(token-metadata-creator entry ${asset_subject} -a "${policy_sk_file}" 2>&1) && println ERROR "\n${FG_RED}ERROR${NC}: failure during token-metadata-creator signing:\n${meta_file}" && popd >/dev/null && waitToProceed && continue
println DEBUG " ${FG_GREEN}OK${NC}!"
# Finalizing the draft file
println DEBUG false "Finalizing the draft file ..."
- ! meta_file=$(token-metadata-creator entry ${asset_subject} --finalize 2>&1) && println ERROR "\n${FG_RED}ERROR${NC}: failure during token-metadata-creator finalize:\n${meta_file}" && popd >/dev/null && waitForInput && continue
+ ! meta_file=$(token-metadata-creator entry ${asset_subject} --finalize 2>&1) && println ERROR "\n${FG_RED}ERROR${NC}: failure during token-metadata-creator finalize:\n${meta_file}" && popd >/dev/null && waitToProceed && continue
println DEBUG " ${FG_GREEN}OK${NC}!"
# Validating the final metadata registry submission file
println DEBUG false "Validating the final metadata registry submission file ..."
- ! output=$(token-metadata-creator validate ${meta_file} 2>&1) && println ERROR "\n${FG_RED}ERROR${NC}: failure during token-metadata-creator validation:\n${output}" && popd >/dev/null && waitForInput && continue
+ ! output=$(token-metadata-creator validate ${meta_file} 2>&1) && println ERROR "\n${FG_RED}ERROR${NC}: failure during token-metadata-creator validation:\n${output}" && popd >/dev/null && waitToProceed && continue
println DEBUG " ${FG_GREEN}OK${NC}!"
popd &>/dev/null || println ERROR "\n${FG_RED}ERROR${NC}: unable to return to previous directory!"
@@ -5134,12 +5266,113 @@ function main {
;;
esac
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
esac # advanced >> multi-asset sub OPERATION
done # Multi-Asset loop
;; ###################################################################
+ multi-sig)
+ clear
+ println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+ println " >> ADVANCED >> MULTI-SIG"
+ println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+ echo
+ getAnswerAnyCust ms_wallet_name "Name of multi-sig wallet"
+ # Remove unwanted characters from wallet name
+ ms_wallet_name=${ms_wallet_name//[^[:alnum:]]/_}
+ if [[ -z "${ms_wallet_name}" ]]; then
+ println ERROR "${FG_RED}ERROR${NC}: Empty wallet name, please retry!"
+ waitToProceed && continue
+ fi
+ echo
+ if ! mkdir -p "${WALLET_FOLDER}/${ms_wallet_name}"; then
+ println ERROR "${FG_RED}ERROR${NC}: Failed to create directory for wallet:\n${WALLET_FOLDER}/${ms_wallet_name}"
+ waitToProceed && continue
+ fi
+ # Wallet key filenames
+ ms_stake_vk_file="${WALLET_FOLDER}/${ms_wallet_name}/${WALLET_STAKE_VK_FILENAME}"
+ ms_stake_sk_file="${WALLET_FOLDER}/${ms_wallet_name}/${WALLET_STAKE_SK_FILENAME}"
+ ms_pay_script_file="${WALLET_FOLDER}/${ms_wallet_name}/${WALLET_PAY_SCRIPT_FILENAME}"
+ if [[ $(find "${WALLET_FOLDER}/${ms_wallet_name}" -type f -print0 | wc -c) -gt 0 ]]; then
+ println "${FG_RED}WARN${NC}: A wallet ${FG_GREEN}${ms_wallet_name}${NC} already exists"
+ println " Choose another name or delete the existing one"
+ waitToProceed && continue
+ fi
+ declare -gA key_hashes=() # key hashes as keys to assosiative array to act as a set
+ unset timelock_after
+ println OFF "Select wallet(s) / payment credentials (key hash) to include in multi-sig wallet"
+ while true; do
+ println DEBUG "\nSelect wallet or manually enter credential?"
+ select_opt "[w] Wallet" "[c] Payment Credential" "[Esc] Cancel"
+ echo
+ case $? in
+ 0) selectWallet "balance" "${WALLET_PAY_VK_FILENAME}"
+ case $? in
+ 1) waitToProceed; continue ;;
+ 2) continue ;;
+ esac
+ getCredentials ${wallet_name}
+ [[ -z ${pay_cred} ]] && println ERROR "${FG_RED}ERROR${NC}: wallet payment credentials not set!" && waitToProceed && continue
+ key_hashes[${pay_cred}]=1
+ ;;
+ 1) getAnswerAnyCust pay_cred "Payment Credential (key hash)"
+ [[ ${#pay_cred} -ne 56 ]] && println ERROR "${FG_RED}ERROR${NC}: invalid payment credential entered!" && waitToProceed && continue
+ key_hashes[${pay_cred}]=1
+ ;;
+ 2) safeDel "${WALLET_FOLDER}/${ms_wallet_name}"; continue 2 ;;
+ esac
+ println DEBUG "\nMulti-Sig size: ${#key_hashes[@]} - Add more wallets / credentials to multi-sig?"
+ select_opt "[n] No" "[y] Yes" "[Esc] Cancel"
+ case $? in
+ 0) break ;;
+ 1) : ;;
+ 2) safeDel "${WALLET_FOLDER}/${ms_wallet_name}"; continue 2 ;;
+ esac
+ done
+ println DEBUG "\n${#key_hashes[@]} wallets / credentials added to multi-sig, how many are required to witness the transaction?"
+ getAnswerAnyCust required_sig_cnt "Required signatures"
+ if ! isNumber ${required_sig_cnt} || [[ ${required_sig_cnt} -lt 1 || ${required_sig_cnt} -gt ${#key_hashes[@]} ]]; then
+ println ERROR "\n${FG_RED}ERROR${NC}: invalid signature count entered, must be above 1 and max ${#key_hashes[@]}"; safeDel "${WALLET_FOLDER}/${ms_wallet_name}"; waitToProceed; continue
+ fi
+ println DEBUG "\nAdd time lock to multi-sig wallet by only allowing spending from wallet after a certain epoch start?"
+ select_opt "[n] No" "[y] Yes" "[Esc] Cancel"
+ case $? in
+ 0) : ;;
+ 1) getAnswerAnyCust epoch_no "Epoch"
+ if ! isNumber ${epoch_no}; then println ERROR "${FG_RED}ERROR${NC}: invalid epoch number entered!"; safeDel "${WALLET_FOLDER}/${ms_wallet_name}"; waitToProceed; continue; fi
+ timelock_after=$(getEpochStart ${epoch_no})
+ ;;
+ 2) safeDel "${WALLET_FOLDER}/${ms_wallet_name}"; continue ;;
+ esac
+ # build multi-sig script
+ jsonscript=$(jq -n --argjson req_sig "${required_sig_cnt}" '{type:"atLeast",required:$req_sig,scripts:[]}')
+ for sig in "${!key_hashes[@]}"; do
+ jsonscript=$(jq --arg sig "${sig}" '.scripts += [{type:"sig",keyHash:$sig}]' <<< "${jsonscript}")
+ done
+ if [[ -n ${timelock_after} ]]; then
+ jsonscript=$(jq -n --argjson after "${timelock_after}" --argjson sig_script "${jsonscript}" '{type:"all",scripts:[{type:"after",slot:$after},$sig_script]}')
+ fi
+ if ! stdout=$(jq -e . <<< "${jsonscript}" > "${ms_pay_script_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during script file creation!\n${stdout}"; safeDel "${WALLET_FOLDER}/${ms_wallet_name}"; waitToProceed && continue
+ fi
+ println ACTION "${CCLI} ${NETWORK_ERA} stake-address key-gen --verification-key-file ${ms_stake_vk_file} --signing-key-file ${ms_stake_sk_file}"
+ if ! stdout=$(${CCLI} ${NETWORK_ERA} stake-address key-gen --verification-key-file "${ms_stake_vk_file}" --signing-key-file "${ms_stake_sk_file}" 2>&1); then
+ println ERROR "\n${FG_RED}ERROR${NC}: failure during stake key creation!\n${stdout}"; safeDel "${WALLET_FOLDER}/${ms_wallet_name}"; waitToProceed && continue
+ fi
+ chmod 600 "${WALLET_FOLDER}/${ms_wallet_name}/"*
+ getBaseAddress ${ms_wallet_name}
+ getPayScriptAddress ${ms_wallet_name}
+ getRewardAddress ${ms_wallet_name}
+ echo
+ println "New Multi-Sig Wallet : ${FG_GREEN}${ms_wallet_name}${NC}"
+ println "Address : ${FG_LGRAY}${base_addr}${NC}"
+ println "Script Address : ${FG_LGRAY}${pay_script_addr}${NC}"
+ println "Reward Address : ${FG_LGRAY}${reward_addr}${NC}"
+ println DEBUG "\nYou can now send and receive ADA using the above 'Address' or 'Script Address'."
+ println DEBUG "Note that Script Address will not take part in staking."
+ waitToProceed && continue
+ ;; ###################################################################
del-keys)
clear
println DEBUG "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
@@ -5190,7 +5423,7 @@ function main {
else
println "\n${FG_LBLUE}${key_del_cnt}${NC} private key(s) found and deleted!"
fi
- waitForInput && continue
+ waitToProceed && continue
;; ###################################################################
esac # advanced sub OPERATION
done # Advanced loop
diff --git a/scripts/cnode-helper-scripts/env b/scripts/cnode-helper-scripts/env
index 704e3ba71..1079b15b4 100644
--- a/scripts/cnode-helper-scripts/env
+++ b/scripts/cnode-helper-scripts/env
@@ -49,11 +49,15 @@
#WALLET_PAY_SK_FILENAME="payment.skey"
#WALLET_HW_PAY_SK_FILENAME="payment.hwsfile"
#WALLET_PAY_ADDR_FILENAME="payment.addr"
+#WALLET_PAY_SCRIPT_FILENAME="payment.script"
+#WALLET_PAY_SCRIPT_ADDR_FILENAME="payment-script.addr"
+#WALLET_PAY_CRED_FILENAME="payment.cred"
#WALLET_BASE_ADDR_FILENAME="base.addr"
#WALLET_STAKE_VK_FILENAME="stake.vkey"
#WALLET_STAKE_SK_FILENAME="stake.skey"
#WALLET_HW_STAKE_SK_FILENAME="stake.hwsfile"
#WALLET_STAKE_ADDR_FILENAME="reward.addr"
+#WALLET_STAKE_CRED_FILENAME="stake.cred"
#WALLET_STAKE_CERT_FILENAME="stake.cert"
#WALLET_STAKE_DEREG_FILENAME="stake.dereg"
#WALLET_DELEGCERT_FILENAME="delegation.cert"
@@ -764,11 +768,34 @@ slotInterval() {
echo "(${SLOT_LENGTH} / ${ACTIVE_SLOTS_COEFF}) + 0.5" | bc -l | awk '{printf "%.0f\n", $1}'
}
+# Description : Get current protocol params from either node or Koios
+# Error codes:
+# 1 : CLI - node socket not available
+# 2 : CLI - node response not valid json
+# 3 : Koios - general error
getProtocolParams() {
- PROT_PARAMS="$(${CCLI} ${NETWORK_ERA} query protocol-parameters ${NETWORK_IDENTIFIER} 2>/dev/null)"
- read -ra PROT_PARAMS_VERSION <<<"$(jq -r '[ .protocolVersion.major //0, .protocolVersion.minor //0]| @tsv' <<<"${PROT_PARAMS}" 2>/dev/null)"
- PROT_MAJOR=${PROT_PARAMS_VERSION[0]}
- PROT_MINOR=${PROT_PARAMS_VERSION[1]}
+ if [[ -n ${KOIOS_API} ]]; then
+ [[ $(type -t println) = function ]] && println ACTION "curl -sSL -f -X GET -H \"accept: application/json\" ${KOIOS_API}/cli_protocol_params"
+ if ! PROT_PARAMS=$(curl -sSL -f -X GET -H "accept: application/json" "${KOIOS_API}/cli_protocol_params" 2>&1); then
+ return 3
+ fi
+ else
+ PROT_PARAMS="$(${CCLI} ${NETWORK_ERA} query protocol-parameters ${NETWORK_IDENTIFIER} 2>&1)"
+ if grep -q "Network.Socket.connect" <<< "${PROT_PARAMS}"; then
+ return 1
+ elif [[ -z "${PROT_PARAMS}" ]] || ! jq -er . <<< "${PROT_PARAMS}" &>/dev/null; then
+ return 2
+ fi
+ fi
+ # Set a collection of commonly used values
+ read -r PROT_MAJOR PROT_MINOR KEY_DEPOSIT POOL_DEPOSIT MIN_POOL_COST POOL_RETIRE_MAX_EPOCH <<<"$(jq -r '[
+ .protocolVersion.major //0,
+ .protocolVersion.minor //0,
+ .stakeAddressDeposit //0,
+ .stakePoolDeposit //0,
+ .minPoolCost //0,
+ .poolRetireMaxEpoch //0
+ ] | @tsv' <<<"${PROT_PARAMS}" 2>/dev/null)"
PROT_VERSION="${PROT_MAJOR}.${PROT_MINOR}"
[[ ${PROT_MAJOR} -eq 0 ]] && return 1 || return 0
}
@@ -822,11 +849,15 @@ set_default_vars() {
[[ -z ${WALLET_PAY_SK_FILENAME} ]] && WALLET_PAY_SK_FILENAME="payment.skey"
[[ -z ${WALLET_HW_PAY_SK_FILENAME} ]] && WALLET_HW_PAY_SK_FILENAME="payment.hwsfile"
[[ -z ${WALLET_PAY_ADDR_FILENAME} ]] && WALLET_PAY_ADDR_FILENAME="payment.addr"
+ [[ -z ${WALLET_PAY_SCRIPT_FILENAME} ]] && WALLET_PAY_SCRIPT_FILENAME="payment.script"
+ [[ -z ${WALLET_PAY_SCRIPT_ADDR_FILENAME} ]] && WALLET_PAY_SCRIPT_ADDR_FILENAME="payment-script.addr"
+ [[ -z ${WALLET_PAY_CRED_FILENAME} ]] && WALLET_PAY_CRED_FILENAME="payment.cred"
[[ -z ${WALLET_BASE_ADDR_FILENAME} ]] && WALLET_BASE_ADDR_FILENAME="base.addr"
[[ -z ${WALLET_STAKE_VK_FILENAME} ]] && WALLET_STAKE_VK_FILENAME="stake.vkey"
[[ -z ${WALLET_STAKE_SK_FILENAME} ]] && WALLET_STAKE_SK_FILENAME="stake.skey"
[[ -z ${WALLET_HW_STAKE_SK_FILENAME} ]] && WALLET_HW_STAKE_SK_FILENAME="stake.hwsfile"
[[ -z ${WALLET_STAKE_ADDR_FILENAME} ]] && WALLET_STAKE_ADDR_FILENAME="reward.addr"
+ [[ -z ${WALLET_STAKE_CRED_FILENAME} ]] && WALLET_STAKE_CRED_FILENAME="stake.cred"
[[ -z ${WALLET_STAKE_CERT_FILENAME} ]] && WALLET_STAKE_CERT_FILENAME="stake.cert"
[[ -z ${WALLET_STAKE_DEREG_FILENAME} ]] && WALLET_STAKE_DEREG_FILENAME="stake.dereg"
[[ -z ${WALLET_DELEGCERT_FILENAME} ]] && WALLET_DELEGCERT_FILENAME="delegation.cert"
@@ -1112,7 +1143,7 @@ if [[ ${OFFLINE_MODE} = "N" && ! -S ${CARDANO_NODE_SOCKET_PATH} ]]; then
return 2
fi
-if [[ ${OFFLINE_MODE} = "N" ]] && ! getProtocolParams; then
+if [[ ${OFFLINE_MODE} = "N" && -z ${KOIOS_API} ]] && ! getProtocolParams; then
echo -e "${FG_RED}Failed to query protocol-parameters from node, not yet fully started?${NC}"
return 2
fi
diff --git a/scripts/cnode-helper-scripts/guild-deploy.sh b/scripts/cnode-helper-scripts/guild-deploy.sh
index 08d4243e9..4e0b8a60f 100755
--- a/scripts/cnode-helper-scripts/guild-deploy.sh
+++ b/scripts/cnode-helper-scripts/guild-deploy.sh
@@ -36,7 +36,7 @@ PARENT="$(dirname $0)"
get_answer() {
printf "%s (yes/no): " "$*" >&2; read -r answer
- while :
+ while :
do
case $answer in
[Yy]*)
@@ -206,11 +206,11 @@ os_dependencies() {
pkgmgrcmd="env NEEDRESTART_MODE=a env DEBIAN_FRONTEND=noninteractive env DEBIAN_PRIORITY=critical apt-get"
libncurses_pkg="libncursesw5"
[[ -f /etc/debian_version ]] && grep -q trixie /etc/debian_version && libncurses_pkg="libncursesw6"
- pkg_list="python3 pkg-config libssl-dev ${libncurses_pkg} libtinfo-dev systemd libsystemd-dev libsodium-dev tmux git jq libtool bc gnupg aptitude libtool secure-delete iproute2 tcptraceroute sqlite3 bsdmainutils libusb-1.0-0-dev libudev-dev unzip llvm clang libnuma-dev libpq-dev build-essential libffi-dev libgmp-dev zlib1g-dev make g++ autoconf automake liblmdb-dev procps"
+ pkg_list="python3 pkg-config libssl-dev ${libncurses_pkg} libtinfo-dev systemd libsystemd-dev libsodium-dev tmux git jq libtool bc gnupg aptitude libtool secure-delete iproute2 tcptraceroute sqlite3 bsdmainutils libusb-1.0-0-dev libudev-dev unzip llvm clang libnuma-dev libpq-dev build-essential libffi-dev libgmp-dev zlib1g-dev make g++ autoconf automake liblmdb-dev procps xxd"
elif [[ "${OS_ID}" =~ rhel ]] || [[ "${OS_ID}" =~ fedora ]] || [[ "${DISTRO}" =~ Fedora ]]; then
#CentOS/RHEL/Fedora/RockyLinux
pkgmgrcmd="yum"
- pkg_list="python3 coreutils ncurses-devel ncurses-libs openssl-devel systemd systemd-devel libsodium-devel tmux git jq gnupg2 libtool iproute bc traceroute sqlite util-linux xz wget unzip procps-ng llvm clang numactl-devel libffi-devel gmp-devel zlib-devel make gcc-c++ autoconf udev lmdb-devel"
+ pkg_list="python3 coreutils ncurses-devel ncurses-libs openssl-devel systemd systemd-devel libsodium-devel tmux git jq gnupg2 libtool iproute bc traceroute sqlite util-linux xz wget unzip procps-ng llvm clang numactl-devel libffi-devel gmp-devel zlib-devel make gcc-c++ autoconf udev lmdb-devel xxd"
if [[ "${VERSION_ID}" == "2" ]] ; then
#AmazonLinux2
pkg_list="${pkg_list} libusb ncurses-compat-libs pkgconfig srm"