Skip to content

Commit 5562496

Browse files
committed
New release: Light-Mode, Sub-Handle and Virtual-Handle, Conway-Era
Rendered Release-Notes: https://github.com/gitmachtl/scripts/releases/tag/Light-Mode ## New Feature - LIGHT-Mode, running the SPO Scripts without a local node This is an exciting new feature in the SPO Scripts. Before we had two operational modes, Online-Mode and Offline-Mode. Now we have an additional one, the Light-Mode. So whats this Light-Mode? If you switch the scripts into Light-Mode - see below how easy it is to do so - you have the advantage of being online with your machine, but you don't need a running synced cardano-node. You can switch between Networks Mainnet, PreProd and PreView within seconds. This comes is handy if you just don't want to install and run a cardano-node, if you don't have the space for the database or if you just don't have the time to wait for a resync. All transactions are of course generated and signed locally, but the queries and the transmit is done via online APIs like Koios. How do you switch between Online-, Light- and Offline-Mode? Thats simple, you just change a single entry in the 00_common.sh, common.inc or $HOME/.common.inc config-file: image workMode="online": Scripts are working in Online-Mode aka Full-Mode. A locally running and synced cardano-node is needed. workMode="light": Scripts are working in Light-Mode. No cardano-node needed. workMode="offline": Scripts are working in isolation and completely offline. No cardano-node needed. You can do ALL OPERATIONS in Light-Mode now! ?? Currently supported Chains are Mainnet, PreProd and PreView. You can switch between chains in seconds, and if you put a different common.inc file into your folders, you can run them all in parallel too. I also wanna thank Holger from Cardano24, because i am hosting the Online-Version of the Protocol-Parameters JSON files on his distributed Server-Platform uptime.live, thank you! The JSON files are updates every 10 mins to make them available in Light-Mode. If you have an Online/Offline Workflow, you can use the Online machine in Light-Mode, and your Offline machine is still offline of course. ## New Feature - $Sub-Handle & $Virtual-Handle support for $Adahandles ?? Complete support for the upcoming Sub-Handle and Virtual-Handle release. All scripts than can use Adahandles for queries and destinations are upgraded to support these additional formats. As always, the scripts doing a second lookup if the Handles are really on the UTXOs that the APIs report. For the Virtual-Handles the Scripts are doing an extra Koios request to checkout the Inline-Datum content of the UTXO holding the Virtual-Handle. Virtual-Handles store the destination address within the Inline-Datum. Also there has been an Update to show all the different types of Adahandles in the Query, like ADA Handle for the original CIP-25 one, Ada Handle(Own) for the new CIP68 ones. Ada Handle(Ref) and Ada Handle(Virt) for the newest formats. ## Improvements to the Online-Mode (aka Full-Mode) Critical queries now always do a check if the local node is 100% synced with the chain before continuation. ## Improvements to the Offline-Mode In Offline-Mode the header on each Script Call now shows your local machine time. This is really important if you are doing things like an OpCert-Update to generate the right KES period. So now you can do an easy check if the time on your Offline-Machine is correct NativeAsset Token-Registry Information also in Offline-Mode. To get the UTXO data of an address you wanna use in Offline-Mode you are using the command ./01_workOffline.sh add <walletname>. This query - if enabled in the config - now also stores the Token-Registry information about NativeAssets on this address within the offlineTransfer.json file. ## General updates The SPO Scripts are now fully Conway-Era compatible!! 01_claimRewards.sh, 01_queryAddress.sh are now showing if the Stake-Address is delegated to a pool. If so it tries to show additional pool-informations like the Ticker, Description and the current Pool-Status 03a_genStakingPaymentAddr.sh: The generation of the Stake-Address registration certificate has been moved to be done within 03b_regStakingAddrCert.sh. This is a change for conway-era, because we now have to check the StakeAdress-Registration Deposit-Fee also for the deregistration. The Deposit-Fee can change after a registration has been done, so with conway-era the used amount is now stored within the certificate itself. If the StakeAddress is already registered on chain, the Script will tell you that and if also delegated to a Pool, it wil try to show you additional informations. 03c_checkStakingAddrOnChain.sh now also shows the used Deposit-Fee of a registered Stake-Address. If delegated to a pool, it tries to show additional Informations. image 04d_genNodeOpCert.sh now directly ready out the onDisKOpCertCount from the via an own new CBOR-Decode function to provide checking information in Light-Mode. 04e_checkNodeOpCert.sh now ready out the onDiscOpCertCount and the onDiskKESSStart values for checking in Online- and Light-Mode 05a_genStakepoolCert.sh now shows the set poolPledge also in ADA and not only in lovecase. Shows minPoolCost now also in ADA and not only in lovelaces. Shows the poolMargin now in percentage and not as decimal value. 05c_regStakepoolCert.sh now shows the set poolPledge also in ADA and not only in lovecase. Shows minPoolCost now also in ADA and not only in lovelaces. Shows the poolMargin now in percentage and not as decimal value. A pool update/registration/retirement of course now also works in Light-Mode: image If there are external Witnesses (MultiOwnerPool) and the registration is done with an attached Metadata-JSON/CBOR, that information is now also stored to be represented in the external witness file. 05e_checkPoolOnChain.sh now gives you detailed informations about the current pool-status. You can of course also use a pool-id in bech or hex to query this information with this script. 06_regDelegationCert.sh now checks the pool status you wanna send the delegation before continue with the transaction. If a pool is retired or was not registered on the chain(yet), such a transaction would let to an error. This precheck avoids this issue. In addition there is now a check that the Stake-Address is already registered on chain. Also, it now shows information about a current delegation and the planned delegation. The script directly reads out the delegation destination pool-id from the delegation certificate to show this information. 08a_genStakingAddrRetireCert.shnow checks if the Stake-Address is even registered before generating the Retirement-Certificate. Also now important, it checks the Deposit-Fee that was used to register the Stake-Address in first place. Because we need to use the exact Fee again to retire the Stake-Address. There is now also a check if the Stake-Address you wanna retire still holds rewards. If the Stake-Address still hold rewards, it will show you the amount and refuse to generate a Retirement certificate. In that case please first claim all your rewards via 01_claimRewards.sh and after that retire the Stake-Address. 08b_deregStakingAddrCert.shnow again checks the current Stake-Address status on chain and a possible active delegation. Just to make sure you're retireing the right Stake-Address. It also now directly reads out the used Stake-Address Deposit-Fee to calculate the balance return correctly. Many additional updates here and there for better request handling via curl, better error checks, etc ... Please enjoy this huge update and especially the new Light-Mode!!
1 parent cb72df9 commit 5562496

