11package lndmobile
22
33import (
4+ "bytes"
45 "encoding/hex"
56 "fmt"
7+ "io/ioutil"
8+ "net/http"
69
10+ "github.com/BoltzExchange/boltz-client/boltz"
711 "github.com/btcsuite/btcd/btcec/v2"
812 "github.com/btcsuite/btcd/txscript"
913 "github.com/decred/dcrd/dcrec/secp256k1/v4"
10- "github.com/BoltzExchange/boltz-client/boltz"
1114)
1215
1316func leaf (script string ) txscript.TapLeaf {
@@ -38,7 +41,7 @@ func CreateClaimTransaction(endpoint string, id string, claimLeaf string, refund
3841 if err != nil {
3942 return fmt .Errorf ("Error decoding service public key hex: %s" , err )
4043 }
41-
44+
4245 // Parse the public key
4346 servicePubKeyFormatted , err := secp256k1 .ParsePubKey (servicePubKeyBytes )
4447 if err != nil {
@@ -61,4 +64,126 @@ func CreateClaimTransaction(endpoint string, id string, claimLeaf string, refund
6164 }
6265
6366 return nil
64- }
67+ }
68+
69+ func CreateReverseClaimTransaction (endpoint string , id string , claimLeaf string , refundLeaf string , privateKey string , servicePubKey string , preimageHex string , transactionHex string , lockupAddress string , destinationAddress string , feeRate int32 , isTestnet bool ) error {
70+ var toCurrency = boltz .CurrencyBtc
71+ var network * boltz.Network
72+ if isTestnet {
73+ network = boltz .TestNet
74+ } else {
75+ network = boltz .MainNet
76+ }
77+
78+ boltzApi := & boltz.Api {URL : endpoint }
79+
80+ // Decode the hex string to bytes
81+ privKeyBytes , err := hex .DecodeString (privateKey )
82+ if err != nil {
83+ fmt .Printf ("Failed to decode hex string: %v" , err )
84+ }
85+
86+ // Create the private key using btcec
87+ keys , _ := btcec .PrivKeyFromBytes (privKeyBytes )
88+
89+ // Decode the hex string to bytes
90+ servicePubKeyBytes , err := hex .DecodeString (servicePubKey )
91+ if err != nil {
92+ return fmt .Errorf ("Error decoding service public key hex: %s" , err )
93+ }
94+
95+ // Parse the public key
96+ servicePubKeyFormatted , err := secp256k1 .ParsePubKey (servicePubKeyBytes )
97+ if err != nil {
98+ return fmt .Errorf ("Error parsing service public key %s" , err )
99+ }
100+
101+ swapTree := & boltz.SwapTree {
102+ ClaimLeaf : leaf (claimLeaf ),
103+ RefundLeaf : leaf (refundLeaf ),
104+ }
105+
106+ if err := swapTree .Init (false , false , keys , servicePubKeyFormatted ); err != nil {
107+ return fmt .Errorf ("Error initializing swap tree %s" , err )
108+ }
109+
110+ lockupTransaction , err := boltz .NewTxFromHex (toCurrency , transactionHex , nil )
111+ if err != nil {
112+ return fmt .Errorf ("Error constructing lockup tx %s" , err )
113+ }
114+
115+ vout , _ , err := lockupTransaction .FindVout (network , lockupAddress )
116+ if err != nil {
117+ return fmt .Errorf ("Error finding vout %s" , err )
118+ }
119+
120+ preimage , err := hex .DecodeString (preimageHex )
121+ if err != nil {
122+ return fmt .Errorf ("Error decoding preimage hex string: %w" , err )
123+ }
124+
125+ satPerVbyte := float64 (feeRate )
126+ claimTransaction , _ , err := boltz .ConstructTransaction (
127+ network ,
128+ boltz .CurrencyBtc ,
129+ []boltz.OutputDetails {
130+ {
131+ SwapId : id ,
132+ SwapType : boltz .ReverseSwap ,
133+ Address : destinationAddress ,
134+ LockupTransaction : lockupTransaction ,
135+ Vout : vout ,
136+ Preimage : preimage ,
137+ PrivateKey : keys ,
138+ SwapTree : swapTree ,
139+ Cooperative : true ,
140+ },
141+ },
142+ satPerVbyte ,
143+ boltzApi ,
144+ )
145+ if err != nil {
146+ return fmt .Errorf ("could not create claim transaction: %w" , err )
147+ }
148+
149+ txHex , err := claimTransaction .Serialize ()
150+ if err != nil {
151+ return fmt .Errorf ("could not serialize claim transaction: %w" , err )
152+ }
153+
154+ var broadcastUrl string
155+ if isTestnet {
156+ broadcastUrl = "https://mempool.space/testnet/api/tx"
157+ } else {
158+ broadcastUrl = "https://mempool.space/api/tx"
159+ }
160+
161+ // Create HTTP request
162+ req , err := http .NewRequest ("POST" , broadcastUrl , bytes .NewBufferString (txHex ))
163+ if err != nil {
164+ return fmt .Errorf ("failed to create HTTP request: %v" , err )
165+ }
166+ req .Header .Set ("Content-Type" , "application/json" )
167+
168+ // Execute HTTP request
169+ client := & http.Client {}
170+ resp , err := client .Do (req )
171+ if err != nil {
172+ return fmt .Errorf ("failed to send HTTP request: %v" , err )
173+ }
174+ defer resp .Body .Close ()
175+
176+ // Read response
177+ body , err := ioutil .ReadAll (resp .Body )
178+ if err != nil {
179+ return fmt .Errorf ("failed to read response body: %v" , err )
180+ }
181+
182+ if resp .StatusCode != http .StatusOK {
183+ return fmt .Errorf ("non-200 response: %d, body: %s" , resp .StatusCode , string (body ))
184+ }
185+
186+ fmt .Printf ("Transaction broadcasted successfully: %s\n " , string (body ))
187+
188+ return nil
189+ }
0 commit comments