@@ -10,6 +10,7 @@ import (
1010 "github.com/btcsuite/btcd/btcutil"
1111 "github.com/btcsuite/btcd/btcutil/psbt"
1212 "github.com/btcsuite/btcd/chaincfg"
13+ "github.com/btcsuite/btcd/chaincfg/chainhash"
1314 "github.com/btcsuite/btcd/txscript"
1415
1516 "github.com/sideprotocol/side/bitcoin"
@@ -75,11 +76,12 @@ func CreateTaprootAddress(internalKey *secp256k1.PublicKey, scripts [][]byte, pa
7576// Assume that the given pub keys are valid
7677func CreateVaultAddress (borrowerPubKey string , borrowerAuthPubKey string , dcmPubKey string , finalTimeout int64 ) (string , error ) {
7778 borrowerPubKeyBytes , _ := hex .DecodeString (borrowerPubKey )
79+ borrowerAuthPubKeyBytes , _ := hex .DecodeString (borrowerAuthPubKey )
7880 dcmPubKeyBytes , _ := hex .DecodeString (dcmPubKey )
7981
8082 internalKey := GetInternalKey (borrowerPubKeyBytes , dcmPubKeyBytes )
8183
82- liquidationScript , repaymentScript , timeoutRefundScript , err := GetVaultScripts (borrowerPubKey , borrowerAuthPubKey , dcmPubKey , finalTimeout )
84+ liquidationScript , repaymentScript , timeoutRefundScript , err := GetVaultScripts (borrowerPubKeyBytes , borrowerAuthPubKeyBytes , dcmPubKeyBytes , finalTimeout )
8385 if err != nil {
8486 return "" , err
8587 }
@@ -95,26 +97,21 @@ func CreateVaultAddress(borrowerPubKey string, borrowerAuthPubKey string, dcmPub
9597}
9698
9799// GetVaultScripts gets the scripts associated the underlying vault address from the given params
98- // Assume that the given pub keys are valid
99- func GetVaultScripts (borrowerPubKey string , borrowerAuthPubKey string , dcmPubKey string , finalTimeout int64 ) ([]byte , []byte , []byte , error ) {
100- borrowerPubKeyBytes , _ := hex .DecodeString (borrowerPubKey )
101- borrowerAuthPubKeyBytes , _ := hex .DecodeString (borrowerAuthPubKey )
102- dcmPubKeyBytes , _ := hex .DecodeString (dcmPubKey )
103-
100+ func GetVaultScripts (borrowerPubKey []byte , borrowerAuthPubKey []byte , dcmPubKey []byte , finalTimeout int64 ) ([]byte , []byte , []byte , error ) {
104101 // liquidation script
105- liquidationScript , err := CreateMultisigScript ([][]byte {borrowerAuthPubKeyBytes , dcmPubKeyBytes })
102+ liquidationScript , err := CreateMultisigScript ([][]byte {borrowerAuthPubKey , dcmPubKey })
106103 if err != nil {
107104 return nil , nil , nil , err
108105 }
109106
110107 // repayment script
111- repaymentScript , err := CreateMultisigScript ([][]byte {borrowerPubKeyBytes , dcmPubKeyBytes })
108+ repaymentScript , err := CreateMultisigScript ([][]byte {borrowerPubKey , dcmPubKey })
112109 if err != nil {
113110 return nil , nil , nil , err
114111 }
115112
116113 // refund script
117- timeoutRefundScript , err := CreatePubKeyTimeLockScript (borrowerPubKeyBytes , finalTimeout )
114+ timeoutRefundScript , err := CreatePubKeyTimeLockScript (borrowerPubKey , finalTimeout )
118115 if err != nil {
119116 return nil , nil , nil , err
120117 }
@@ -145,20 +142,44 @@ func GetInternalKey(borrowerPubKey []byte, dcmPubKey []byte) *btcec.PublicKey {
145142 return btcec .NewPublicKey (& P .X , & P .Y )
146143}
147144
145+ // GetTapscriptTree gets the tapscript tree built from the given tapscripts
146+ // NOTE: Duplicate scripts are filtered out
148147func GetTapscriptTree (scripts [][]byte ) * txscript.IndexedTapScriptTree {
149148 leaves := []txscript.TapLeaf {}
149+ leafMap := make (map [chainhash.Hash ]bool )
150150
151151 for _ , script := range scripts {
152- leaves = append (leaves , txscript .NewBaseTapLeaf (script ))
152+ leaf := txscript .NewBaseTapLeaf (script )
153+ hash := leaf .TapHash ()
154+
155+ if ! leafMap [hash ] {
156+ leaves = append (leaves , leaf )
157+ leafMap [hash ] = true
158+ }
153159 }
154160
155161 tree := txscript .AssembleTaprootScriptTree (leaves ... )
156162
157163 return tree
158164}
159165
160- func GetControlBlock (pubKey * secp256k1.PublicKey , proof txscript.TapscriptProof ) ([]byte , error ) {
161- controlBlock := proof .ToControlBlock (pubKey )
166+ // GetTapscriptMerkleProof gets the merkle proof of the specified script from the given tapscript tree
167+ func GetTapscriptMerkleProof (tree * txscript.IndexedTapScriptTree , script []byte ) txscript.TapscriptProof {
168+ leaf := txscript .NewBaseTapLeaf (script )
169+
170+ index , ok := tree .LeafProofIndex [leaf .TapHash ()]
171+ if ! ok {
172+ return txscript.TapscriptProof {}
173+ }
174+
175+ return tree .LeafMerkleProofs [index ]
176+ }
177+
178+ // GetControlBlock gets the control block for the given tapscript
179+ // Assume that the given script exists in the tapscript tree
180+ func GetControlBlock (tree * txscript.IndexedTapScriptTree , script []byte , internalKey * secp256k1.PublicKey ) ([]byte , error ) {
181+ proof := GetTapscriptMerkleProof (tree , script )
182+ controlBlock := proof .ToControlBlock (internalKey )
162183
163184 controlBlockBz , err := controlBlock .ToBytes ()
164185 if err != nil {
0 commit comments