1+ #!/usr/bin/env python3
2+ """
3+ Finalize a PSBT (Partially Signed Bitcoin Transaction) to produce a broadcastable Bitcoin transaction.
4+
5+ This script serves as the finalizer step (as defined in BIP-174), assembling signatures and scripts
6+ into a complete transaction ready for broadcast.
7+
8+ Features:
9+ - Loads a base64-encoded PSBT from string or file
10+ - Finalizes all inputs by constructing scriptSig/scriptWitness
11+ - Optionally validates that all inputs are fully signed before finalization
12+ - Outputs the raw hex-encoded Bitcoin transaction
13+
14+ Usage:
15+ python finalize_psbt.py <psbt_base64_string>
16+ python finalize_psbt.py --file <psbt_file.txt>
17+ python finalize_psbt.py --file <psbt_file.txt> --validate
18+
19+ Arguments:
20+ <psbt_base64_string> PSBT data as a base64-encoded string
21+ --file <psbt_file.txt> Load PSBT from a file
22+ --validate (Optional) Enforce validation before finalizing
23+
24+ Returns:
25+ Hex-encoded, fully signed Bitcoin transaction ready for broadcast
26+ """
27+
28+
29+ import argparse
30+ import base64
31+ import sys
32+ from bitcoinutils .setup import setup
33+ from bitcoinutils .psbt import PSBT
34+
35+
36+ def main ():
37+ """
38+ Main function for PSBT finalization.
39+
40+ Usage:
41+ python finalize_psbt.py <psbt_base64_string>
42+ python finalize_psbt.py --file <psbt_file.txt>
43+ python finalize_psbt.py --file <psbt_file.txt> --validate
44+ """
45+ parser = argparse .ArgumentParser (description = 'Finalize a PSBT and create a transaction.' )
46+ parser .add_argument ('psbt' , nargs = '?' , help = 'Base64-encoded PSBT string' )
47+ parser .add_argument ('--file' , help = 'Text file containing base64 PSBT' )
48+ parser .add_argument ('--validate' , action = 'store_true' , help = 'Validate finalized transaction' )
49+ parser .add_argument ('--network' , choices = ['mainnet' , 'testnet' ], default = 'testnet' ,
50+ help = 'Bitcoin network (default: testnet)' )
51+
52+ args = parser .parse_args ()
53+
54+ # Setup the library for specified network
55+ setup (args .network )
56+
57+ try :
58+ # Load PSBT from input
59+ if args .file :
60+ with open (args .file , 'r' ) as f :
61+ psbt_b64 = f .read ().strip ()
62+ elif args .psbt :
63+ psbt_b64 = args .psbt
64+ else :
65+ print ("Error: Provide either base64 string or --file option." )
66+ print ("Use --help for usage information." )
67+ return 1
68+
69+ # Create PSBT object
70+ psbt = PSBT .from_base64 (psbt_b64 )
71+
72+ # Finalize the PSBT
73+ if args .validate :
74+ final_tx , validation = psbt .finalize (validate = True )
75+
76+ print ("Finalized Transaction (Hex):" )
77+ print (final_tx .serialize ())
78+
79+ print ("\n Validation Report:" )
80+ print (f"Valid: { validation ['valid' ]} " )
81+ print (f"Transaction ID: { validation ['txid' ]} " )
82+ print (f"Size: { validation ['size' ]} bytes" )
83+ print (f"Virtual Size: { validation ['vsize' ]} vbytes" )
84+
85+ if validation ['errors' ]:
86+ print ("Errors:" )
87+ for error in validation ['errors' ]:
88+ print (f" - { error } " )
89+
90+ if validation ['warnings' ]:
91+ print ("Warnings:" )
92+ for warning in validation ['warnings' ]:
93+ print (f" - { warning } " )
94+
95+ else :
96+ final_tx = psbt .finalize (validate = False )
97+ print ("Finalized Transaction (Hex):" )
98+ print (final_tx .serialize ())
99+
100+ print (f"\n Transaction ready to broadcast!" )
101+ print (f"Use 'bitcoin-cli sendrawtransaction { final_tx .serialize ()} ' to broadcast" )
102+
103+ return 0
104+
105+ except Exception as e :
106+ print (f"Error: { str (e )} " )
107+ return 1
108+
109+
110+ if __name__ == "__main__" :
111+ sys .exit (main ())
0 commit comments