38 files changed

+3882
-1560
lines changed

cardano/mainnet/00_common.sh

+924-155
Large diffs are not rendered by default.

cardano/mainnet/01_claimRewards.sh

+149-71
Large diffs are not rendered by default.

cardano/mainnet/01_protectKey.sh

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Example: $(basename $0) enc mywallet ... Encrypts the mywallet.skey fi
2424
EOF
2525
}
2626

27+
2728
#Check commandline parameters
2829
if [[ $# -lt 2 ]]; then showUsage; exit 1; fi #check about two given parameters
2930
case ${1^^} in

cardano/mainnet/01_queryAddress.sh

+111-55
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#load variables and functions from common.sh
66
. "$(dirname "$0")"/00_common.sh
77

8-
98
#Check the commandline parameter
109
if [[ $# -eq 1 && ! $1 == "" ]]; then addrName="$(dirname $1)/$(basename $1 .addr)"; addrName=${addrName/#.\//}; else echo "ERROR - Usage: $0 <AdressName or HASH or '\$adahandle'>"; exit 2; fi
1110

@@ -18,41 +17,19 @@ if [ ! -f "${addrName}.addr" ]; then
1817
typeOfAddr=$(get_addressType "${addrName}");
1918
if [[ ${typeOfAddr} == ${addrTypePayment} || ${typeOfAddr} == ${addrTypeStake} ]]; then echo "$(basename ${addrName})" > ${tempDir}/tempAddr.addr; addrName="${tempDir}/tempAddr";
2019

21-
#check if its an root adahandle (without a @ char)
22-
elif checkAdaRootHandleFormat "${addrName}"; then
23-
if ${offlineMode}; then echo -e "\n\e[35mERROR - Adahandles are only supported in Online mode.\n\e[0m"; exit 1; fi
20+
#check if its an adahandle (root/sub/virtual)
21+
elif checkAdaHandleFormat "${addrName}"; then
22+
2423
adahandleName=${addrName,,}
25-
assetNameHex=$(convert_assetNameASCII2HEX ${adahandleName:1})
26-
#query classic cip-25 adahandle asset holding address via koios
27-
showProcessAnimation "Query Adahandle(CIP-25) into holding address: " &
28-
response=$(curl -s -m 10 -X GET "${koiosAPI}/asset_address_list?_asset_policy=${adahandlePolicyID}&_asset_name=${assetNameHex}" -H "Accept: application/json" 2> /dev/null)
29-
stopProcessAnimation;
30-
#check if the received json only contains one entry in the array (will also not be 1 if not a valid json)
31-
if [[ $(jq ". | length" 2> /dev/null <<< ${response}) -ne 1 ]]; then
32-
#query classic cip-68 adahandle asset holding address via koios
33-
showProcessAnimation "Query Adahandle(CIP-68) into holding address: " &
34-
response=$(curl -s -m 10 -X GET "${koiosAPI}/asset_address_list?_asset_policy=${adahandlePolicyID}&_asset_name=000de140${assetNameHex}" -H "Accept: application/json" 2> /dev/null)
35-
stopProcessAnimation;
36-
#check if the received json only contains one entry in the array (will also not be 1 if not a valid json)
37-
if [[ $(jq ". | length" 2> /dev/null <<< ${response}) -ne 1 ]]; then echo -e "\n\e[35mCould not resolve Adahandle to an address.\n\e[0m"; exit 1; fi
38-
assetNameHex="000de140${assetNameHex}"
39-
fi
40-
addrName=$(jq -r ".[0].payment_address" <<< ${response} 2> /dev/null)
41-
typeOfAddr=$(get_addressType "${addrName}");
42-
if [[ ${typeOfAddr} != ${addrTypePayment} ]]; then echo -e "\n\e[35mERROR - Resolved address '${addrName}' is not a valid payment address.\n\e[0m"; exit 1; fi;
43-
showProcessAnimation "Verify Adahandle is on resolved address: " &
44-
utxo=$(${cardanocli} query utxo --address ${addrName} ${magicparam} ); stopProcessAnimation; checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi;
45-
if [[ $(grep "${adahandlePolicyID}.${assetNameHex} " <<< ${utxo} | wc -l) -ne 1 ]]; then
46-
echo -e "\n\e[35mERROR - Resolved address '${addrName}' does not hold the \$adahandle '${adahandleName}' !\n\e[0m"; exit 1; fi;
47-
echo -e "\e[0mFound \$adahandle '${adahandleName}' on Address:\e[32m ${addrName}\e[0m\n"
48-
echo "$(basename ${addrName})" > ${tempDir}/adahandle-resolve.addr; addrName="${tempDir}/adahandle-resolve";
49-
50-
elif checkAdaSubHandleFormat "${addrName}"; then
51-
echo -e "\n\e[33mINFO - AdaSubHandles are not supported yet.\n\e[0m"; exit 1;
5224

53-
#otherwise post an error message
54-
else echo -e "\n\e[35mERROR - Destination Address can't be resolved. Maybe filename wrong, or not a payment-address.\n\e[0m"; exit 1;
25+
#resolve given adahandle into address
26+
resolveAdahandle "${adahandleName}" "addrName" #if successful, it resolves the adahandle and writes it out into the variable 'addrName'. also sets the variable 'utxo' if possible
27+
28+
#resolveAdahandle did not exit with an error, so we resolved it
29+
echo "${addrName}" > ${tempDir}/adahandle-resolve.addr; addrName="${tempDir}/adahandle-resolve";
5530

31+
#otherwise post an error message
32+
else echo -e "\n\e[35mERROR - Destination Address can't be resolved. Maybe filename wrong, or not a payment- or stake-address.\n\e[0m"; exit 1;
5633
fi
5734
fi
5835

@@ -71,18 +48,34 @@ if [[ ${typeOfAddr} == ${addrTypePayment} ]]; then #Enterprise and Base UTXO ad
7148
echo -e "\e[0mAddress-Type / Era:\e[32m $(get_addressType "${checkAddr}")\e[0m / \e[32m$(get_addressEra "${checkAddr}")\e[0m"
7249
echo
7350

74-
#Get UTX0 Data for the address. When in online mode of course from the node and the chain, in offlinemode from the transferFile
75-
#${nodeEraParam} not needed anymore
76-
if ${onlineMode}; then
77-
showProcessAnimation "Query-UTXO: " &
78-
utxo=$(${cardanocli} query utxo --address ${checkAddr} ${magicparam} ); stopProcessAnimation; checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi;
51+
#Get UTX0 Data for the address. When in online mode of course from the node and the chain, in lightmode via API requests, in offlinemode from the transferFile
52+
case ${workMode} in
53+
"online") if [[ "${utxo}" == "" ]]; then #only query it again if not already queried via an adahandle check before
54+
#check that the node is fully synced, otherwise the query would mabye return a false state
55+
if [[ $(get_currentSync) != "synced" ]]; then echo -e "\e[35mError - Node not fully synced or not running, please let your node sync to 100% first !\e[0m\n"; exit 1; fi
56+
showProcessAnimation "Query-UTXO: " &
57+
utxo=$(${cardanocli} ${cliEra} query utxo --address ${checkAddr} 2> /dev/stdout);
58+
if [ $? -ne 0 ]; then stopProcessAnimation; echo -e "\e[35mERROR - ${utxo}\e[0m\n"; exit $?; else stopProcessAnimation; fi;
59+
fi
60+
showProcessAnimation "Convert-UTXO: " &
61+
utxoJSON=$(generate_UTXO "${utxo}" "${checkAddr}"); stopProcessAnimation;
62+
;;
63+
64+
"light") if [[ "${utxo}" == "" ]]; then #only query it again if not already queried via an adahandle check before
65+
showProcessAnimation "Query-UTXO-LightMode: " &
66+
utxo=$(queryLight_UTXO "${checkAddr}");
67+
if [ $? -ne 0 ]; then stopProcessAnimation; echo -e "\e[35mERROR - ${utxo}\e[0m\n"; exit $?; else stopProcessAnimation; fi;
68+
fi
7969
showProcessAnimation "Convert-UTXO: " &
8070
utxoJSON=$(generate_UTXO "${utxo}" "${checkAddr}"); stopProcessAnimation;
81-
else
82-
readOfflineFile; #Reads the offlinefile into the offlineJSON variable
83-
utxoJSON=$(jq -r ".address.\"${checkAddr}\".utxoJSON" <<< ${offlineJSON})
71+
;;
72+
73+
74+
"offline") readOfflineFile; #Reads the offlinefile into the offlineJSON variable
75+
utxoJSON=$(jq -r ".address.\"${checkAddr}\".utxoJSON" <<< ${offlineJSON} 2> /dev/null)
8476
if [[ "${utxoJSON}" == null ]]; then echo -e "\e[35mAddress not included in the offline transferFile, please include it first online!\e[0m\n"; exit 1; fi
85-
fi
77+
;;
78+
esac
8679

8780
utxoEntryCnt=$(jq length <<< ${utxoJSON})
8881
if [[ ${utxoEntryCnt} == 0 ]]; then echo -e "\e[35mNo funds on the Address!\e[0m\n"; exit 1; else echo -e "\e[32m${utxoEntryCnt} UTXOs\e[0m found on the Address!"; fi
@@ -141,9 +134,20 @@ if [[ ${typeOfAddr} == ${addrTypePayment} ]]; then #Enterprise and Base UTXO ad
141134
totalAssetsJSON=$( jq ". += {\"${assetHash}${point}${assetName}\":{amount: \"${newValue}\", name: \"${assetTmpName}\", bech: \"${assetBech}\"}}" <<< ${totalAssetsJSON})
142135
if [[ "${assetTmpName:0:1}" == "." ]]; then assetTmpName=${assetTmpName:1}; else assetTmpName="{${assetTmpName}}"; fi
143136

144-
case ${assetHash} in
145-
"${adahandlePolicyID}" ) #$adahandle
146-
if [[ ${assetTmpName:1:8} == "000de140" ]]; then assetName=${assetName:8}; fi #if it is a cip-68 adahandle, cut the first 4 bytes (8 chars in hex format)
137+
case "${assetHash}${assetTmpName:1:8}" in
138+
"${adahandlePolicyID}000de140" ) #$adahandle cip-68
139+
assetName=${assetName:8};
140+
echo -e "\e[90m Asset: ${assetBech} \e[33mADA Handle(Own): \$$(convert_assetNameHEX2ASCII ${assetName}) ${assetTmpName}\e[0m"
141+
;;
142+
"${adahandlePolicyID}00000000" ) #$adahandle virtual
143+
assetName=${assetName:8};
144+
echo -e "\e[90m Asset: ${assetBech} \e[33mADA Handle(Vir): \$$(convert_assetNameHEX2ASCII ${assetName}) ${assetTmpName}\e[0m"
145+
;;
146+
"${adahandlePolicyID}000643b0" ) #$adahandle reference
147+
assetName=${assetName:8};
148+
echo -e "\e[90m Asset: ${assetBech} \e[33mADA Handle(Ref): \$$(convert_assetNameHEX2ASCII ${assetName}) ${assetTmpName}\e[0m"
149+
;;
150+
"${adahandlePolicyID}"* ) #$adahandle cip-25
147151
echo -e "\e[90m Asset: ${assetBech} \e[33mADA Handle: \$$(convert_assetNameHEX2ASCII ${assetName}) ${assetTmpName}\e[0m"
148152
;;
149153
* ) #default
@@ -202,14 +206,26 @@ elif [[ ${typeOfAddr} == ${addrTypeStake} ]]; then #Staking Address
202206
echo -e "\e[0mAddress-Type / Era:\e[32m $(get_addressType "${checkAddr}")\e[0m / \e[32m$(get_addressEra "${checkAddr}")\e[0m"
203207
echo
204208

