44 "bytes"
55 "encoding/hex"
66 "fmt"
7- "io/ioutil "
7+ "io"
88 "net/http"
99
1010 "github.com/BoltzExchange/boltz-client/boltz"
@@ -174,7 +174,7 @@ func CreateReverseClaimTransaction(endpoint string, id string, claimLeaf string,
174174 defer resp .Body .Close ()
175175
176176 // Read response
177- body , err := ioutil .ReadAll (resp .Body )
177+ body , err := io .ReadAll (resp .Body )
178178 if err != nil {
179179 return fmt .Errorf ("failed to read response body: %v" , err )
180180 }
@@ -187,3 +187,132 @@ func CreateReverseClaimTransaction(endpoint string, id string, claimLeaf string,
187187
188188 return nil
189189}
190+
191+ func CreateRefundTransaction (endpoint string , id string , claimLeaf string , refundLeaf string , transactionHex string , privateKey string , servicePubKey string , feeRate int32 , timeoutBlockHeight int32 , destinationAddress string , lockupAddress string , isTestnet bool ) (string , error ) {
192+ var toCurrency = boltz .CurrencyBtc
193+
194+ var network * boltz.Network
195+ if isTestnet {
196+ network = boltz .TestNet
197+ } else {
198+ network = boltz .MainNet
199+ }
200+
201+ boltzApi := & boltz.Api {URL : endpoint }
202+
203+ // Decode the hex string to bytes
204+ privKeyBytes , err := hex .DecodeString (privateKey )
205+ if err != nil {
206+ fmt .Printf ("Failed to decode hex string: %v\n " , err )
207+ return "" , fmt .Errorf ("failed to decode hex string: %v" , err )
208+ }
209+
210+ // Create the private key using btcec
211+ keys , _ := btcec .PrivKeyFromBytes (privKeyBytes )
212+
213+ // Decode the hex string to bytes
214+ servicePubKeyBytes , err := hex .DecodeString (servicePubKey )
215+ if err != nil {
216+ return "" , fmt .Errorf ("error decoding service public key hex: %s" , err )
217+ }
218+
219+ // Parse the public key
220+ servicePubKeyFormatted , err := secp256k1 .ParsePubKey (servicePubKeyBytes )
221+ if err != nil {
222+ return "" , fmt .Errorf ("error parsing service public key %s" , err )
223+ }
224+
225+ // Creating the swapTree
226+ swapTree := & boltz.SwapTree {
227+ ClaimLeaf : leaf (claimLeaf ),
228+ RefundLeaf : leaf (refundLeaf ),
229+ }
230+ fmt .Println ("SwapTree created successfully" )
231+
232+ if err := swapTree .Init (false , false , keys , servicePubKeyFormatted ); err != nil {
233+ return "" , fmt .Errorf ("error initializing swap tree %s" , err )
234+ }
235+
236+ satPerVbyte := float64 (feeRate )
237+
238+ lockupTransaction , err := boltz .NewTxFromHex (toCurrency , transactionHex , nil )
239+ if err != nil {
240+ return "" , fmt .Errorf ("error constructing lockup tx %v" , err )
241+ }
242+ fmt .Println ("Lockup transaction constructed successfully" )
243+
244+ vout , _ , err := lockupTransaction .FindVout (network , lockupAddress )
245+ if err != nil {
246+ return "" , fmt .Errorf ("error finding vout %s" , err )
247+ }
248+
249+ refundTransaction , _ , err := boltz .ConstructTransaction (
250+ network ,
251+ boltz .CurrencyBtc ,
252+ []boltz.OutputDetails {
253+ {
254+ SwapId : id ,
255+ SwapType : boltz .NormalSwap ,
256+ Address : destinationAddress ,
257+ LockupTransaction : lockupTransaction ,
258+ Vout : vout ,
259+ Preimage : []byte {},
260+ PrivateKey : keys ,
261+ TimeoutBlockHeight : uint32 (timeoutBlockHeight ),
262+ SwapTree : swapTree ,
263+ Cooperative : true ,
264+ },
265+ },
266+ satPerVbyte ,
267+ boltzApi ,
268+ )
269+
270+ if err != nil {
271+ return "" , fmt .Errorf ("could not create refund transaction: %w" , err )
272+ }
273+ fmt .Println ("Refund transaction constructed successfully" )
274+
275+ txHex , err := refundTransaction .Serialize ()
276+ if err != nil {
277+ return "" , fmt .Errorf ("could not serialize refund transaction: %w" , err )
278+ }
279+ fmt .Println ("Refund transaction serialized successfully" )
280+
281+ var broadcastUrl string
282+ if isTestnet {
283+ broadcastUrl = "https://mempool.space/testnet/api/tx"
284+ } else {
285+ broadcastUrl = "https://mempool.space/api/tx"
286+ }
287+
288+ // Create HTTP request
289+ req , err := http .NewRequest ("POST" , broadcastUrl , bytes .NewBufferString (txHex ))
290+ if err != nil {
291+ return "" , fmt .Errorf ("failed to create HTTP request: %v" , err )
292+ }
293+ req .Header .Set ("Content-Type" , "application/json" )
294+
295+ // Execute HTTP request
296+ client := & http.Client {}
297+ resp , err := client .Do (req )
298+ if err != nil {
299+ return "" , fmt .Errorf ("failed to send HTTP request: %v" , err )
300+ }
301+ defer resp .Body .Close ()
302+
303+ // Read response
304+ body , err := io .ReadAll (resp .Body )
305+ if err != nil {
306+ return "" , fmt .Errorf ("failed to read response body: %v" , err )
307+ }
308+
309+ if resp .StatusCode != http .StatusOK {
310+ return "" , fmt .Errorf ("non-200 response: %d, body: %s" , resp .StatusCode , string (body ))
311+ }
312+
313+ txid := string (body )
314+ fmt .Printf ("Transaction broadcasted successfully: %s\n " , txid )
315+ fmt .Println ("Transaction broadcasted successfully" )
316+
317+ return txid , nil
318+ }
0 commit comments