1
1
import { Hash } from 'fast-sha256' ;
2
+ import { Psbt } from '@bitgo/utxo-lib' ;
2
3
3
4
export const BIP322_TAG = 'BIP0322-signed-message' ;
4
5
@@ -22,3 +23,42 @@ export function hashMessageWithTag(message: string | Buffer, tag = BIP322_TAG):
22
23
const messageHash = messageHasher . digest ( ) ;
23
24
return Buffer . from ( messageHash ) ;
24
25
}
26
+
27
+ /**
28
+ * Build a BIP322 "to spend" transaction
29
+ * Source: https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki#full
30
+ *
31
+ * @param {Buffer } scriptPubKey - The scriptPubKey to use for the output
32
+ * @param {string | Buffer } message - The message to include in the transaction
33
+ * @param {Buffer } [tag=BIP322_TAG] - The tag to use for hashing, defaults to BIP322_TAG.
34
+ * @returns {string } - The hex representation of the constructed transaction
35
+ */
36
+ export function buildToSpendTransaction ( scriptPubKey : Buffer , message : string | Buffer , tag = BIP322_TAG ) : string {
37
+ // Create PSBT object for constructing the transaction
38
+ const psbt = new Psbt ( ) ;
39
+ // Set default value for nVersion and nLockTime
40
+ psbt . setVersion ( 0 ) ; // nVersion = 0
41
+ psbt . setLocktime ( 0 ) ; // nLockTime = 0
42
+ // Compute the message hash - SHA256(SHA256(tag) || SHA256(tag) || message)
43
+ const messageHash = hashMessageWithTag ( message , tag ) ;
44
+ // Construct the scriptSig - OP_0 PUSH32[ message_hash ]
45
+ const scriptSigPartOne = new Uint8Array ( [ 0x00 , 0x20 ] ) ; // OP_0 PUSH32
46
+ const scriptSig = new Uint8Array ( scriptSigPartOne . length + messageHash . length ) ;
47
+ scriptSig . set ( scriptSigPartOne ) ;
48
+ scriptSig . set ( messageHash , scriptSigPartOne . length ) ;
49
+ // Set the input
50
+ psbt . addInput ( {
51
+ hash : '0' . repeat ( 64 ) , // vin[0].prevout.hash = 0000...000
52
+ index : 0xffffffff , // vin[0].prevout.n = 0xFFFFFFFF
53
+ sequence : 0 , // vin[0].nSequence = 0
54
+ finalScriptSig : Buffer . from ( scriptSig ) , // vin[0].scriptSig = OP_0 PUSH32[ message_hash ]
55
+ witnessScript : Buffer . from ( [ ] ) , // vin[0].scriptWitness = []
56
+ } ) ;
57
+ // Set the output
58
+ psbt . addOutput ( {
59
+ value : BigInt ( 0 ) , // vout[0].nValue = 0
60
+ script : scriptPubKey , // vout[0].scriptPubKey = message_challenge
61
+ } ) ;
62
+ // Return transaction
63
+ return psbt . extractTransaction ( ) . toHex ( ) ;
64
+ }
0 commit comments