@@ -6,68 +6,99 @@ import { regtestUtils } from './_regtest';
66import * as bitcoin from '../..' ;
77import { toXOnly } from '../../src/psbt/bip371' ;
88
9+ import { tweakSigner } from './taproot.utils' ;
10+
911const rng = require ( 'randombytes' ) ;
1012const regtest = regtestUtils . network ;
1113bitcoin . initEccLib ( ecc ) ;
1214const bip32 = BIP32Factory ( ecc ) ;
1315
1416describe ( 'bitcoinjs-lib (silent payments)' , ( ) => {
1517 it ( 'can create (and broadcast via 3PBP) a simple silent payment' , async ( ) => {
18+ // for simplicity the transactions in this test have only one input and one output
19+
1620 const { senderKeyPair, receiverKeyPair, sharedSecret } = initParticipants ( ) ;
17- // this is what the sender sees/scans
21+
22+ // this is what the sender sees/scans (from twitter bio, public forum, truck door)
1823 const silentPublicKey = toXOnly ( receiverKeyPair . publicKey ) ;
1924
20- // the input being spent
21- const { output : p2wpkhOutput } = bitcoin . payments . p2wpkh ( {
22- pubkey : senderKeyPair . publicKey ,
25+ const senderUtxo = await fundP2pkhUtxo ( senderKeyPair . publicKey ) ;
26+
27+ // amount to pay the silent address
28+ const payAmount = senderUtxo . value - 1e4 ;
29+ const {
30+ psbt : payPsbt ,
31+ address : tweakedSilentAddress ,
32+ } = buildPayToSilentAddress (
33+ senderUtxo . txId ,
34+ senderUtxo ,
35+ silentPublicKey ,
36+ payAmount ,
37+ sharedSecret ,
38+ ) ;
39+ payPsbt . signInput ( 0 , senderKeyPair ) . finalizeAllInputs ( ) ;
40+
41+ // the transaction paying to the silent address
42+ const payTx = payPsbt . extractTransaction ( ) ;
43+ await broadcastAndVerifyTx ( payTx , tweakedSilentAddress ! , payAmount ) ;
44+
45+ // the amount the receiver will spend
46+ const sendAmount = payAmount - 1e4 ;
47+ // the utxo with the tweaked silent address
48+ const receiverUtxo = { value : payAmount , script : payTx . outs [ 0 ] . script } ;
49+ const { psbt : spendPsbt , address } = buildSpendFromSilentAddress (
50+ payTx . getId ( ) ,
51+ receiverUtxo ,
52+ silentPublicKey ,
53+ sendAmount ,
54+ sharedSecret ,
55+ ) ;
56+
57+ const tweakedSigner = tweakSigner ( receiverKeyPair ! , {
58+ tweakHash : sharedSecret ,
2359 network : regtest ,
2460 } ) ;
61+ spendPsbt . signInput ( 0 , tweakedSigner ) . finalizeAllInputs ( ) ;
2562
26- // amount from faucet
27- const amount = 42e4 ;
28- // amount to send
29- const sendAmount = amount - 1e4 ;
30- // get faucet
31- const unspent = await regtestUtils . faucetComplex ( p2wpkhOutput ! , amount ) ;
32-
33- const psbt = new bitcoin . Psbt ( { network : regtest } ) ;
34- psbt . addInput ( {
35- hash : unspent . txId ,
36- index : 0 ,
37- witnessUtxo : { value : amount , script : p2wpkhOutput ! } ,
38- } ) ;
39-
40- // destination
41- const { address } = bitcoin . payments . p2tr ( {
42- internalPubkey : silentPublicKey ,
43- hash : sharedSecret ,
44- network : regtest ,
45- } ) ;
46- psbt . addOutput ( { value : sendAmount , address : address ! } ) ;
63+ // the transaction spending from the silent address
64+ const spendTx = spendPsbt . extractTransaction ( ) ;
65+ await broadcastAndVerifyTx ( spendTx , address ! , sendAmount ) ;
66+ } ) ;
67+ } ) ;
4768
48- psbt . signInput ( 0 , senderKeyPair ) ;
69+ async function fundP2pkhUtxo ( senderPubKey : Buffer ) {
70+ // the input being spent
71+ const { output : p2wpkhOutput } = bitcoin . payments . p2wpkh ( {
72+ pubkey : senderPubKey ,
73+ network : regtest ,
74+ } ) ;
4975
50- psbt . finalizeAllInputs ( ) ;
51- const tx = psbt . extractTransaction ( ) ;
52- const rawTx = tx . toBuffer ( ) ;
76+ // amount from faucet
77+ const amount = 42e4 ;
78+ // get faucet
79+ const unspent = await regtestUtils . faucetComplex ( p2wpkhOutput ! , amount ) ;
5380
54- const hex = rawTx . toString ( 'hex' ) ;
81+ return { value : amount , script : p2wpkhOutput ! , txId : unspent . txId } ;
82+ }
5583
56- await regtestUtils . broadcast ( hex ) ;
57- await regtestUtils . verify ( {
58- txId : tx . getId ( ) ,
59- address : address ! ,
60- vout : 0 ,
61- value : sendAmount ,
62- } ) ;
84+ async function broadcastAndVerifyTx (
85+ tx : bitcoin . Transaction ,
86+ address : string ,
87+ value : number ,
88+ ) {
89+ await regtestUtils . broadcast ( tx . toBuffer ( ) . toString ( 'hex' ) ) ;
90+ await regtestUtils . verify ( {
91+ txId : tx . getId ( ) ,
92+ address : address ! ,
93+ vout : 0 ,
94+ value,
6395 } ) ;
64- } ) ;
96+ }
6597
6698function initParticipants ( ) {
6799 const receiverKeyPair = bip32 . fromSeed ( rng ( 64 ) , regtest ) ;
68100 const senderKeyPair = bip32 . fromSeed ( rng ( 64 ) , regtest ) ;
69101
70-
71102 const senderSharedSecret = ecc . pointMultiply (
72103 receiverKeyPair . publicKey ,
73104 senderKeyPair . privateKey ! ,
@@ -88,4 +119,55 @@ function initParticipants() {
88119 } ;
89120}
90121
122+ function buildPayToSilentAddress (
123+ prevOutTxId : string ,
124+ witnessUtxo : { value : number ; script : Buffer } ,
125+ silentPublicKey : Buffer ,
126+ sendAmount : number ,
127+ sharedSecret : Buffer ,
128+ ) {
129+ const psbt = new bitcoin . Psbt ( { network : regtest } ) ;
130+ psbt . addInput ( {
131+ hash : prevOutTxId ,
132+ index : 0 ,
133+ witnessUtxo,
134+ } ) ;
135+
136+ // destination
137+ const { address } = bitcoin . payments . p2tr ( {
138+ internalPubkey : silentPublicKey ,
139+ hash : sharedSecret ,
140+ network : regtest ,
141+ } ) ;
142+ psbt . addOutput ( { value : sendAmount , address : address ! } ) ;
143+
144+ return { psbt, address } ;
145+ }
146+
147+ function buildSpendFromSilentAddress (
148+ prevOutTxId : string ,
149+ witnessUtxo : { value : number ; script : Buffer } ,
150+ silentPublicKey : Buffer ,
151+ sendAmount : number ,
152+ sharedSecret : Buffer ,
153+ ) {
154+ const psbt = new bitcoin . Psbt ( { network : regtest } ) ;
155+ psbt . addInput ( {
156+ hash : prevOutTxId ,
157+ index : 0 ,
158+ witnessUtxo,
159+ tapInternalKey : silentPublicKey ,
160+ tapMerkleRoot : sharedSecret ,
161+ } ) ;
162+
163+ // random address value, not important
164+ const address =
165+ 'bcrt1pqknex3jwpsaatu5e5dcjw70nac3fr5k5y3hcxr4hgg6rljzp59nqs6a0vh' ;
166+ psbt . addOutput ( {
167+ value : sendAmount ,
168+ address,
169+ } ) ;
170+
171+ return { psbt, address } ;
172+ }
91173const toBuffer = ( a : Uint8Array ) => Buffer . from ( a ) ;
0 commit comments