205-
#Get rewards state data for the address. When in online mode of course from the node and the chain, in offlinemode from the transferFile
206-
if ${onlineMode}; then
207-
rewardsJSON=$(${cardanocli} query stake-address-info --address ${checkAddr} ${magicparam} | jq -rc .)
208-
else
209-
rewardsJSON=$(cat ${offlineFile} | jq -r ".address.\"${checkAddr}\".rewardsJSON" 2> /dev/null)
209+
#Get rewards state data for the address. When in online mode of course from the node and the chain, in light mode via koios, in offlinemode from the transferFile
210+
case ${workMode} in
211+
212+
"online") showProcessAnimation "Query-StakeAddress-Info: " &
213+
rewardsJSON=$(${cardanocli} ${cliEra} query stake-address-info --address ${checkAddr} 2> /dev/null )
214+
if [ $? -ne 0 ]; then stopProcessAnimation; echo -e "\e[35mERROR - ${rewardsJSON}\e[0m\n"; exit $?; else stopProcessAnimation; fi;
215+
rewardsJSON=$(jq -rc . <<< "${rewardsJSON}")
216+
;;
217+
218+
"light") showProcessAnimation "Query-StakeAddress-Info-LightMode: " &
219+
rewardsJSON=$(queryLight_stakeAddressInfo "${checkAddr}")
220+
if [ $? -ne 0 ]; then stopProcessAnimation; echo -e "\e[35mERROR - ${rewardsJSON}\e[0m\n"; exit $?; else stopProcessAnimation; fi;
221+
;;
222+
223+
"offline") readOfflineFile; #Reads the offlinefile into the offlineJSON variable
224+
rewardsJSON=$(jq -r ".address.\"${checkAddr}\".rewardsJSON" <<< ${offlineJSON} 2> /dev/null)
210225
if [[ "${rewardsJSON}" == null ]]; then echo -e "\e[35mAddress not included in the offline transferFile, please include it first online!\e[0m\n"; exit; fi
211-
fi
212-
checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi
226+
;;
227+
228+
esac
213229

