14
14
from qrl .core import config
15
15
from qrl .core .Wallet import Wallet , WalletDecryptionError
16
16
from qrl .core .misc .helper import parse_hexblob , parse_qaddress
17
+ from qrl .core .MultiSigAddressState import MultiSigAddressState
17
18
from qrl .core .txs .MessageTransaction import MessageTransaction
18
19
from qrl .core .txs .SlaveTransaction import SlaveTransaction
19
20
from qrl .core .txs .TokenTransaction import TokenTransaction
20
21
from qrl .core .txs .Transaction import Transaction
21
22
from qrl .core .txs .TransferTokenTransaction import TransferTokenTransaction
22
23
from qrl .core .txs .TransferTransaction import TransferTransaction
24
+ from qrl .core .txs .multisig .MultiSigCreate import MultiSigCreate
25
+ from qrl .core .txs .multisig .MultiSigSpend import MultiSigSpend
23
26
from qrl .crypto .xmss import XMSS , hash_functions
24
27
from qrl .generated import qrl_pb2_grpc , qrl_pb2
25
28
@@ -181,15 +184,15 @@ def _quanta_to_shor(x: Decimal, base=Decimal(config.dev.shor_per_quanta)) -> int
181
184
return int (Decimal (x * base ).to_integral_value ())
182
185
183
186
184
- def _parse_dsts_amounts (addresses : str , amounts : str , token_decimals : int = 0 ):
187
+ def _parse_dsts_amounts (addresses : str , amounts : str , token_decimals : int = 0 , check_multi_sig_address = False ):
185
188
"""
186
189
'Qaddr1 Qaddr2...' -> [\\ xcx3\\ xc2, \\ xc2d\\ xc3]
187
190
'10 10' -> [10e9, 10e9] (in shor)
188
191
:param addresses:
189
192
:param amounts:
190
193
:return:
191
194
"""
192
- addresses_split = [parse_qaddress (addr ) for addr in addresses .split (' ' )]
195
+ addresses_split = [parse_qaddress (addr , check_multi_sig_address ) for addr in addresses .split (' ' )]
193
196
194
197
if token_decimals != 0 :
195
198
multiplier = Decimal (10 ** int (token_decimals ))
@@ -471,11 +474,12 @@ def tx_push(ctx, txblob):
471
474
@qrl .command ()
472
475
@click .option ('--src' , type = str , default = '' , prompt = True , help = 'signer QRL address' )
473
476
@click .option ('--master' , type = str , default = '' , prompt = True , help = 'master QRL address' )
477
+ @click .option ('--addr_to' , type = str , default = '' , prompt = True , help = 'QRL Address receiving this message (optional)' )
474
478
@click .option ('--message' , type = str , prompt = True , help = 'Message (max 80 bytes)' )
475
479
@click .option ('--fee' , type = Decimal , default = 0.0 , prompt = True , help = 'fee in Quanta' )
476
480
@click .option ('--ots_key_index' , default = 1 , prompt = True , help = 'OTS key Index (1..XMSS num signatures)' )
477
481
@click .pass_context
478
- def tx_message (ctx , src , master , message , fee , ots_key_index ):
482
+ def tx_message (ctx , src , master , addr_to , message , fee , ots_key_index ):
479
483
"""
480
484
Message Transaction
481
485
"""
@@ -491,6 +495,7 @@ def tx_message(ctx, src, master, message, fee, ots_key_index):
491
495
src_xmss .set_ots_index (ots_key_index )
492
496
493
497
message = message .encode ()
498
+ addr_to = parse_qaddress (addr_to , False )
494
499
495
500
master_addr = None
496
501
if master :
@@ -503,6 +508,7 @@ def tx_message(ctx, src, master, message, fee, ots_key_index):
503
508
try :
504
509
stub = ctx .obj .get_stub_public_api ()
505
510
tx = MessageTransaction .create (message_hash = message ,
511
+ addr_to = addr_to ,
506
512
fee = fee_shor ,
507
513
xmss_pk = address_src_pk ,
508
514
master_addr = master_addr )
@@ -516,6 +522,159 @@ def tx_message(ctx, src, master, message, fee, ots_key_index):
516
522
print ("Error {}" .format (str (e )))
517
523
518
524
525
+ @qrl .command ()
526
+ @click .option ('--src' , type = str , default = '' , prompt = True , help = 'source QRL address' )
527
+ @click .option ('--master' , type = str , default = '' , prompt = True , help = 'master QRL address' )
528
+ @click .option ('--threshold' , default = 0 , prompt = True , help = 'Threshold' )
529
+ @click .option ('--fee' , type = Decimal , default = 0.0 , prompt = True , help = 'fee in Quanta' )
530
+ @click .option ('--ots_key_index' , default = 1 , prompt = True , help = 'OTS key Index (1..XMSS num signatures)' )
531
+ @click .pass_context
532
+ def tx_multi_sig_create (ctx , src , master , threshold , fee , ots_key_index ):
533
+ """
534
+ Creates Multi Sig Create Transaction, that results into the formation of new multi_sig_address if accepted.
535
+ """
536
+ signatories = []
537
+ weights = []
538
+ while True :
539
+ address = click .prompt ('Address of Signatory ' , default = '' )
540
+ if address == '' :
541
+ break
542
+ weight = int (click .prompt ('Weight ' ))
543
+ signatories .append (parse_qaddress (address ))
544
+ weights .append (weight )
545
+
546
+ try :
547
+ _ , src_xmss = _select_wallet (ctx , src )
548
+ if not src_xmss :
549
+ click .echo ("A local wallet is required to sign the transaction" )
550
+ quit (1 )
551
+
552
+ address_src_pk = src_xmss .pk
553
+
554
+ ots_key_index = validate_ots_index (ots_key_index , src_xmss )
555
+ src_xmss .set_ots_index (ots_key_index )
556
+
557
+ master_addr = None
558
+ if master_addr :
559
+ master_addr = parse_qaddress (master )
560
+ # FIXME: This could be problematic. Check
561
+ fee_shor = _quanta_to_shor (fee )
562
+
563
+ except KeyboardInterrupt :
564
+ click .echo ("Terminated by user" )
565
+ quit (1 )
566
+ except Exception as e :
567
+ click .echo ("Error validating arguments: {}" .format (e ))
568
+ quit (1 )
569
+
570
+ try :
571
+ stub = ctx .obj .get_stub_public_api ()
572
+ tx = MultiSigCreate .create (signatories = signatories ,
573
+ weights = weights ,
574
+ threshold = threshold ,
575
+ fee = fee_shor ,
576
+ xmss_pk = address_src_pk ,
577
+ master_addr = master_addr )
578
+
579
+ tx .sign (src_xmss )
580
+
581
+ push_transaction_req = qrl_pb2 .PushTransactionReq (transaction_signed = tx .pbdata )
582
+ push_transaction_resp = stub .PushTransaction (push_transaction_req , timeout = CONNECTION_TIMEOUT )
583
+
584
+ print (push_transaction_resp .error_code )
585
+ print ('Multi sig Address Q{}' .format (bin2hstr (MultiSigAddressState .generate_multi_sig_address (tx .txhash ))))
586
+ except Exception as e :
587
+ print ("Error {}" .format (str (e )))
588
+
589
+
590
+ @qrl .command ()
591
+ @click .option ('--src' , type = str , default = '' , prompt = True , help = 'signer QRL address' )
592
+ @click .option ('--master' , type = str , default = '' , help = 'master QRL address' )
593
+ @click .option ('--multi_sig_address' , type = str , default = '' , prompt = True , help = 'signer Multi Sig Address' )
594
+ @click .option ('--dsts' , type = str , prompt = True , help = 'List of destination addresses' )
595
+ @click .option ('--amounts' , type = str , prompt = True , help = 'List of amounts to transfer (Quanta)' )
596
+ @click .option ('--expiry_block_number' , type = int , prompt = True , help = 'Expiry Blocknumber' )
597
+ @click .option ('--fee' , type = Decimal , default = 0.0 , prompt = True , help = 'fee in Quanta' )
598
+ @click .option ('--ots_key_index' , default = 1 , help = 'OTS key Index (1..XMSS num signatures)' )
599
+ @click .pass_context
600
+ def tx_multi_sig_spend (ctx , src , master , multi_sig_address , dsts , amounts , expiry_block_number , fee , ots_key_index ):
601
+ """
602
+ Transfer coins from src to dsts
603
+ """
604
+ address_src_pk = None
605
+ master_addr = None
606
+
607
+ addresses_dst = []
608
+ shor_amounts = []
609
+ fee_shor = []
610
+
611
+ signing_object = None
612
+
613
+ try :
614
+ # Retrieve signing object
615
+ selected_wallet = _select_wallet (ctx , src )
616
+ if selected_wallet is None or len (selected_wallet ) != 2 :
617
+ click .echo ("A wallet was not found" )
618
+ quit (1 )
619
+
620
+ _ , src_xmss = selected_wallet
621
+
622
+ if not src_xmss :
623
+ click .echo ("A local wallet is required to sign the transaction" )
624
+ quit (1 )
625
+
626
+ address_src_pk = src_xmss .pk
627
+
628
+ ots_key_index = validate_ots_index (ots_key_index , src_xmss )
629
+ src_xmss .set_ots_index (ots_key_index )
630
+
631
+ signing_object = src_xmss
632
+
633
+ # Get and validate other inputs
634
+ if master :
635
+ master_addr = parse_qaddress (master )
636
+
637
+ addresses_dst , shor_amounts = _parse_dsts_amounts (dsts , amounts , check_multi_sig_address = True )
638
+ fee_shor = _quanta_to_shor (fee )
639
+ except Exception as e :
640
+ click .echo ("Error validating arguments: {}" .format (e ))
641
+ quit (1 )
642
+ multi_sig_address = bytes (hstr2bin (multi_sig_address [1 :]))
643
+ try :
644
+ # MultiSigSpend transaction
645
+ tx = MultiSigSpend .create (multi_sig_address = multi_sig_address ,
646
+ addrs_to = addresses_dst ,
647
+ amounts = shor_amounts ,
648
+ expiry_block_number = expiry_block_number ,
649
+ fee = fee_shor ,
650
+ xmss_pk = address_src_pk ,
651
+ master_addr = master_addr )
652
+
653
+ # Sign transaction
654
+ tx .sign (signing_object )
655
+
656
+ if not tx .validate ():
657
+ print ("It was not possible to validate the signature" )
658
+ quit (1 )
659
+
660
+ print ("\n Transaction Blob (signed): \n " )
661
+ txblob = tx .pbdata .SerializeToString ()
662
+ txblobhex = hexlify (txblob ).decode ()
663
+ print (txblobhex )
664
+
665
+ # Push transaction
666
+ print ()
667
+ print ("Sending to a QRL Node..." )
668
+ stub = ctx .obj .get_stub_public_api ()
669
+ push_transaction_req = qrl_pb2 .PushTransactionReq (transaction_signed = tx .pbdata )
670
+ push_transaction_resp = stub .PushTransaction (push_transaction_req , timeout = CONNECTION_TIMEOUT )
671
+
672
+ # Print result
673
+ print (push_transaction_resp )
674
+ except Exception as e :
675
+ print ("Error {}" .format (str (e )))
676
+
677
+
519
678
def base64tohex (data ):
520
679
return hexlify (a2b_base64 (data ))
521
680
@@ -534,10 +693,11 @@ def tx_unbase64(tx_json_str):
534
693
@click .option ('--master' , type = str , default = '' , help = 'master QRL address' )
535
694
@click .option ('--dsts' , type = str , prompt = True , help = 'List of destination addresses' )
536
695
@click .option ('--amounts' , type = str , prompt = True , help = 'List of amounts to transfer (Quanta)' )
696
+ @click .option ('--message_data' , type = str , prompt = True , help = 'Message (Optional)' )
537
697
@click .option ('--fee' , type = Decimal , default = 0.0 , prompt = True , help = 'fee in Quanta' )
538
698
@click .option ('--ots_key_index' , default = 1 , help = 'OTS key Index (1..XMSS num signatures)' )
539
699
@click .pass_context
540
- def tx_transfer (ctx , src , master , dsts , amounts , fee , ots_key_index ):
700
+ def tx_transfer (ctx , src , master , dsts , amounts , message_data , fee , ots_key_index ):
541
701
"""
542
702
Transfer coins from src to dsts
543
703
"""
@@ -549,6 +709,7 @@ def tx_transfer(ctx, src, master, dsts, amounts, fee, ots_key_index):
549
709
fee_shor = []
550
710
551
711
signing_object = None
712
+ message_data = message_data .encode ()
552
713
553
714
try :
554
715
# Retrieve signing object
@@ -573,8 +734,7 @@ def tx_transfer(ctx, src, master, dsts, amounts, fee, ots_key_index):
573
734
# Get and validate other inputs
574
735
if master :
575
736
master_addr = parse_qaddress (master )
576
-
577
- addresses_dst , shor_amounts = _parse_dsts_amounts (dsts , amounts )
737
+ addresses_dst , shor_amounts = _parse_dsts_amounts (dsts , amounts , check_multi_sig_address = True )
578
738
fee_shor = _quanta_to_shor (fee )
579
739
except Exception as e :
580
740
click .echo ("Error validating arguments: {}" .format (e ))
@@ -584,6 +744,7 @@ def tx_transfer(ctx, src, master, dsts, amounts, fee, ots_key_index):
584
744
# Create transaction
585
745
tx = TransferTransaction .create (addrs_to = addresses_dst ,
586
746
amounts = shor_amounts ,
747
+ message_data = message_data ,
587
748
fee = fee_shor ,
588
749
xmss_pk = address_src_pk ,
589
750
master_addr = master_addr )
@@ -605,7 +766,6 @@ def tx_transfer(ctx, src, master, dsts, amounts, fee, ots_key_index):
605
766
print (txblobhex )
606
767
607
768
# Push transaction
608
- print ()
609
769
print ("Sending to a QRL Node..." )
610
770
stub = ctx .obj .get_stub_public_api ()
611
771
push_transaction_req = qrl_pb2 .PushTransactionReq (transaction_signed = tx .pbdata )
@@ -877,3 +1037,4 @@ def main():
877
1037
878
1038
if __name__ == '__main__' :
879
1039
main ()
1040
+
0 commit comments