mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
Update LND, Aperture, and Taproot Assets to revisions using the btcd v2 modules, and update lndclient to v0.21.0-3. Migrate Loop chain, transaction, and address types to their corresponding v2 packages. The lndclient release includes the migration from: https://github.com/lightninglabs/lndclient/pull/280 Taproot Assets is temporarily replaced with its btcd v2 revision because the v0.8 release branch has not adopted the new modules. This raises the minimum Go version to 1.26 and changes exported address types.
278 lines
7.2 KiB
Go
278 lines
7.2 KiB
Go
package loop
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
|
|
btcaddr "github.com/btcsuite/btcd/address/v2"
|
|
"github.com/btcsuite/btcd/btcutil/v2"
|
|
"github.com/btcsuite/btcd/chaincfg/v2"
|
|
"github.com/lightninglabs/loop/loopdb"
|
|
"github.com/lightninglabs/loop/sweep"
|
|
"github.com/lightninglabs/loop/test"
|
|
"github.com/lightningnetwork/lnd/input"
|
|
"github.com/lightningnetwork/lnd/lntypes"
|
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// testSweeper is implementation of sweeper.Sweeper for test.
|
|
type testSweeper struct {
|
|
}
|
|
|
|
// GetSweepFeeDetails calculates the required tx fee to spend to destAddr. It
|
|
// takes a function that is expected to add the weight of the input to the
|
|
// weight estimator. It returns also the fee rate and transaction weight.
|
|
func (s testSweeper) GetSweepFeeDetails(ctx context.Context,
|
|
addInputEstimate func(*input.TxWeightEstimator) error,
|
|
destAddr btcaddr.Address, sweepConfTarget int32,
|
|
label string) (btcutil.Amount, chainfee.SatPerKWeight,
|
|
lntypes.WeightUnit, error) {
|
|
|
|
var feeRate chainfee.SatPerKWeight
|
|
switch {
|
|
case sweepConfTarget == 0:
|
|
return 0, 0, 0, fmt.Errorf("zero sweepConfTarget")
|
|
|
|
case sweepConfTarget == 1:
|
|
return 0, 0, 0, fmt.Errorf("sweepConfTarget is 1")
|
|
|
|
case sweepConfTarget == 2:
|
|
feeRate = 25000
|
|
|
|
case sweepConfTarget == 3:
|
|
feeRate = 20000
|
|
|
|
case sweepConfTarget < 10:
|
|
feeRate = 8000
|
|
|
|
case sweepConfTarget < 100:
|
|
feeRate = 5000
|
|
|
|
case sweepConfTarget < 1000:
|
|
feeRate = 2000
|
|
|
|
default:
|
|
feeRate = 250
|
|
}
|
|
|
|
// Calculate weight for this tx.
|
|
var weightEstimate input.TxWeightEstimator
|
|
|
|
// Add output.
|
|
err := sweep.AddOutputEstimate(&weightEstimate, destAddr)
|
|
if err != nil {
|
|
return 0, 0, 0, fmt.Errorf("failed to add output weight "+
|
|
"estimate: %w", err)
|
|
}
|
|
|
|
// Add input.
|
|
err = addInputEstimate(&weightEstimate)
|
|
if err != nil {
|
|
return 0, 0, 0, fmt.Errorf("failed to add input weight "+
|
|
"estimate: %w", err)
|
|
}
|
|
|
|
// Find weight.
|
|
weight := weightEstimate.Weight()
|
|
|
|
return feeRate.FeeForWeight(weight), feeRate, weight, nil
|
|
}
|
|
|
|
// TestLoopOutSweepFeerateProvider tests that loopOutSweepFeerateProvider
|
|
// provides correct fee rate for loop-out swaps.
|
|
func TestLoopOutSweepFeerateProvider(t *testing.T) {
|
|
htlcKeys := func() loopdb.HtlcKeys {
|
|
var senderKey, receiverKey [33]byte
|
|
|
|
// Generate keys.
|
|
_, senderPubKey := test.CreateKey(1)
|
|
copy(senderKey[:], senderPubKey.SerializeCompressed())
|
|
_, receiverPubKey := test.CreateKey(2)
|
|
copy(receiverKey[:], receiverPubKey.SerializeCompressed())
|
|
|
|
return loopdb.HtlcKeys{
|
|
SenderScriptKey: senderKey,
|
|
ReceiverScriptKey: receiverKey,
|
|
SenderInternalPubKey: senderKey,
|
|
ReceiverInternalPubKey: receiverKey,
|
|
}
|
|
}()
|
|
|
|
var destAddr *btcaddr.AddressTaproot
|
|
|
|
swapInvoice := "lntb1230n1pjjszzgpp5j76f03wrkya4sm4gxv6az5nmz5aqsvmn4" +
|
|
"tpguu2sdvdyygedqjgqdq9xyerxcqzzsxqr23ssp5rwzmwtfjmsgranfk8sr" +
|
|
"4p4gcgmvyd42uug8pxteg2mkk23ndvkqs9qyyssq44ruk3ex59cmv4dm6k4v" +
|
|
"0kc6c0gcqjs0gkljfyd6c6uatqa2f67xlx3pcg5tnvcae5p3jju8ra77e87d" +
|
|
"vhhs0jrx53wnc0fq9rkrhmqqelyx7l"
|
|
|
|
cases := []struct {
|
|
name string
|
|
cltvExpiry int32
|
|
height int32
|
|
amount btcutil.Amount
|
|
protocolVersion loopdb.ProtocolVersion
|
|
wantConfTarget int32
|
|
wantFeeRate chainfee.SatPerKWeight
|
|
wantError string
|
|
}{
|
|
{
|
|
name: "simple case",
|
|
cltvExpiry: 801_000,
|
|
height: 800_900,
|
|
amount: 1_000_000,
|
|
protocolVersion: loopdb.ProtocolVersionMuSig2,
|
|
wantConfTarget: 100,
|
|
wantFeeRate: 2000,
|
|
},
|
|
{
|
|
name: "zero height",
|
|
cltvExpiry: 801_000,
|
|
height: 0,
|
|
amount: 1_000_000,
|
|
protocolVersion: loopdb.ProtocolVersionMuSig2,
|
|
wantError: "got zero best block height",
|
|
},
|
|
{
|
|
name: "huge amount, no proportional fee",
|
|
cltvExpiry: 801_000,
|
|
height: 800_900,
|
|
amount: 100_000_000,
|
|
protocolVersion: loopdb.ProtocolVersionMuSig2,
|
|
wantConfTarget: 100,
|
|
wantFeeRate: 2000,
|
|
},
|
|
{
|
|
name: "huge amount, no proportional fee, v2",
|
|
cltvExpiry: 801_000,
|
|
height: 800_900,
|
|
amount: 100_000_000,
|
|
protocolVersion: loopdb.ProtocolVersionLoopOutCancel,
|
|
wantConfTarget: 100,
|
|
wantFeeRate: 2000,
|
|
},
|
|
{
|
|
name: "huge amount, no proportional fee, " +
|
|
"capped by urgent fee",
|
|
cltvExpiry: 801_000,
|
|
height: 800_900,
|
|
amount: 200_000_000,
|
|
protocolVersion: loopdb.ProtocolVersionMuSig2,
|
|
wantConfTarget: 100,
|
|
wantFeeRate: 2000,
|
|
},
|
|
{
|
|
name: "11 blocks until expiry",
|
|
cltvExpiry: 801_000,
|
|
height: 800_989,
|
|
amount: 1_000_000,
|
|
protocolVersion: loopdb.ProtocolVersionMuSig2,
|
|
wantConfTarget: 11,
|
|
wantFeeRate: 5000,
|
|
},
|
|
{
|
|
name: "10 blocks until expiry",
|
|
cltvExpiry: 801_000,
|
|
height: 800_990,
|
|
amount: 1_000_000,
|
|
protocolVersion: loopdb.ProtocolVersionMuSig2,
|
|
wantConfTarget: 3,
|
|
wantFeeRate: 22000,
|
|
},
|
|
{
|
|
name: "9 blocks until expiry",
|
|
cltvExpiry: 801_000,
|
|
height: 800_991,
|
|
amount: 1_000_000,
|
|
protocolVersion: loopdb.ProtocolVersionMuSig2,
|
|
wantConfTarget: 3,
|
|
wantFeeRate: 22000,
|
|
},
|
|
{
|
|
name: "3 blocks until expiry",
|
|
cltvExpiry: 801_000,
|
|
height: 800_997,
|
|
amount: 1_000_000,
|
|
protocolVersion: loopdb.ProtocolVersionMuSig2,
|
|
wantConfTarget: 3,
|
|
wantFeeRate: 22000,
|
|
},
|
|
{
|
|
name: "2 blocks until expiry",
|
|
cltvExpiry: 801_000,
|
|
height: 800_998,
|
|
amount: 1_000_000,
|
|
protocolVersion: loopdb.ProtocolVersionMuSig2,
|
|
wantConfTarget: 2,
|
|
wantFeeRate: 27500,
|
|
},
|
|
{
|
|
name: "1 blocks until expiry",
|
|
cltvExpiry: 801_000,
|
|
height: 800_999,
|
|
amount: 1_000_000,
|
|
protocolVersion: loopdb.ProtocolVersionMuSig2,
|
|
wantConfTarget: 2,
|
|
wantFeeRate: 27500,
|
|
},
|
|
{
|
|
name: "expired",
|
|
cltvExpiry: 801_000,
|
|
height: 801_000,
|
|
amount: 1_000_000,
|
|
protocolVersion: loopdb.ProtocolVersionMuSig2,
|
|
wantConfTarget: 2,
|
|
wantFeeRate: 27500,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
store := loopdb.NewStoreMock(t)
|
|
|
|
ctx := context.Background()
|
|
|
|
swapHash := lntypes.Hash{1, 1, 1}
|
|
swap := &loopdb.LoopOutContract{
|
|
SwapContract: loopdb.SwapContract{
|
|
CltvExpiry: tc.cltvExpiry,
|
|
AmountRequested: tc.amount,
|
|
ProtocolVersion: tc.protocolVersion,
|
|
HtlcKeys: htlcKeys,
|
|
},
|
|
|
|
DestAddr: destAddr,
|
|
SwapInvoice: swapInvoice,
|
|
SweepConfTarget: 100,
|
|
}
|
|
|
|
err := store.CreateLoopOut(ctx, swapHash, swap)
|
|
require.NoError(t, err)
|
|
store.AssertLoopOutStored()
|
|
|
|
getHeight := func() int32 {
|
|
return tc.height
|
|
}
|
|
|
|
p := newLoopOutSweepFeerateProvider(
|
|
testSweeper{}, store,
|
|
&chaincfg.RegressionNetParams, getHeight,
|
|
)
|
|
|
|
confTarget, feeRate, err := p.GetConfTargetAndFeeRate(
|
|
ctx, swapHash,
|
|
)
|
|
if tc.wantError != "" {
|
|
require.ErrorContains(t, err, tc.wantError)
|
|
|
|
return
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, tc.wantConfTarget, confTarget)
|
|
require.Equal(t, tc.wantFeeRate, feeRate)
|
|
})
|
|
}
|
|
}
|