Skip to content

Commit

Permalink
Adding new feature - Catalyst VotingPower query
Browse files Browse the repository at this point in the history
09a_catalystVote.sh / 09a_vatalystVoteF10.sh:

Added a query feature so you can now verify your registered Voting-Power. This works on MainNet and on TestNet, because its a combined API at the moment.

The result is the currently registered total Voting-Power, and all the Delegators/Delegations that are done to that Voting-Key.

Queries can be done by providing the name of the Voting-Key file, by providing a bech encoded Voting-Key or by directly providing a hex encoded Voting-Key like:

- 09a_catalystVoteF10.sh query myvote-test

- 09a_catalystVoteF10.sh query cvote_vk1lca8dhe30dtmuk4yq3c9f20af0jk7ne9vhzhemheczjtpy3dq85qcdzn3e

- 09a_catalystVoteF10.sh query fe3a76df317b57be5aa4047054a9fd4be56f4f2565c57ceef9c0a4b0922d01e8
  • Loading branch information
gitmachtl committed Aug 15, 2023
1 parent 78c6aaa commit c5b959b
Show file tree
Hide file tree
Showing 4 changed files with 351 additions and 13 deletions.
9 changes: 8 additions & 1 deletion cardano/mainnet/00_common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ case "${network,,}" in
_transactionExplorer="https://cardanoscan.io/transaction/" #URLS for the Transaction-Explorers -> autoresolve into ${transactionExplorer}/
_koiosAPI="https://api.koios.rest/api/v0" #Koios-API URLs -> autoresolve into ${koiosAPI}
_adahandlePolicyID="f0ff48bbb7bbe9d59a40f1ce90e9e9d0ff5002ec48f232b49ca0fb9a" #PolicyIDs for the adaHandles -> autoresolve into ${adahandlePolicyID}
_catalystAPI="https://api.testnet.projectcatalyst.io/api/v1" #Catalyst-API URLs -> autoresolve into ${catalystAPI}
;;


Expand All @@ -166,6 +167,7 @@ case "${network,,}" in
_transactionExplorer="https://preprod.cardanoscan.io/transaction"
_koiosAPI="https://preprod.koios.rest/api/v0"
_adahandlePolicyID="f0ff48bbb7bbe9d59a40f1ce90e9e9d0ff5002ec48f232b49ca0fb9a" #PolicyIDs for the adaHandles -> autoresolve into ${adahandlePolicyID}
_catalystAPI="https://api.testnet.projectcatalyst.io/api/v1" #Catalyst-API URLs -> autoresolve into ${catalystAPI}
;;


Expand All @@ -178,6 +180,7 @@ case "${network,,}" in
_transactionExplorer="https://preview.cardanoscan.io/transaction"
_koiosAPI="https://preview.koios.rest/api/v0"
_adahandlePolicyID="f0ff48bbb7bbe9d59a40f1ce90e9e9d0ff5002ec48f232b49ca0fb9a" #PolicyIDs for the adaHandles -> autoresolve into ${adahandlePolicyID}
_catalystAPI="https://api.testnet.projectcatalyst.io/api/v1" #Catalyst-API URLs -> autoresolve into ${catalystAPI}
;;


Expand All @@ -190,6 +193,7 @@ case "${network,,}" in
_transactionExplorer=
_koiosAPI="https://guild.koios.rest/api/v0"
_adahandlePolicyID="f0ff48bbb7bbe9d59a40f1ce90e9e9d0ff5002ec48f232b49ca0fb9a" #PolicyIDs for the adaHandles -> autoresolve into ${adahandlePolicyID}
_catalystAPI= #Catalyst-API URLs -> autoresolve into ${catalystAPI}
;;


Expand All @@ -202,6 +206,7 @@ case "${network,,}" in
_transactionExplorer="https://testnet.cexplorer.io/tx"
_koiosAPI=
_adahandlePolicyID="8d18d786e92776c824607fd8e193ec535c79dc61ea2405ddf3b09fe3"
_catalystAPI= #Catalyst-API URLs -> autoresolve into ${catalystAPI}
;;

esac
Expand All @@ -215,12 +220,14 @@ tokenMetaServer=${tokenMetaServer:-"${_tokenMetaServer}"}
transactionExplorer=${transactionExplorer:-"${_transactionExplorer}"}
koiosAPI=${koiosAPI:-"${_koiosAPI}"}
adahandlePolicyID=${adahandlePolicyID:-"${_adahandlePolicyID}"}
catalystAPI=${catalystAPI:-"${_catalystAPI}"}


#Check about the / at the end of the URLs
if [[ "${tokenMetaServer: -1}" == "/" ]]; then tokenMetaServer=${tokenMetaServer%?}; fi #make sure the last char is not a /
if [[ "${koiosAPI: -1}" == "/" ]]; then koiosAPI=${koiosAPI%?}; fi #make sure the last char is not a /
if [[ "${transactionExplorer: -1}" == "/" ]]; then transactionExplorer=${transactionExplorer%?}; fi #make sure the last char is not a /
if [[ "${catalystAPI: -1}" == "/" ]]; then catalystAPI=${catalystAPI%?}; fi #make sure the last char is not a /


#Check about the needed chain params
Expand Down Expand Up @@ -558,7 +565,7 @@ if [[ ! "${tmpEra}" == "auto" ]]; then nodeEraParam="--${tmpEra}-era"; else node

#Temporary fix to lock the transaction build-raw to alonzo era for
#Hardware-Wallet operations. Babbage-Era is not yet supported, so we will lock this for now
#if [[ "${nodeEraParam}" == "" ]] || [[ "${nodeEraParam}" == "--babbage-era" ]]; then nodeEraParam="--alonzo-era"; fi
if [[ "${nodeEraParam}" == "" ]] || [[ "${nodeEraParam}" == "--conway-era" ]]; then nodeEraParam="--babbage-era"; fi


#-------------------------------------------------------
Expand Down
178 changes: 172 additions & 6 deletions cardano/mainnet/09a_catalystVote.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Usage: $(basename $0) new cli <voteKeyName> ... Generat
$(basename $0) qrcode <voteKeyName> <4-Digit-PinCode> ... Shows the QR code for the Catalyst-Voting-App protected via a 4-digit PinCode
$(basename $0) query <voteKeyName|voteBechPublicKey> ... Queries the Catalyst-API for the Voting-Power and Delegations for a VotingKey
Examples:
Expand Down Expand Up @@ -53,13 +55,13 @@ payPath=0 #set default paymentPath
paramCnt=$#;
allParameters=( "$@" )

if [[ ${paramCnt} -lt 3 ]]; then showUsage; exit 1; fi

case ${1,,} in

### Generate the QR code from the vote secret key for the mobile voting app
qrcode )

if [[ ${paramCnt} -lt 3 ]]; then showUsage; exit 1; fi

#Check the catalyst-toolbox binary existance and version
if ! exists "${catalyst_toolbox_bin}"; then
#Try the one in the scripts folder
Expand All @@ -70,7 +72,7 @@ case ${1,,} in
if [[ $? -ne 0 ]]; then echo -e "\e[35mERROR - This script needs a working 'catalyst-toolbox' binary. Please make sure you have it present with with the right path in '00_common.sh' !\e[0m\n\n"; exit 1; fi
catalystToolboxVersion=$(echo ${catalystToolboxCheck} | cut -d' ' -f 2)
versionCheck "${minCatalystToolboxVersion}" "${catalystToolboxVersion}"
if [[ $? -ne 0 ]]; then majorError "Version ${catalystToolboxVersion} ERROR - Please use a cardano-toolbox version ${minCatalystToolboxVersion} or higher !\nOld versions are not compatible, please upgrade - thx."; exit 1; fi
if [[ $? -ne 0 ]]; then majorError "Version ${catalystToolboxVersion} ERROR - Please use a catalyst-toolbox version ${minCatalystToolboxVersion} or higher !\nOld versions are not compatible, please upgrade - thx."; exit 1; fi

voteKeyName="${allParameters[1]}"; voteKeyName=${voteKeyName/#.\//};
pinCode="${allParameters[2]}";
Expand Down Expand Up @@ -112,7 +114,9 @@ case ${1,,} in

### Generate new Voting Keys
new )
if [[ ${paramCnt} -ge 3 ]]; then

if [[ ${paramCnt} -lt 3 ]]; then showUsage; exit 1;
elif [[ ${paramCnt} -ge 3 ]]; then
method="${allParameters[1]}";
voteKeyName="${allParameters[2]}"; voteKeyName=${voteKeyName/#.\//};
else echo -e "\e[35mMissing parameters!\e[0m\n"; showUsage; exit 1; fi
Expand Down Expand Up @@ -203,7 +207,7 @@ case ${1,,} in
hw )

#We need a voting keypair with vkey and hwsfile from a Hardware-Key, so lets create them
start_HwWallet; checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi
start_HwWallet "" "6.0.3" ""; checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi
tmp=$(${cardanohwcli} address key-gen --path 1694H/1815H/${accountNo}H/${payPath}/${indexNo} --verification-key-file "${voteKeyName}.voting.vkey" --hw-signing-file "${voteKeyName}.voting.hwsfile" 2> /dev/stdout)
if [[ "${tmp^^}" =~ (ERROR|DISCONNECT) ]]; then echo -e "\e[35m${tmp}\e[0m\n"; exit 1; else echo -e "\e[32mDONE\e[0m\n"; fi
checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi
Expand Down Expand Up @@ -400,7 +404,7 @@ case ${1,,} in
echo -e "\e[0mNonce (current slotHeight): \e[32m${currentTip}\e[0m"
echo

start_HwWallet; checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi
start_HwWallet "" "6.0.3" ""; checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi
tmp=$(${cardanohwcli} vote registration-metadata ${cardanoHwCliParameters} --stake-signing-key-hwsfile "${stakeAcct}.hwsfile" --metadata-cbor-out-file "${votingMetaFile}" 2> /dev/stdout)
if [[ "${tmp^^}" =~ (ERROR|DISCONNECT) ]]; then echo -e "\e[35m${tmp}\e[0m\n"; exit 1; else echo -e "\e[32mDONE\e[0m\n"; fi
checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi
Expand Down Expand Up @@ -456,6 +460,168 @@ case ${1,,} in
;;


### Query the Catalyst-API for the voteKey -> VotingPower and Delegations
query )

#Query only possible if not offline mode
if ${offlineMode}; then
echo -e "\e[35mYou have to be in ONLINE MODE to do this!\e[0m\n"; exit 1;
fi

#Check that there is actually a catalystAPI available for this network
if [[ ${catalystAPI} == "" ]]; then
echo -e "\e[35mThere is no Catalyst-API available for this network, i am sorry!\e[0m\n"; exit 1;
fi

#Check about 1 input parameters
if [[ ${paramCnt} -ne 2 ]]; then echo -e "\e[35mIncorrect parameter count!\e[0m\n"; showUsage; exit 1; fi

echo -e "\e[0mQuery the Catalyst-API (${catalystAPI}) for the following Voting-Key\e[0m"
echo

#Read the votePublicKey information
voteKeyName="${allParameters[1]}"

#check the voteKeyName entry if it is a .pkey file (contains the bech pubKey), or if is a .vkey file (contains the key in hex format) or if it is a direct bech or hex key
if [ -f "${voteKeyName}.voting.pkey" ]; then #the .pkey file exists so lets read the value in it and check it if its a bech key
inputKey=$(cat "${voteKeyName}.voting.pkey")
tmp=$(${bech32_bin} <<< "${inputKey}" 2> /dev/null)
if [ $? -ne 0 ]; then echo -e "\e[35mError - ${voteKeyName}.voting.pkey contains an invalid bech votePublicKey !\e[0m\n"; exit 1; fi
votePubKey=$(${bech32_bin} "cvote_vk" <<< "${inputKey}" 2> /dev/null) #make sure it is a bechKey "cvote_vk"
checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi
voteKeySource="${voteKeyName}.voting.pkey"
elif [ -f "${voteKeyName}.voting.vkey" ]; then #the .vkey file exists so lets read the value in it and check it
cborVoteKey=$(jq -r ".cborHex" "${voteKeyName}.voting.vkey" 2> /dev/null);
if [[ $? -ne 0 ]]; then echo -e "\e[35mERROR - ${voteKeyName}.voting.vkey is not a valid json file. Please make sure to use the new voting key format, you can generate it with the subcommand 'new' !\e[0m\n\n"; exit 1; fi
#Generate the voting key bech format
inputKey=${cborVoteKey:4}
votePubKey=$(${bech32_bin} "cvote_vk" <<< ${inputKey:0:64} 2> /dev/null) #only use the first 64chars (32 bytes) in case an extended key was provided
checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi
voteKeySource="${voteKeyName}.voting.vkey"