214230
rewardsEntryCnt=$(jq -r 'length' <<< ${rewardsJSON})
215231

@@ -224,10 +240,10 @@ elif [[ ${typeOfAddr} == ${addrTypeStake} ]]; then #Staking Address
224240
rewardsAmount=$(jq -r ".[${tmpCnt}].rewardAccountBalance" <<< ${rewardsJSON})
225241
rewardsAmountInADA=$(bc <<< "scale=6; ${rewardsAmount} / 1000000")
226242

227-
delegationPoolID=$(jq -r ".[${tmpCnt}].delegation" <<< ${rewardsJSON})
243+
delegationPoolID=$(jq -r ".[${tmpCnt}].delegation // .[${tmpCnt}].stakeDelegation" <<< ${rewardsJSON})
228244

229245
rewardsSum=$((${rewardsSum}+${rewardsAmount}))
230-
rewardsSumInADA=$(bc <<< "scale=6; ${rewardsSum} / 1000000")
246+
rewardsSumInADA=$(bc <<< "scale=6; ${rewardsSum} / 1000000")
231247

232248
echo -ne "[$((${tmpCnt}+1))]\t"
233249

@@ -237,7 +253,47 @@ elif [[ ${typeOfAddr} == ${addrTypeStake} ]]; then #Staking Address
237253
fi
238254

