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