diff --git a/loopd/daemon.go b/loopd/daemon.go index be05421f..786baf4e 100644 --- a/loopd/daemon.go +++ b/loopd/daemon.go @@ -24,6 +24,7 @@ import ( "github.com/lightninglabs/loop/staticaddr/address" "github.com/lightninglabs/loop/staticaddr/deposit" "github.com/lightninglabs/loop/staticaddr/loopin" + "github.com/lightninglabs/loop/staticaddr/openchannel" "github.com/lightninglabs/loop/staticaddr/withdraw" loop_swaprpc "github.com/lightninglabs/loop/swapserverrpc" "github.com/lightninglabs/loop/sweepbatcher" @@ -584,6 +585,7 @@ func (d *Daemon) initialize(withMacaroonService bool) error { staticAddressManager *address.Manager depositManager *deposit.Manager withdrawalManager *withdraw.Manager + openChannelManager *openchannel.Manager staticLoopInManager *loopin.Manager ) @@ -642,6 +644,20 @@ func (d *Daemon) initialize(withMacaroonService bool) error { err) } + // Static address deposit open channel manager setup. + openChannelCfg := &openchannel.Config{ + Server: staticAddressClient, + AddressManager: staticAddressManager, + DepositManager: depositManager, + WithdrawalManager: withdrawalManager, + WalletKit: d.lnd.WalletKit, + ChainParams: d.lnd.ChainParams, + ChainNotifier: d.lnd.ChainNotifier, + Signer: d.lnd.Signer, + LightningClient: d.lnd.Client, + } + openChannelManager = openchannel.NewManager(openChannelCfg) + // Static address loop-in manager setup. staticAddressLoopInStore := loopin.NewSqlStore( loopdb.NewTypedStore[loopin.Querier](baseDb), @@ -752,6 +768,7 @@ func (d *Daemon) initialize(withMacaroonService bool) error { depositManager: depositManager, withdrawalManager: withdrawalManager, staticLoopInManager: staticLoopInManager, + openChannelManager: openChannelManager, assetClient: d.assetClient, stopDaemon: d.Stop, } @@ -988,6 +1005,20 @@ func (d *Daemon) initialize(withMacaroonService bool) error { cancel() } } + // Start the static address open channel manager. + if openChannelManager != nil { + d.wg.Add(1) + go func() { + defer d.wg.Done() + + infof("Starting static address open channel manager") + err := openChannelManager.Run(d.mainCtx) + if err != nil && !errors.Is(context.Canceled, err) { + d.internalErrChan <- err + } + infof("Static address open channel manager stopped") + }() + } // Start the static address loop-in manager. if staticLoopInManager != nil { diff --git a/loopd/swapclient_server.go b/loopd/swapclient_server.go index 3623ac6f..2cc4f5c6 100644 --- a/loopd/swapclient_server.go +++ b/loopd/swapclient_server.go @@ -32,6 +32,7 @@ import ( "github.com/lightninglabs/loop/staticaddr/address" "github.com/lightninglabs/loop/staticaddr/deposit" "github.com/lightninglabs/loop/staticaddr/loopin" + "github.com/lightninglabs/loop/staticaddr/openchannel" "github.com/lightninglabs/loop/staticaddr/staticutil" "github.com/lightninglabs/loop/staticaddr/withdraw" "github.com/lightninglabs/loop/swap" @@ -98,6 +99,7 @@ type swapClientServer struct { depositManager *deposit.Manager withdrawalManager *withdraw.Manager staticLoopInManager *loopin.Manager + openChannelManager *openchannel.Manager assetClient *assets.TapdClient swaps map[lntypes.Hash]loop.SwapInfo subscribers map[int]chan<- interface{} @@ -2009,13 +2011,14 @@ func (s *swapClientServer) GetStaticAddressSummary(ctx context.Context, } var ( - totalNumDeposits = len(allDeposits) - valueUnconfirmed int64 - valueDeposited int64 - valueExpired int64 - valueWithdrawn int64 - valueLoopedIn int64 - htlcTimeoutSwept int64 + totalNumDeposits = len(allDeposits) + valueUnconfirmed int64 + valueDeposited int64 + valueExpired int64 + valueWithdrawn int64 + valueLoopedIn int64 + valueChannelsOpened int64 + htlcTimeoutSwept int64 ) // Value unconfirmed. @@ -2047,6 +2050,9 @@ func (s *swapClientServer) GetStaticAddressSummary(ctx context.Context, case deposit.HtlcTimeoutSwept: htlcTimeoutSwept += value + + case deposit.ChannelPublished: + valueChannelsOpened += value } } @@ -2071,6 +2077,7 @@ func (s *swapClientServer) GetStaticAddressSummary(ctx context.Context, ValueExpiredSatoshis: valueExpired, ValueWithdrawnSatoshis: valueWithdrawn, ValueLoopedInSatoshis: valueLoopedIn, + ValueChannelsOpened: valueChannelsOpened, ValueHtlcTimeoutSweepsSatoshis: htlcTimeoutSwept, }, nil } @@ -2180,6 +2187,33 @@ func (s *swapClientServer) populateBlocksUntilExpiry(ctx context.Context, return nil } +// StaticOpenChannel initiates an open channel request using static address +// deposits. +func (s *swapClientServer) StaticOpenChannel(ctx context.Context, + req *looprpc.StaticOpenChannelRequest) (*looprpc.StaticOpenChannelResponse, + error) { + + infof("Static open channel request received") + + if req == nil || req.OpenChannelRequest == nil { + return &looprpc.StaticOpenChannelResponse{}, + fmt.Errorf("missing open channel request") + } + + chanOutpoint, err := s.openChannelManager.DeliverOpenChannelRequest( + ctx, req.OpenChannelRequest, + ) + + var outpointStr string + if chanOutpoint != nil { + outpointStr = chanOutpoint.String() + } + + return &looprpc.StaticOpenChannelResponse{ + ChannelOpenOutpoint: outpointStr, + }, err +} + type filterFunc func(deposits *deposit.Deposit) bool func filter(deposits []*deposit.Deposit, f filterFunc) []*looprpc.Deposit { @@ -2233,6 +2267,12 @@ func toClientDepositState(state fsm.StateType) looprpc.DepositState { case deposit.LoopedIn: return looprpc.DepositState_LOOPED_IN + case deposit.OpeningChannel: + return looprpc.DepositState_OPENING_CHANNEL + + case deposit.ChannelPublished: + return looprpc.DepositState_CHANNEL_PUBLISHED + case deposit.SweepHtlcTimeout: return looprpc.DepositState_SWEEP_HTLC_TIMEOUT @@ -2312,6 +2352,12 @@ func toServerState(state looprpc.DepositState) fsm.StateType { case looprpc.DepositState_LOOPED_IN: return deposit.LoopedIn + case looprpc.DepositState_OPENING_CHANNEL: + return deposit.OpeningChannel + + case looprpc.DepositState_CHANNEL_PUBLISHED: + return deposit.ChannelPublished + case looprpc.DepositState_SWEEP_HTLC_TIMEOUT: return deposit.SweepHtlcTimeout diff --git a/staticaddr/openchannel/manager.go b/staticaddr/openchannel/manager.go index 8f509d4c..af2f5162 100644 --- a/staticaddr/openchannel/manager.go +++ b/staticaddr/openchannel/manager.go @@ -87,8 +87,8 @@ type newOpenChannelRequest struct { } type newOpenChannelResponse struct { - // ChanTxHash is the transaction hash of the channel open transaction. - ChanTxHash *chainhash.Hash + // ChanOutpoint is the outpoint of the channel open transaction. + ChanOutpoint *wire.OutPoint // Err is the error that occurred during the channel open process. err error @@ -129,10 +129,10 @@ func (m *Manager) Run(ctx context.Context) error { for { select { case req := <-m.newOpenChannelRequestChan: - chanTxHash, err := m.OpenChannel(ctx, req.request) + chanOutpoint, err := m.OpenChannel(ctx, req.request) resp := &newOpenChannelResponse{ - ChanTxHash: chanTxHash, - err: err, + ChanOutpoint: chanOutpoint, + err: err, } select { @@ -236,7 +236,7 @@ func (m *Manager) recoverOpeningChannelDeposits(ctx context.Context) error { // and then starts the open channel psbt flow between the client's lnd instance // and the server. func (m *Manager) OpenChannel(ctx context.Context, - req *lnrpc.OpenChannelRequest) (*chainhash.Hash, error) { + req *lnrpc.OpenChannelRequest) (*wire.OutPoint, error) { var ( outpoints []wire.OutPoint @@ -378,7 +378,7 @@ func (m *Manager) OpenChannel(ctx context.Context, Memo: req.Memo, } - chanTxHash, err := m.openChannelPsbt( + chanOutpoint, err := m.openChannelPsbt( ctx, openChanRequest, deposits, feeRate, ) if err != nil { @@ -403,7 +403,7 @@ func (m *Manager) OpenChannel(ctx context.Context, return nil, err } - return chanTxHash, nil + return chanOutpoint, nil } // openChannelPsbt starts an interactive channel open protocol that uses a @@ -426,7 +426,7 @@ func (m *Manager) OpenChannel(ctx context.Context, // | | func (m *Manager) openChannelPsbt(ctx context.Context, req *lnrpc.OpenChannelRequest, deposits []*deposit.Deposit, - feeRate chainfee.SatPerKWeight) (*chainhash.Hash, error) { + feeRate chainfee.SatPerKWeight) (*wire.OutPoint, error) { var ( pendingChanID [32]byte @@ -689,8 +689,13 @@ func (m *Manager) openChannelPsbt(ctx context.Context, "open tx: %v", err) } + chanOutpoint := &wire.OutPoint{ + Hash: *hash, + Index: update.ChanPending.OutputIndex, + } + log.Infof("Channel transaction pending: %v", - hash.String()) + chanOutpoint) log.Infof("Please monitor the channel from lnd") err = m.cfg.DepositManager.TransitionDeposits( @@ -706,9 +711,7 @@ func (m *Manager) openChannelPsbt(ctx context.Context, // goroutine that reads from the server. closeQuit() - // Nil indicates that the channel was successfully - // published. - return hash, nil + return chanOutpoint, nil } } } @@ -770,7 +773,7 @@ func checkPsbtFlags(req *lnrpc.OpenChannelRequest) error { // DeliverOpenChannelRequest forwards a open channel request to the manager main // loop. func (m *Manager) DeliverOpenChannelRequest(ctx context.Context, - req *lnrpc.OpenChannelRequest) (*chainhash.Hash, error) { + req *lnrpc.OpenChannelRequest) (*wire.OutPoint, error) { request := newOpenChannelRequest{ request: req, @@ -793,7 +796,7 @@ func (m *Manager) DeliverOpenChannelRequest(ctx context.Context, // Wait for the response from the manager run loop. select { case resp := <-request.respChan: - return resp.ChanTxHash, resp.err + return resp.ChanOutpoint, resp.err case <-m.exitChan: return nil, fmt.Errorf("open channel manager has been " +