239255
#If delegated to a pool, show the current pool ID
240-
if [[ ! ${delegationPoolID} == null ]]; then echo -e " \tAccount is delegated to a Pool with ID: \e[32m${delegationPoolID}\e[0m"; else echo -e " \tAccount is not delegated to a Pool !"; fi
256+
if [[ ! ${delegationPoolID} == null ]]; then
257+
echo -e " \tAccount is delegated to a Pool with ID: \e[32m${delegationPoolID}\e[0m";
258+
259+
if [[ ${onlineMode} == true && ${koiosAPI} != "" ]]; then
260+
261+
#query poolinfo via poolid on koios
262+
errorcnt=0; error=-1;
263+
showProcessAnimation "Query Pool-Info via Koios: " &
264+
while [[ ${errorcnt} -lt 5 && ${error} -ne 0 ]]; do #try a maximum of 5 times to request the information
265+
error=0
266+
response=$(curl -sL -m 30 -X POST -w "---spo-scripts---%{http_code}" "${koiosAPI}/pool_info" -H "Accept: application/json" -H "Content-Type: application/json" -d "{\"_pool_bech32_ids\":[\"${delegationPoolID}\"]}" 2> /dev/null)
267+
if [[ $? -ne 0 ]]; then error=1; sleep 1; fi; #if there is an error, wait for a second and repeat
268+
errorcnt=$(( ${errorcnt} + 1 ))
269+
done
270+
stopProcessAnimation;
271+
272+
#if no error occured, split the response string into JSON content and the HTTP-ResponseCode
273+
if [[ ${error} -eq 0 && "${response}" =~ (.*)---spo-scripts---([0-9]*)* ]]; then
274+
275+
responseJSON="${BASH_REMATCH[1]}"
276+
responseCode="${BASH_REMATCH[2]}"
277+
278+
#if the responseCode is 200 (OK) and the received json only contains one entry in the array (will also not be 1 if not a valid json)
279+
if [[ ${responseCode} -eq 200 && $(jq ". | length" 2> /dev/null <<< ${responseJSON}) -eq 1 ]]; then
280+
{ read poolNameInfo; read poolTickerInfo; read poolStatusInfo; } <<< $(jq -r ".[0].meta_json.name // \"-\", .[0].meta_json.ticker // \"-\", .[0].pool_status // \"-\"" 2> /dev/null <<< ${responseJSON})
281+
echo -e " \t\e[0mInformation about the Pool: \e[32m${poolNameInfo} (${poolTickerInfo})\e[0m"
282+
echo -e " \t\e[0m Status: \e[32m${poolStatusInfo}\e[0m"
283+
echo
284+
unset poolNameInfo poolTickerInfo poolStatusInfo
285+
fi #responseCode & jsoncheck
286+
287+
fi #error & response
288+
unset errorcnt error
289+
290+
fi #onlineMode & koiosAPI
291+
292+
else
293+
294+
echo -e " \tAccount is not delegated to a Pool !";
295+
296+
fi
241297

242298
echo
243299

0 commit comments

Comments
 (0)