11#!/usr/bin/env python
2+ from ctypes import Array
23import shutil
34import subprocess
45from subprocess import CalledProcessError , CompletedProcess
89import json
910
1011HOME = os .environ .get ("HOME" ,"/root" )
12+ log_cli = 'LOG_CLI' in os .environ and os .environ ['LOG_CLI' ].lower () not in ('no' ,'off' ,'false' ,'0' )
1113# Define paths
1214KEYS_DIR = os .environ .get ("CARDANO_KEYS_DIR" ,os .path .join (HOME ,".cardano" ,"keys" ))
1315NETWORK = "--testnet-magic=4"
1416CARDANO_NODE_SOCKET_PATH = os .environ .get ("CARDANO_NODE_SOCKET_PATH" ,os .path .join (HOME ,'.cardano' ,'testnet' ,'node.socket' )).strip ()
15- if not os .path .exists (KEYS_DIR ):
16- os .makedirs (KEYS_DIR )
17+ TEMP_DIR = os .path .join (KEYS_DIR ,'tmp' )
18+ if not os .path .exists (TEMP_DIR ):
19+ os .makedirs (TEMP_DIR )
20+
1721if (os .environ .get ("NETWORK" )):
1822 NETWORK = os .environ .get ("NETWORK" ).strip ()
1923
2529 except ValueError :
2630 if NETWORK == 'mainnet' :
2731 NETWORK = "--mainnet"
28- elif NETWORK == 'snacho ' or NETWORK == 'sanchonet' :
32+ elif NETWORK == 'sancho ' or NETWORK == 'sanchonet' :
2933 NETWORK = "--testnet-magic=4"
3034 elif NETWORK == 'preview' :
3135 NETWORK = "--testnet-magic=2"
@@ -39,7 +43,6 @@ class SubmitResult:
3943 def __init__ (self ,process ,txid ):
4044 self .process :CompletedProcess = process
4145 self .txid :str = txid
42- log_cli = 'LOG_CLI' in os .environ and os .environ ['LOG_CLI' ].lower () not in ('no' ,'off' ,'false' ,'0' )
4346# Utility function to run cardano-cli commands
4447def run_cli_command (command : List [str ],raise_error = True ):
4548 if log_cli :
@@ -80,6 +83,8 @@ def gen_wallet(self,cli:'CardanoCLI'):
8083 stake_vkey = os .path .join (self .keys_dir , "stake.vkey" )
8184 stake_skey = os .path .join (self .keys_dir , "stake.skey" )
8285 payment_addr = os .path .join (self .keys_dir , "payment.addr" )
86+ check_if_file_exists (payment_vkey ,payment_skey ,stake_vkey ,stake_skey ,payment_addr )
87+
8388
8489 # Generate keys
8590 cli .cardano_cli ( "address" , "key-gen" , ["--verification-key-file" , payment_vkey , "--signing-key-file" , payment_skey ])
@@ -98,6 +103,7 @@ def gen_drep_key(self,cli:'CardanoCLI'):
98103 drep_vkey = os .path .join (self .keys_dir , "drep.vkey" )
99104 drep_skey = os .path .join (self .keys_dir , "drep.skey" )
100105 drep_id = os .path .join (self .keys_dir , "drep.id.hex.txt" )
106+ check_if_file_exists (drep_vkey ,drep_skey ,drep_id )
101107
102108 cli .cardano_cli_conway ("governance" , "drep" ,["key-gen" , "--verification-key-file" , drep_vkey , "--signing-key-file" , drep_skey ])
103109 cli .cardano_cli_conway ("governance" , "drep" , ["id" ,"--drep-verification-key-file" ,drep_vkey ,"--out-file" ,drep_id ,"--output-format" ,"hex" ])
@@ -126,7 +132,7 @@ def gen_cc_keys(self,cli:'CardanoCLI')->(Key):
126132 hot_vkey = self .file_path ("cc-hot.vkey" )
127133 hot_skey = self .file_path ("cc-hot.skey" )
128134 authorization_cert = self .file_path ("cc-hot-key-authorization.cert" )
129-
135+ check_if_file_exists ( cold_vkey , cold_skey , hot_vkey , hot_skey , cold_key_hash , authorization_cert )
130136
131137 cli .cardano_cli_conway ("governance" ,"committee" ,[
132138 "key-gen-cold" ,
@@ -206,7 +212,7 @@ def build_tx(self,wallet:Wallet,tx_name:str,commands:List[str],add_collateral=Fa
206212 commands .extend (["--tx-in-collateral" ,list (utxos .keys ())[0 ]])
207213
208214 # Build the transaction
209- tx_body_file = os .path .join (KEYS_DIR , tx_name + "_tx.raw" )
215+ tx_body_file = os .path .join (TEMP_DIR , tx_name + "_tx.raw" )
210216
211217
212218 self .cardano_cli_conway ("transaction" , "build" ,
@@ -216,7 +222,7 @@ def build_tx(self,wallet:Wallet,tx_name:str,commands:List[str],add_collateral=Fa
216222
217223 def build_and_submit (self ,wallet :Wallet ,tx_name :str ,commands :List [str ],raise_error = True ,extra_keys = [],add_collateral = False ):
218224
219- signed_tx_file = os .path .join (KEYS_DIR , tx_name + "_signed_tx.json" )
225+ signed_tx_file = os .path .join (TEMP_DIR , tx_name + "_signed_tx.json" )
220226
221227 tx_body_file = self .build_tx (wallet ,tx_name ,commands ,add_collateral )
222228 return self .sign_and_submit (wallet ,tx_body_file ,signed_tx_file ,raise_error = raise_error ,extra_keys = extra_keys )
@@ -240,7 +246,7 @@ def load_gov_state(self,):
240246 def propose (self ,wallet :Wallet ,args ):
241247 self .load_gov_state ()
242248 proposal_type = args [0 ] if len (args ) > 0 else ''
243- proposal_file = proposal_type + ".proposal"
249+ proposal_file = os . path . join ( TEMP_DIR , proposal_type + ".proposal" )
244250 req_prev = ["create-no-confidence" ,"update-committee" ,"create-constitution" ,"create-protocol-parameters-update" ,"create-hardfork" ]
245251 no_prev = ["create-treasury-withdrawal" ,"create-info" ]
246252 require_guardrail = ['create-treasury-withdrawal' ,"create-protocol-parameters-update" ]
@@ -301,7 +307,7 @@ def propose(self,wallet:Wallet,args):
301307
302308
303309 def register_stake (self , wallet : Wallet ):
304- stake_cert = os .path .join (KEYS_DIR , "stake_reg.cert" )
310+ stake_cert = os .path .join (TEMP_DIR , "stake_reg.cert" )
305311 # Generate stake key registration certificate
306312 self .load_gov_state ()
307313
@@ -338,7 +344,10 @@ def vote(self,vote,wallet:Wallet,key:Key,role:str,action_tx,action_tx_index):
338344 key_arg = "--cc-hot-verification-key-file"
339345 elif role == 'spo' :
340346 key_arg = "--cold-verification-key-file"
341- vote_file = os .path .join (KEYS_DIR ,"vote_" + vote + "_" + action_tx + '_' + action_tx_index + ".vote" )
347+ else :
348+ print ("Invalid Role :" , role )
349+ exit (1 )
350+ vote_file = os .path .join (TEMP_DIR ,"vote_" + vote + "_" + action_tx + '_' + action_tx_index + ".vote" )
342351 self .cardano_cli_conway ("governance" ,"vote" ,[
343352
344353 "create" ,
@@ -354,12 +363,24 @@ def vote(self,vote,wallet:Wallet,key:Key,role:str,action_tx,action_tx_index):
354363 "--witness-override" , "2"
355364 ],extra_keys = [key .private ],raise_error = False )
356365 process = result .process
357- if 'GovActionsDoNotExist' in process .stderr :
358- print ("ERROR: Gov Action doesn't exist on chain : " ,action_tx + "#" + action_tx_index )
359- print ("Nothing was done on-chain" )
360-
366+ if process .returncode > 0 :
367+ if 'GovActionsDoNotExist' in process .stderr :
368+ print ("ERROR: Gov Action doesn't exist on chain : " ,action_tx + "#" + action_tx_index )
369+ print ("Nothing was done on-chain" )
370+ elif 'VotersDoNotExist (DRepVoter' in process .stderr :
371+ print ("ERROR: You are not a Registred Drep" )
372+ print ("Nothing was done on-chain" )
373+ elif 'DisallowedVoters ((CommitteeVoter' in process .stderr :
374+ print ("ERROR: You are not a CC Member" )
375+ print ("Nothing was done on-chain" )
376+ else :
377+ print (process .stderr )
378+ print ("Nothing was done on-chain" )
379+ else :
380+ print ("Submitted :" ,result .txid )
381+
361382 def register_drep (self , wallet : Wallet , drep : Key ):
362- drep_cert = os .path .join (KEYS_DIR , "drep_reg.cert" )
383+ drep_cert = os .path .join (TEMP_DIR , "drep_reg.cert" )
363384 # Generate DRep registration certificate
364385 self .load_gov_state ()
365386
@@ -404,7 +425,7 @@ def sign_and_submit(self,wallet:Wallet,tx_raw_file,signed_tx_file,raise_error=Tr
404425 return self .get_tx_id (tx_raw_file )
405426
406427 def delegate (self ,wallet :Wallet ,own_drep :Key ,drep :str ):
407- delegation_cert = os .path .join (KEYS_DIR , "vote_deleg.cert" )
428+ delegation_cert = os .path .join (TEMP_DIR , "vote_deleg.cert" )
408429
409430 if drep == 'abstain' :
410431 delegation = ["--always-abstain" ]
@@ -429,38 +450,53 @@ def delegate(self,wallet:Wallet,own_drep:Key,drep:str):
429450 "--certificate-file" , delegation_cert ],extra_keys = [wallet .stake_skey ],raise_error = False )
430451 process = result .process
431452 if (process .returncode != 0 ):
453+
432454 if 'StakeKeyNotRegisteredDELEG' in process .stderr :
433- print ("ERROR: Drep is not registered:" ,drep )
434- elif 'StakeKeyNotRegisteredDELEG' in process .stderr :
435- print ("Your stake key is not registered" )
455+ print ("ERROR: Stake Address is not registered" )
436456 print ("run > gov-cli register stake" )
437- print ("To register your stake" )
438- else :
457+ print ("To register your stake" )
458+ else : ## Ledger allows delegating to non-existing drep.
439459 raise Exception ("Process failed " + process .stdout + process .stderr )
440460 else :
441461 print ("Submitted :" ,result .txid )
442462
443463 def cc_authorize_hot_key (self ,wallet :Wallet ,hot_key :Key ,cold_key :Key ):
444464
445- txid = self .build_and_submit (wallet ,'cc_hot_key_register' ,[
465+ result : SubmitResult = self .build_and_submit (wallet ,'cc_hot_key_register' ,[
446466 "--certificate-file" ,hot_key .id ,
447467 "--witness-override" ,"2"
448- ],extra_keys = [cold_key .private ])
468+ ],extra_keys = [cold_key .private ], raise_error = False )
449469
450- print ("Submitted :" ,txid )
470+ process = result .process
471+ if (process .returncode != 0 ):
451472
473+ if 'ConwayCommitteeIsUnknown' in process .stderr :
474+ print ("CC Cold Key Hash: " ,cold_key .id )
475+ print ("ERROR: Cold Key is not registered as CC Member" )
476+ else : ## Ledger allows delegating to non-existing drep.
477+ raise Exception ("Process failed " + process .stdout + process .stderr )
478+ else :
479+ print ("Submitted :" ,result .txid )
452480
453481
454482 def query_utxos (self , wallet : Wallet ):
455483 utxos = self .cardano_cli ("query" , "utxo" , ["--address" , wallet .address ], include_network = True , include_socket = True ,)
456484 return utxos
457485
458486 def query_utxos_json (self , wallet : Wallet ):
487+
459488 file_path = os .path .join (KEYS_DIR , 'utxo.json' )
460489 utxos = self .cardano_cli ("query" , "utxo" , ["--address" , wallet .address ,"--out-file" ,file_path ], include_network = True , include_socket = True ,)
461490
462491 with open (file_path ) as f :
463492 utxos = json .load (f )
493+ if len (utxos ) == 0 :
494+ print ("Wallet Adddress : " ,wallet .address )
495+ print (" ERROR: Missing Balance" )
496+
497+ exit (1 )
498+
499+
464500 return utxos
465501
466502
@@ -559,6 +595,7 @@ def vote(store:WalletStore,role):
559595
560596 elif command == "wallet" :
561597 store = WalletStore (KEYS_DIR )
598+ print ("Wallet Store :" ,KEYS_DIR )
562599 try :
563600 wallet = store .load_wallet ()
564601 print (f"Address : { wallet .address } " )
@@ -573,14 +610,19 @@ def vote(store:WalletStore,role):
573610
574611 try :
575612 wallet = store .load_cc_cold_keys ()
613+ hot_key = store .load_cc_hot_keys ()
614+
576615 print (f"CC key Hash : { wallet .id } " )
616+ print (f"CC Hot KeyHash: { hot_key .id } " )
617+
577618 except :
578619 print (":: CC keys not generated > gov-cli gen cc" )
579620
580621
581622 elif command == "register" :
582623 store = WalletStore (KEYS_DIR )
583624 wallet = store .load_wallet ()
625+
584626 if len (sys .argv )> 2 :
585627 if sys .argv [2 ] == "drep" :
586628 drep = store .load_drep_key ()
@@ -595,6 +637,7 @@ def vote(store:WalletStore,role):
595637 print ("Invalid option for register \" " + sys .argv [2 ]+ "\" . Expected \" drep\" or \" stake\" " )
596638
597639 else :
640+ print ("Registering stake key" )
598641 # Register stake key
599642 cli .register_stake (wallet )
600643 elif command == 'delegate' :
@@ -604,7 +647,7 @@ def vote(store:WalletStore,role):
604647 if len (sys .argv ) == 3 :
605648 cli .delegate (wallet ,drep ,sys .argv [2 ])
606649 else :
607- print ("Usage:\n gov-cli delegate [no-confidence|abstain|drep_id]" )
650+ print ("Usage:\n gov-cli delegate [no-confidence|abstain|drep_id|self ]" )
608651
609652 elif command == "propose" :
610653 store = WalletStore (KEYS_DIR )
@@ -641,7 +684,6 @@ def vote(store:WalletStore,role):
641684 sys .exit (1 )
642685
643686 # Query UTXOs for the specified address
644- print ("queryutxo" )
645687 wallet = Wallet (payment_vkey = None , payment_skey = None , stake_vkey = None , stake_skey = None , address = address )
646688 result = cli .query_utxos (wallet )
647689 print (result )
@@ -678,4 +720,17 @@ def vote(store:WalletStore,role):
678720 print ('Tx Submitted :' ,tx )
679721
680722 else :
681- help ()
723+ help ()
724+
725+ def check_if_file_exists (* files ):
726+ existing_files = []
727+ for file in files :
728+ if os .path .exists (file ):
729+ existing_files .append (file )
730+
731+ if len (existing_files ) > 0 :
732+ print ("File Already Exists:" )
733+ for file in existing_files :
734+ print (" -" ,file )
735+ print ("Backup and remove them to generate new keys" )
736+ exit (1 )
0 commit comments