Skip to content

Commit 726ecdd

Browse files
committed
Reverse swaps
1 parent bbec3d6 commit 726ecdd

File tree

1 file changed

+128
-3
lines changed

1 file changed

+128
-3
lines changed

mobile/swaps.go

Lines changed: 128 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package lndmobile
22

33
import (
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

1316
func 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

Comments
 (0)