Skip to content

Commit 33a049f

Browse files
authored
Merge pull request #184 from bhandras/native-segwit
support for native segwit loop-in
2 parents b070a4f + c6e3829 commit 33a049f

16 files changed

+601
-270
lines changed

client.go

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -194,17 +194,17 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) {
194194
}
195195

196196
swaps = append(swaps, &SwapInfo{
197-
SwapType: swap.TypeOut,
198-
SwapContract: swp.Contract.SwapContract,
199-
SwapStateData: swp.State(),
200-
SwapHash: swp.Hash,
201-
LastUpdate: swp.LastUpdateTime(),
202-
HtlcAddress: htlc.Address,
197+
SwapType: swap.TypeOut,
198+
SwapContract: swp.Contract.SwapContract,
199+
SwapStateData: swp.State(),
200+
SwapHash: swp.Hash,
201+
LastUpdate: swp.LastUpdateTime(),
202+
HtlcAddressP2WSH: htlc.Address,
203203
})
204204
}
205205

206206
for _, swp := range loopInSwaps {
207-
htlc, err := swap.NewHtlc(
207+
htlcNP2WSH, err := swap.NewHtlc(
208208
swp.Contract.CltvExpiry, swp.Contract.SenderKey,
209209
swp.Contract.ReceiverKey, swp.Hash, swap.HtlcNP2WSH,
210210
s.lndServices.ChainParams,
@@ -213,13 +213,23 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) {
213213
return nil, err
214214
}
215215

216+
htlcP2WSH, err := swap.NewHtlc(
217+
swp.Contract.CltvExpiry, swp.Contract.SenderKey,
218+
swp.Contract.ReceiverKey, swp.Hash, swap.HtlcP2WSH,
219+
s.lndServices.ChainParams,
220+
)
221+
if err != nil {
222+
return nil, err
223+
}
224+
216225
swaps = append(swaps, &SwapInfo{
217-
SwapType: swap.TypeIn,
218-
SwapContract: swp.Contract.SwapContract,
219-
SwapStateData: swp.State(),
220-
SwapHash: swp.Hash,
221-
LastUpdate: swp.LastUpdateTime(),
222-
HtlcAddress: htlc.Address,
226+
SwapType: swap.TypeIn,
227+
SwapContract: swp.Contract.SwapContract,
228+
SwapStateData: swp.State(),
229+
SwapHash: swp.Hash,
230+
LastUpdate: swp.LastUpdateTime(),
231+
HtlcAddressP2WSH: htlcP2WSH.Address,
232+
HtlcAddressNP2WSH: htlcNP2WSH.Address,
223233
})
224234
}
225235

@@ -464,15 +474,15 @@ func (s *Client) waitForInitialized(ctx context.Context) error {
464474

465475
// LoopIn initiates a loop in swap.
466476
func (s *Client) LoopIn(globalCtx context.Context,
467-
request *LoopInRequest) (*lntypes.Hash, btcutil.Address, error) {
477+
request *LoopInRequest) (*LoopInSwapInfo, error) {
468478

469479
log.Infof("Loop in %v (last hop: %v)",
470480
request.Amount,
471481
request.LastHop,
472482
)
473483

474484
if err := s.waitForInitialized(globalCtx); err != nil {
475-
return nil, nil, err
485+
return nil, err
476486
}
477487

478488
// Create a new swap object for this swap.
@@ -486,15 +496,20 @@ func (s *Client) LoopIn(globalCtx context.Context,
486496
globalCtx, &swapCfg, initiationHeight, request,
487497
)
488498
if err != nil {
489-
return nil, nil, err
499+
return nil, err
490500
}
491501

492502
// Post swap to the main loop.
493503
s.executor.initiateSwap(globalCtx, swap)
494504

495505
// Return hash so that the caller can identify this swap in the updates
496506
// stream.
497-
return &swap.hash, swap.htlc.Address, nil
507+
swapInfo := &LoopInSwapInfo{
508+
SwapHash: swap.hash,
509+
HtlcAddressP2WSH: swap.htlcP2WSH.Address,
510+
HtlcAddressNP2WSH: swap.htlcNP2WSH.Address,
511+
}
512+
return swapInfo, nil
498513
}
499514

500515
// LoopInQuote takes an amount and returns a break down of estimated

cmd/loop/loopin.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,10 @@ func loopIn(ctx *cli.Context) error {
153153

154154
fmt.Printf("Swap initiated\n")
155155
fmt.Printf("ID: %v\n", resp.Id)
156-
fmt.Printf("HTLC address: %v\n", resp.HtlcAddress)
156+
if external {
157+
fmt.Printf("HTLC address (NP2WSH): %v\n", resp.HtlcAddressNp2Wsh)
158+
}
159+
fmt.Printf("HTLC address (P2WSH): %v\n", resp.HtlcAddressP2Wsh)
157160
fmt.Println()
158161
fmt.Printf("Run `loop monitor` to monitor progress.\n")
159162

cmd/loop/main.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,24 @@ func parseAmt(text string) (btcutil.Amount, error) {
225225
}
226226

227227
func logSwap(swap *looprpc.SwapStatus) {
228-
fmt.Printf("%v %v %v %v - %v",
229-
time.Unix(0, swap.LastUpdateTime).Format(time.RFC3339),
230-
swap.Type, swap.State, btcutil.Amount(swap.Amt),
231-
swap.HtlcAddress,
232-
)
228+
if swap.Type == looprpc.SwapType_LOOP_OUT {
229+
fmt.Printf("%v %v %v %v - %v",
230+
time.Unix(0, swap.LastUpdateTime).Format(time.RFC3339),
231+
swap.Type, swap.State, btcutil.Amount(swap.Amt),
232+
swap.HtlcAddressP2Wsh,
233+
)
234+
} else {
235+
fmt.Printf("%v %v %v %v -",
236+
time.Unix(0, swap.LastUpdateTime).Format(time.RFC3339),
237+
swap.Type, swap.State, btcutil.Amount(swap.Amt))
238+
if swap.HtlcAddressP2Wsh != "" {
239+
fmt.Printf(" P2WSH: %v", swap.HtlcAddressP2Wsh)
240+
}
241+
242+
if swap.HtlcAddressNp2Wsh != "" {
243+
fmt.Printf(" NP2WSH: %v", swap.HtlcAddressNp2Wsh)
244+
}
245+
}
233246

234247
if swap.State != looprpc.SwapState_INITIATED &&
235248
swap.State != looprpc.SwapState_HTLC_PUBLISHED &&

interface.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,21 @@ type LoopInQuote struct {
235235
CltvDelta int32
236236
}
237237

238+
// LoopInSwapInfo contains essential information of a loop-in swap after the
239+
// swap is initiated.
240+
type LoopInSwapInfo struct { // nolint
241+
// SwapHash contains the sha256 hash of the swap preimage.
242+
SwapHash lntypes.Hash
243+
244+
// HtlcAddressP2WSH contains the native segwit swap htlc address,
245+
// where the loop-in funds may be paid.
246+
HtlcAddressP2WSH btcutil.Address
247+
248+
// HtlcAddressNP2WSH contains the nested segwit swap htlc address,
249+
// where the loop-in funds may be paid.
250+
HtlcAddressNP2WSH btcutil.Address
251+
}
252+
238253
// SwapInfoKit contains common swap info fields.
239254
type SwapInfoKit struct {
240255
// Hash is the sha256 hash of the preimage that unlocks the htlcs. It
@@ -249,15 +264,27 @@ type SwapInfoKit struct {
249264
type SwapInfo struct {
250265
loopdb.SwapStateData
251266

267+
loopdb.SwapContract
268+
269+
// LastUpdateTime is the time of the last state change.
252270
LastUpdate time.Time
253271

272+
// SwapHash stores the swap preimage hash.
254273
SwapHash lntypes.Hash
255274

275+
// SwapType describes whether this is a loop in or loop out swap.
256276
SwapType swap.Type
257277

258-
loopdb.SwapContract
278+
// HtlcAddressP2WSH stores the address of the P2WSH (native segwit)
279+
// swap htlc. This is used for both loop-in and loop-out.
280+
HtlcAddressP2WSH btcutil.Address
259281

260-
HtlcAddress btcutil.Address
282+
// HtlcAddressNP2WSH stores the address of the NP2WSH (nested segwit)
283+
// swap htlc. This is only used for external loop-in.
284+
HtlcAddressNP2WSH btcutil.Address
285+
286+
// ExternalHtlc is set to true for external loop-in swaps.
287+
ExternalHtlc bool
261288
}
262289

263290
// LastUpdate returns the last update time of the swap

loopd/swapclient_server.go

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -126,27 +126,43 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) (
126126
}
127127

128128
var swapType looprpc.SwapType
129+
var htlcAddress, htlcAddressP2WSH, htlcAddressNP2WSH string
130+
129131
switch loopSwap.SwapType {
130132
case swap.TypeIn:
131133
swapType = looprpc.SwapType_LOOP_IN
134+
htlcAddressP2WSH = loopSwap.HtlcAddressP2WSH.EncodeAddress()
135+
136+
if loopSwap.ExternalHtlc {
137+
htlcAddressNP2WSH = loopSwap.HtlcAddressNP2WSH.EncodeAddress()
138+
htlcAddress = htlcAddressNP2WSH
139+
} else {
140+
htlcAddress = htlcAddressP2WSH
141+
}
142+
132143
case swap.TypeOut:
133144
swapType = looprpc.SwapType_LOOP_OUT
145+
htlcAddressP2WSH = loopSwap.HtlcAddressP2WSH.EncodeAddress()
146+
htlcAddress = htlcAddressP2WSH
147+
134148
default:
135149
return nil, errors.New("unknown swap type")
136150
}
137151

138152
return &looprpc.SwapStatus{
139-
Amt: int64(loopSwap.AmountRequested),
140-
Id: loopSwap.SwapHash.String(),
141-
IdBytes: loopSwap.SwapHash[:],
142-
State: state,
143-
InitiationTime: loopSwap.InitiationTime.UnixNano(),
144-
LastUpdateTime: loopSwap.LastUpdate.UnixNano(),
145-
HtlcAddress: loopSwap.HtlcAddress.EncodeAddress(),
146-
Type: swapType,
147-
CostServer: int64(loopSwap.Cost.Server),
148-
CostOnchain: int64(loopSwap.Cost.Onchain),
149-
CostOffchain: int64(loopSwap.Cost.Offchain),
153+
Amt: int64(loopSwap.AmountRequested),
154+
Id: loopSwap.SwapHash.String(),
155+
IdBytes: loopSwap.SwapHash[:],
156+
State: state,
157+
InitiationTime: loopSwap.InitiationTime.UnixNano(),
158+
LastUpdateTime: loopSwap.LastUpdate.UnixNano(),
159+
HtlcAddress: htlcAddress,
160+
HtlcAddressP2Wsh: htlcAddressP2WSH,
161+
HtlcAddressNp2Wsh: htlcAddressNP2WSH,
162+
Type: swapType,
163+
CostServer: int64(loopSwap.Cost.Server),
164+
CostOnchain: int64(loopSwap.Cost.Onchain),
165+
CostOffchain: int64(loopSwap.Cost.Offchain),
150166
}, nil
151167
}
152168

@@ -255,6 +271,9 @@ func (s *swapClientServer) ListSwaps(_ context.Context,
255271
err error
256272
)
257273

274+
s.swapsLock.Lock()
275+
defer s.swapsLock.Unlock()
276+
258277
// We can just use the server's in-memory cache as that contains the
259278
// most up-to-date state including temporary failures which aren't
260279
// persisted to disk. The swaps field is a map, that's why we need an
@@ -409,17 +428,25 @@ func (s *swapClientServer) LoopIn(ctx context.Context,
409428
}
410429
req.LastHop = &lastHop
411430
}
412-
hash, htlc, err := s.impl.LoopIn(ctx, req)
431+
swapInfo, err := s.impl.LoopIn(ctx, req)
413432
if err != nil {
414433
log.Errorf("Loop in: %v", err)
415434
return nil, err
416435
}
417436

418-
return &looprpc.SwapResponse{
419-
Id: hash.String(),
420-
IdBytes: hash[:],
421-
HtlcAddress: htlc.String(),
422-
}, nil
437+
np2wshAddress := swapInfo.HtlcAddressNP2WSH.String()
438+
response := &looprpc.SwapResponse{
439+
Id: swapInfo.SwapHash.String(),
440+
IdBytes: swapInfo.SwapHash[:],
441+
HtlcAddress: np2wshAddress,
442+
HtlcAddressNp2Wsh: np2wshAddress,
443+
}
444+
445+
if req.ExternalHtlc {
446+
response.HtlcAddressP2Wsh = swapInfo.HtlcAddressP2WSH.String()
447+
}
448+
449+
return response, nil
423450
}
424451

425452
// GetLsatTokens returns all tokens that are contained in the LSAT token store.

0 commit comments

Comments
 (0)