elif [[ "${voteKeyName//[![:xdigit:]]}" == "${voteKeyName}" ]] && [[ ${#voteKeyName} -eq 64 || ${#voteKeyName} -eq 128 ]]; then #lets use a hex key as the voteKeyName with length of 32 or 64 bytes
#Generate the voting key from hex input
inputKey=${voteKeyName,,}
votePubKey=$(${bech32_bin} "cvote_vk" <<< ${inputKey:0:64} 2> /dev/null) #only use the first 64chars (32 bytes) in case an extended key was provided
checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi
voteKeySource="direct"
voteKeyName="Hex-VotePublicKey"

else #ok lets try to read in the voteKeyName as a direct bech key
inputKey="${voteKeyName}"
tmp=$(${bech32_bin} <<< "${inputKey}" 2> /dev/null)
if [ $? -ne 0 ]; then echo -e "\e[35mError - ${voteKeyName}.voting.pkey/vkey file not found. Also it is not a direct valid bech or hex votePublicKey !\e[0m\n"; exit 1; fi
votePubKey=$(${bech32_bin} "cvote_vk" <<< "${inputKey}" 2> /dev/null) #make sure it is a bechKey "cvote_vk"
checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi
voteKeySource="direct"
voteKeyName="Bech-VotePublicKey"
fi

echo -e "\e[0m Name: \e[32m${voteKeyName}\n\e[0m Source: \e[32m${voteKeySource}\n\e[0m inputKey: \e[32m${inputKey}\n\e[0m votePubKey: \e[32m${votePubKey}\e[0m\n"



#votePubKey is always in bech format at this point, so lets get the hex format for the api query
voteKeyHex=$(${bech32_bin} <<< "${votePubKey}" 2> /dev/null) #convert the displayed votePubKey(Bech) into the Hex-Representation

#query the voteKeyHex via the catalyst-api, try it 5 times
retrycnt=5
while [[ ${retrycnt} -gt 0 ]]; do
echo -n "Requesting information via the Catalyst-API ... "
response=$(curl -s -m 10 -X GET "${catalystAPI}/registration/voter/0x${voteKeyHex}?with_delegators=true" -H "accept: application/json" 2> /dev/null)
if [[ $? -ne 0 ]]; then #curl existed with an error
echo -e "\e[31mError - Bad response!\e[0m";
retrycnt=$(( ${retrycnt} - 1 ));
else #curl exited ok, so lets check the response content
voter_info=$(jq -r ".voter_info" 2> /dev/null <<< ${response})
if [[ "${voter_info}" == "" || "${voter_info}" == "null" ]]; then #no data available
echo -e "\e[35mThere is no data available (yet) for this Voting-Key!\e[0m\n\n";
exit 1;
else
break; #good answer found
fi
fi
done

#exit if all retries were used to get an answer
if [[ ${retrycnt} -eq 0 ]]; then
echo -e "\n\e[35mError - Something went wrong, the Catalyst-API server is not reachable correctly!\e[0m\n\n";
exit 1;
fi

#entry for the 'voter_info' found
echo -e "\e[32mDONE\e[0m\n"

#get the values
voting_power=$(jq -r ".voting_power" <<< ${voter_info})
delegator_count=$(jq -r ".delegator_addresses | length" <<< ${voter_info})
delegator_addresses=(); readarray -t delegator_addresses <<< $(jq -r ".delegator_addresses | .[]" <<< ${voter_info})
registration_lastupdated=$(jq -r ".last_updated" <<< ${response})
registration_finalized=$(jq -r ".final" <<< ${response})

echo -e "\e[0m Last updated: \e[32m$(date --date="${registration_lastupdated}")\e[0m"
echo -e "\e[0m Is Finalized: \e[32m${registration_finalized}\e[0m"
echo
echo -e "\e[0m Voting-Power: \e[33m$(convertToADA ${voting_power}) ADA\e[0m"
echo -e "\e[0m Delegator-Count: \e[32m${delegator_count}\e[0m"
echo
echo -e "\e[0m ---------------- \e[0m"
echo

#list all addresses(vkeys -> resolve to stakeaddresses -> get detailed infos again via the api)
for (( tmpCnt=0; tmpCnt<${delegator_count}; tmpCnt++ ))
do
delegator_vkey=${delegator_addresses[${tmpCnt}]:2};

#get the stakeaddress from the vkey hash
if [[ "${magicparam}" == *"mainnet"* ]]; then
delegator_stakeaddress=$(echo -n "e1$(xxd -r -ps <<< "${delegator_vkey}" | b2sum -l 224 -b | cut -d' ' -f 1)" | ./bech32 "stake");
else
delegator_stakeaddress=$(echo -n "e0$(xxd -r -ps <<< "${delegator_vkey}" | b2sum -l 224 -b | cut -d' ' -f 1)" | ./bech32 "stake_test");
fi

echo -e "\e[0m Delegator: $(( ${tmpCnt} + 1))\e[0m"
echo -e "\e[0m Public-Key: \e[32m${delegator_vkey}\e[0m"
echo -e "\e[0m Stake-Address: \e[32m${delegator_stakeaddress}\e[0m"

#get details about the current delegator
#query the delegator publicKey (vkey) via the catalyst-api, try it 5 times
retrycnt=5
delegator_rewardaddress="\e[35mquery error\e[0m";
delegator_rawpower=0;
showProcessAnimation "Requesting information via the Catalyst-API: " &
while [[ ${retrycnt} -gt 0 ]]; do
response=$(curl -s -m 10 -X GET "${catalystAPI}/registration/delegations/0x${delegator_vkey}" -H "accept: application/json" 2> /dev/null)
if [[ $? -ne 0 ]]; then #curl existed with an error
retrycnt=$(( ${retrycnt} - 1 ));
else #curl exited ok, so lets check the response content
delegator_rewardaddress=$(jq -r ".reward_address" 2> /dev/null <<< ${response})
if [[ "${delegator_rewardaddress}" != "" && "${delegator_rewardaddress}" != "null" ]]; then #valid data found
delegator_rawpower=$(jq -r ".raw_power" 2> /dev/null <<< ${response})
break;
else #no valid data found
delegator_rewardaddress="\e[35mquery error\e[0m";
break;
fi
fi
done
stopProcessAnimation;

#if we used all retry counts, we failed to get data
if [[ ${retrycnt} -eq 0 ]]; then delegator_rewardaddress="\e[35mquery error\e[0m"; fi

echo -e "\e[0m Rewards-Address: \e[32m${delegator_rewardaddress}\e[0m"
echo -e "\e[0m Raw-Power: \e[33m$(convertToADA ${delegator_rawpower}) ADA\e[0m"
echo

done

echo

exit 0;
;;


* ) showUsage; exit 1;
;;
esac
Expand Down
Loading

0 comments on commit c5b959b

Please sign in to comment.