mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
staticaddr: sign with per-deposit address keys
Construct cooperative MuSig2 sessions from the address parameters stored on each deposit. Loop-ins and withdrawals can therefore combine inputs owned by different derived static addresses.
This commit is contained in:
parent
fd1c651a47
commit
689e1b119f
6 changed files with 216 additions and 79 deletions
|
|
@ -601,8 +601,7 @@ func (f *FSM) SignHtlcTxAction(ctx context.Context,
|
|||
// rates.
|
||||
createSession := staticutil.CreateMusig2Sessions
|
||||
htlcSessions, clientHtlcNonces, err := createSession(
|
||||
ctx, f.cfg.Signer, f.loopIn.Deposits, f.loopIn.AddressParams,
|
||||
f.loopIn.Address,
|
||||
ctx, f.cfg.Signer, f.loopIn.Deposits,
|
||||
)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to create musig2 sessions: %w", err)
|
||||
|
|
@ -612,8 +611,7 @@ func (f *FSM) SignHtlcTxAction(ctx context.Context,
|
|||
defer f.cleanUpSessions(ctx, htlcSessions)
|
||||
|
||||
htlcSessionsHighFee, highFeeNonces, err := createSession(
|
||||
ctx, f.cfg.Signer, f.loopIn.Deposits, f.loopIn.AddressParams,
|
||||
f.loopIn.Address,
|
||||
ctx, f.cfg.Signer, f.loopIn.Deposits,
|
||||
)
|
||||
if err != nil {
|
||||
return f.HandleError(err)
|
||||
|
|
@ -621,8 +619,7 @@ func (f *FSM) SignHtlcTxAction(ctx context.Context,
|
|||
defer f.cleanUpSessions(ctx, htlcSessionsHighFee)
|
||||
|
||||
htlcSessionsExtremelyHighFee, extremelyHighNonces, err := createSession(
|
||||
ctx, f.cfg.Signer, f.loopIn.Deposits, f.loopIn.AddressParams,
|
||||
f.loopIn.Address,
|
||||
ctx, f.cfg.Signer, f.loopIn.Deposits,
|
||||
)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to convert nonces: %w", err)
|
||||
|
|
|
|||
|
|
@ -204,9 +204,7 @@ func (l *StaticAddressLoopIn) signMusig2Tx(ctx context.Context,
|
|||
musig2sessions []*input.MuSig2SessionInfo,
|
||||
counterPartyNonces [][musig2.PubNonceSize]byte) ([][]byte, error) {
|
||||
|
||||
prevOuts, err := staticutil.ToPrevOuts(
|
||||
l.Deposits, l.AddressParams.PkScript,
|
||||
)
|
||||
prevOuts, err := staticutil.ToPrevOuts(l.Deposits)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -376,8 +376,18 @@ func (m *Manager) handleLoopInSweepReq(ctx context.Context,
|
|||
map[string]*swapserverrpc.ClientSweeplessSigningInfo,
|
||||
len(req.DepositToNonces),
|
||||
)
|
||||
depositMap := make(map[string]*deposit.Deposit, len(loopIn.Deposits))
|
||||
for _, d := range loopIn.Deposits {
|
||||
depositMap[d.String()] = d
|
||||
}
|
||||
|
||||
for depositOutpoint, nonce := range req.DepositToNonces {
|
||||
d, ok := depositMap[depositOutpoint]
|
||||
if !ok {
|
||||
return fmt.Errorf("deposit %v not found in loop-in",
|
||||
depositOutpoint)
|
||||
}
|
||||
|
||||
taprootSigHash, err := txscript.CalcTaprootSignatureHash(
|
||||
sigHashes, txscript.SigHashDefault,
|
||||
sweepPacket.UnsignedTx,
|
||||
|
|
@ -396,7 +406,7 @@ func (m *Manager) handleLoopInSweepReq(ctx context.Context,
|
|||
}
|
||||
|
||||
musig2Session, err := staticutil.CreateMusig2Session(
|
||||
ctx, m.cfg.Signer, loopIn.AddressParams, loopIn.Address,
|
||||
ctx, m.cfg.Signer, d,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package staticutil
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
|
|
@ -12,7 +13,6 @@ import (
|
|||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightninglabs/lndclient"
|
||||
"github.com/lightninglabs/loop/staticaddr/deposit"
|
||||
"github.com/lightninglabs/loop/staticaddr/script"
|
||||
"github.com/lightninglabs/loop/swapserverrpc"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
|
|
@ -21,8 +21,12 @@ import (
|
|||
)
|
||||
|
||||
// ToPrevOuts converts a slice of deposits to a map of outpoints to TxOuts.
|
||||
func ToPrevOuts(deposits []*deposit.Deposit,
|
||||
pkScript []byte) (map[wire.OutPoint]*wire.TxOut, error) {
|
||||
//
|
||||
// Each deposit carries the static address parameters that produced its output.
|
||||
// Using the per-deposit script here keeps signing correct when one transaction
|
||||
// spends deposits from multiple static addresses.
|
||||
func ToPrevOuts(deposits []*deposit.Deposit) (
|
||||
map[wire.OutPoint]*wire.TxOut, error) {
|
||||
|
||||
outpoints := make([]wire.OutPoint, len(deposits))
|
||||
for i, d := range deposits {
|
||||
|
|
@ -35,9 +39,13 @@ func ToPrevOuts(deposits []*deposit.Deposit,
|
|||
prevOuts := make(map[wire.OutPoint]*wire.TxOut, len(deposits))
|
||||
for i, d := range deposits {
|
||||
outpoint := outpoints[i]
|
||||
if d.AddressParams == nil {
|
||||
return nil, fmt.Errorf("missing static address "+
|
||||
"parameters for deposit %v", d.OutPoint)
|
||||
}
|
||||
txOut := &wire.TxOut{
|
||||
Value: int64(d.Value),
|
||||
PkScript: pkScript,
|
||||
PkScript: d.AddressParams.PkScript,
|
||||
}
|
||||
prevOuts[outpoint] = txOut
|
||||
}
|
||||
|
|
@ -47,9 +55,8 @@ func ToPrevOuts(deposits []*deposit.Deposit,
|
|||
|
||||
// CreateMusig2Sessions creates a musig2 session for a number of deposits.
|
||||
func CreateMusig2Sessions(ctx context.Context,
|
||||
signer lndclient.SignerClient, deposits []*deposit.Deposit,
|
||||
addrParams *script.Parameters,
|
||||
staticAddress *script.StaticAddress) ([]*input.MuSig2SessionInfo,
|
||||
signer lndclient.SignerClient, deposits []*deposit.Deposit) (
|
||||
[]*input.MuSig2SessionInfo,
|
||||
[][]byte, error) {
|
||||
|
||||
musig2Sessions := make([]*input.MuSig2SessionInfo, len(deposits))
|
||||
|
|
@ -58,7 +65,7 @@ func CreateMusig2Sessions(ctx context.Context,
|
|||
// Create the sessions and nonces from the deposits.
|
||||
for i := range len(deposits) {
|
||||
session, err := CreateMusig2Session(
|
||||
ctx, signer, addrParams, staticAddress,
|
||||
ctx, signer, deposits[i],
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
|
@ -72,11 +79,12 @@ func CreateMusig2Sessions(ctx context.Context,
|
|||
}
|
||||
|
||||
// CreateMusig2SessionsPerDeposit creates a musig2 session for a number of
|
||||
// deposits.
|
||||
// deposits and returns the sessions keyed by outpoint string.
|
||||
//
|
||||
// The per-deposit keying mirrors the server response format and avoids relying
|
||||
// on positional ordering after the request crosses the wire.
|
||||
func CreateMusig2SessionsPerDeposit(ctx context.Context,
|
||||
signer lndclient.SignerClient, deposits []*deposit.Deposit,
|
||||
addrParams *script.Parameters,
|
||||
staticAddress *script.StaticAddress) (
|
||||
signer lndclient.SignerClient, deposits []*deposit.Deposit) (
|
||||
map[string]*input.MuSig2SessionInfo, map[string][]byte, map[string]int,
|
||||
error) {
|
||||
|
||||
|
|
@ -86,25 +94,73 @@ func CreateMusig2SessionsPerDeposit(ctx context.Context,
|
|||
|
||||
// Create the musig2 sessions for the sweepless sweep tx.
|
||||
for i, deposit := range deposits {
|
||||
session, err := CreateMusig2Session(
|
||||
ctx, signer, addrParams, staticAddress,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
depositKey := deposit.String()
|
||||
if _, ok := sessions[depositKey]; ok {
|
||||
err := fmt.Errorf("duplicate outpoint %v", depositKey)
|
||||
return nil, nil, nil, errors.Join(
|
||||
err, CleanupMusig2Sessions(ctx, signer, sessions),
|
||||
)
|
||||
}
|
||||
|
||||
sessions[deposit.String()] = session
|
||||
nonces[deposit.String()] = session.PublicNonce[:]
|
||||
depositToIdx[deposit.String()] = i
|
||||
session, err := CreateMusig2Session(
|
||||
ctx, signer, deposit,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Join(
|
||||
err, CleanupMusig2Sessions(ctx, signer, sessions),
|
||||
)
|
||||
}
|
||||
|
||||
sessions[depositKey] = session
|
||||
nonces[depositKey] = session.PublicNonce[:]
|
||||
depositToIdx[depositKey] = i
|
||||
}
|
||||
|
||||
return sessions, nonces, depositToIdx, nil
|
||||
}
|
||||
|
||||
// CreateMusig2Session creates a musig2 session for the deposit.
|
||||
// CleanupMusig2Sessions releases all supplied MuSig2 sessions.
|
||||
func CleanupMusig2Sessions(ctx context.Context,
|
||||
signer lndclient.SignerClient,
|
||||
sessions map[string]*input.MuSig2SessionInfo) error {
|
||||
|
||||
var cleanupErr error
|
||||
for depositKey, session := range sessions {
|
||||
if session == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
err := signer.MuSig2Cleanup(
|
||||
context.WithoutCancel(ctx), session.SessionID,
|
||||
)
|
||||
if err != nil {
|
||||
cleanupErr = errors.Join(
|
||||
cleanupErr, fmt.Errorf("unable to clean up MuSig2 "+
|
||||
"session for deposit %v: %w", depositKey, err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return cleanupErr
|
||||
}
|
||||
|
||||
// CreateMusig2Session creates a musig2 session for the deposit's static
|
||||
// address.
|
||||
func CreateMusig2Session(ctx context.Context,
|
||||
signer lndclient.SignerClient, addrParams *script.Parameters,
|
||||
staticAddress *script.StaticAddress) (*input.MuSig2SessionInfo, error) {
|
||||
signer lndclient.SignerClient, d *deposit.Deposit) (
|
||||
*input.MuSig2SessionInfo, error) {
|
||||
|
||||
if d.AddressParams == nil {
|
||||
return nil, fmt.Errorf("missing static address parameters "+
|
||||
"for deposit %v", d.OutPoint)
|
||||
}
|
||||
|
||||
staticAddress, err := d.GetStaticAddressScript()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
addrParams := d.AddressParams
|
||||
|
||||
signers := [][]byte{
|
||||
addrParams.ClientPubkey.SerializeCompressed(),
|
||||
|
|
|
|||
|
|
@ -3,14 +3,16 @@ package staticutil
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightninglabs/lndclient"
|
||||
"github.com/lightninglabs/loop/staticaddr/address"
|
||||
"github.com/lightninglabs/loop/staticaddr/deposit"
|
||||
"github.com/lightninglabs/loop/staticaddr/script"
|
||||
"github.com/lightninglabs/loop/swapserverrpc"
|
||||
looptest "github.com/lightninglabs/loop/test"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
|
|
@ -21,6 +23,37 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type sessionCleanupSigner struct {
|
||||
lndclient.SignerClient
|
||||
|
||||
createCalls int
|
||||
failCreateAt int
|
||||
cleaned [][32]byte
|
||||
cleanupCtxErr []error
|
||||
}
|
||||
|
||||
func (s *sessionCleanupSigner) MuSig2CreateSession(context.Context,
|
||||
input.MuSig2Version, *keychain.KeyLocator, [][]byte,
|
||||
...lndclient.MuSig2SessionOpts) (*input.MuSig2SessionInfo, error) {
|
||||
|
||||
s.createCalls++
|
||||
if s.createCalls == s.failCreateAt {
|
||||
return nil, errors.New("session creation failed")
|
||||
}
|
||||
|
||||
sessionID := [32]byte{byte(s.createCalls)}
|
||||
return &input.MuSig2SessionInfo{SessionID: sessionID}, nil
|
||||
}
|
||||
|
||||
func (s *sessionCleanupSigner) MuSig2Cleanup(ctx context.Context,
|
||||
sessionID [32]byte) error {
|
||||
|
||||
s.cleaned = append(s.cleaned, sessionID)
|
||||
s.cleanupCtxErr = append(s.cleanupCtxErr, ctx.Err())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// mustHash converts a hex string to a chainhash.Hash and panics on error.
|
||||
func mustHash(t *testing.T, s string) chainhash.Hash {
|
||||
t.Helper()
|
||||
|
|
@ -36,7 +69,8 @@ func TestToPrevOuts_Success(t *testing.T) {
|
|||
Hash: mustHash(t, "0000000000000000000000000000000000000000000000000000000000000001"),
|
||||
Index: 0,
|
||||
},
|
||||
Value: btcutil.Amount(12345),
|
||||
Value: btcutil.Amount(12345),
|
||||
AddressParams: &address.Parameters{PkScript: []byte{0x51}},
|
||||
}
|
||||
|
||||
d2 := &deposit.Deposit{
|
||||
|
|
@ -44,12 +78,11 @@ func TestToPrevOuts_Success(t *testing.T) {
|
|||
Hash: mustHash(t, "1111111111111111111111111111111111111111111111111111111111111111"),
|
||||
Index: 7,
|
||||
},
|
||||
Value: btcutil.Amount(987654321),
|
||||
Value: btcutil.Amount(987654321),
|
||||
AddressParams: &address.Parameters{PkScript: []byte{0x52}},
|
||||
}
|
||||
|
||||
pkScript := []byte{0x51, 0x21, 0x02, 0x52} // arbitrary bytes
|
||||
|
||||
prevOuts, err := ToPrevOuts([]*deposit.Deposit{d1, d2}, pkScript)
|
||||
prevOuts, err := ToPrevOuts([]*deposit.Deposit{d1, d2})
|
||||
require.NoError(t, err)
|
||||
|
||||
// We expect two entries.
|
||||
|
|
@ -59,13 +92,13 @@ func TestToPrevOuts_Success(t *testing.T) {
|
|||
txOut1, ok := prevOuts[d1.OutPoint]
|
||||
require.True(t, ok, "expected outpoint d1 to be present")
|
||||
require.EqualValues(t, int64(d1.Value), txOut1.Value)
|
||||
require.Equal(t, pkScript, txOut1.PkScript)
|
||||
require.Equal(t, d1.AddressParams.PkScript, txOut1.PkScript)
|
||||
|
||||
// Check the second outpoint mapping.
|
||||
txOut2, ok := prevOuts[d2.OutPoint]
|
||||
require.True(t, ok, "expected outpoint d2 to be present")
|
||||
require.EqualValues(t, int64(d2.Value), txOut2.Value)
|
||||
require.Equal(t, pkScript, txOut2.PkScript)
|
||||
require.Equal(t, d2.AddressParams.PkScript, txOut2.PkScript)
|
||||
|
||||
// Ensure the keys in the map are exactly the outpoints we provided.
|
||||
for op := range prevOuts {
|
||||
|
|
@ -80,13 +113,34 @@ func TestToPrevOuts_DuplicateOutpoint(t *testing.T) {
|
|||
Index: 2,
|
||||
}
|
||||
|
||||
d1 := &deposit.Deposit{OutPoint: shared, Value: btcutil.Amount(100)}
|
||||
d2 := &deposit.Deposit{OutPoint: shared, Value: btcutil.Amount(200)}
|
||||
d1 := &deposit.Deposit{
|
||||
OutPoint: shared,
|
||||
Value: btcutil.Amount(100),
|
||||
AddressParams: &address.Parameters{PkScript: []byte{0x00}},
|
||||
}
|
||||
d2 := &deposit.Deposit{
|
||||
OutPoint: shared,
|
||||
Value: btcutil.Amount(200),
|
||||
AddressParams: &address.Parameters{PkScript: []byte{0x01}},
|
||||
}
|
||||
|
||||
_, err := ToPrevOuts([]*deposit.Deposit{d1, d2}, []byte{0x00})
|
||||
_, err := ToPrevOuts([]*deposit.Deposit{d1, d2})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestToPrevOutsMissingAddressParams(t *testing.T) {
|
||||
d := &deposit.Deposit{
|
||||
OutPoint: wire.OutPoint{
|
||||
Hash: mustHash(t, "3333333333333333333333333333333333333333333333333333333333333333"),
|
||||
Index: 3,
|
||||
},
|
||||
Value: btcutil.Amount(100),
|
||||
}
|
||||
|
||||
_, err := ToPrevOuts([]*deposit.Deposit{d})
|
||||
require.ErrorContains(t, err, "missing static address parameters")
|
||||
}
|
||||
|
||||
func TestGetPrevoutInfo_ConversionAndSorting(t *testing.T) {
|
||||
// Helper to create a hash from string.
|
||||
must := func(s string) chainhash.Hash {
|
||||
|
|
@ -182,13 +236,8 @@ func TestCreateMusig2Session_Success(t *testing.T) {
|
|||
KeyLocator: keychain.KeyLocator{Family: 1, Index: 2},
|
||||
}
|
||||
|
||||
// Build a static address for tweak options.
|
||||
staticAddr, err := script.NewStaticAddress(
|
||||
input.MuSig2Version100RC2, int64(params.Expiry), params.ClientPubkey, params.ServerPubkey,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
sess, err := CreateMusig2Session(context.Background(), signer, params, staticAddr)
|
||||
d := &deposit.Deposit{AddressParams: params}
|
||||
sess, err := CreateMusig2Session(context.Background(), signer, d)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, sess)
|
||||
}
|
||||
|
|
@ -211,20 +260,15 @@ func TestCreateMusig2Sessions_Multiple(t *testing.T) {
|
|||
KeyLocator: keychain.KeyLocator{Family: 9, Index: 8},
|
||||
}
|
||||
|
||||
staticAddr, err := script.NewStaticAddress(
|
||||
input.MuSig2Version100RC2, int64(params.Expiry), params.ClientPubkey, params.ServerPubkey,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Prepare N deposits; only the length matters for session count.
|
||||
deposits := []*deposit.Deposit{
|
||||
{OutPoint: wire.OutPoint{Index: 0}},
|
||||
{OutPoint: wire.OutPoint{Index: 1}},
|
||||
{OutPoint: wire.OutPoint{Index: 2}},
|
||||
{OutPoint: wire.OutPoint{Index: 0}, AddressParams: params},
|
||||
{OutPoint: wire.OutPoint{Index: 1}, AddressParams: params},
|
||||
{OutPoint: wire.OutPoint{Index: 2}, AddressParams: params},
|
||||
}
|
||||
|
||||
sessions, nonces, err := CreateMusig2Sessions(
|
||||
context.Background(), signer, deposits, params, staticAddr,
|
||||
context.Background(), signer, deposits,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, sessions, len(deposits))
|
||||
|
|
@ -237,6 +281,43 @@ func TestCreateMusig2Sessions_Multiple(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCreateMusig2SessionsPerDepositCleansUpPartialFailure(
|
||||
t *testing.T) {
|
||||
|
||||
clientKey, err := btcec.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
serverKey, err := btcec.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
params := &address.Parameters{
|
||||
ClientPubkey: clientKey.PubKey(),
|
||||
ServerPubkey: serverKey.PubKey(),
|
||||
Expiry: 12,
|
||||
KeyLocator: keychain.KeyLocator{Family: 9, Index: 8},
|
||||
}
|
||||
deposits := []*deposit.Deposit{
|
||||
{
|
||||
OutPoint: wire.OutPoint{Index: 1},
|
||||
AddressParams: params,
|
||||
},
|
||||
{
|
||||
OutPoint: wire.OutPoint{Index: 2},
|
||||
AddressParams: params,
|
||||
},
|
||||
}
|
||||
|
||||
signer := &sessionCleanupSigner{failCreateAt: 2}
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
cancel()
|
||||
|
||||
_, _, _, err = CreateMusig2SessionsPerDeposit(
|
||||
ctx, signer, deposits,
|
||||
)
|
||||
require.ErrorContains(t, err, "session creation failed")
|
||||
require.Equal(t, [][32]byte{{1}}, signer.cleaned)
|
||||
require.Equal(t, []error{nil}, signer.cleanupCtxErr)
|
||||
}
|
||||
|
||||
// makeDeposit creates a deposit with the given value for testing.
|
||||
func makeDeposit(value btcutil.Amount) *deposit.Deposit {
|
||||
return &deposit.Deposit{Value: value}
|
||||
|
|
|
|||
|
|
@ -536,32 +536,27 @@ func (m *Manager) CreateFinalizedWithdrawalTx(ctx context.Context,
|
|||
selectedWithdrawalAmount int64,
|
||||
commitmentType lnrpc.CommitmentType) (*wire.MsgTx, []byte, error) {
|
||||
|
||||
// Create a musig2 session for each deposit.
|
||||
addrParams, err := m.cfg.AddressManager.GetStaticAddressParameters(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
staticAddress, err := m.cfg.AddressManager.GetStaticAddress(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Create a musig2 session for each deposit. Each selected deposit carries
|
||||
// the address parameters that produced the output, so withdrawals can
|
||||
// spend inputs from multiple static addresses in one transaction.
|
||||
sessions, clientNonces, idx, err := staticutil.CreateMusig2SessionsPerDeposit(
|
||||
ctx, m.cfg.Signer, deposits, addrParams, staticAddress,
|
||||
ctx, m.cfg.Signer, deposits,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
params, err := m.cfg.AddressManager.GetStaticAddressParameters(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("couldn't get confirmation "+
|
||||
"height for deposit, %w", err)
|
||||
}
|
||||
defer func() {
|
||||
err := staticutil.CleanupMusig2Sessions(
|
||||
ctx, m.cfg.Signer, sessions,
|
||||
)
|
||||
if err != nil {
|
||||
log.Warnf("Unable to clean up withdrawal MuSig2 "+
|
||||
"sessions: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
outpoints := toOutpoints(deposits)
|
||||
prevOuts, err := staticutil.ToPrevOuts(deposits, params.PkScript)
|
||||
prevOuts, err := staticutil.ToPrevOuts(deposits)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue