Skip to content

Commit

Permalink
loopd: fractional static address swap amount
Browse files Browse the repository at this point in the history
  • Loading branch information
hieblmi committed Feb 20, 2025
1 parent 76e8edf commit fd6cc75
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 47 deletions.
38 changes: 9 additions & 29 deletions cmd/loop/staticaddr.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,13 @@ var staticAddressLoopInCommand = cli.Command{
"The client can retry the swap with adjusted " +
"parameters after the payment timed out.",
},
cli.IntFlag{
Name: "amount",
Usage: "the number of satoshis that should be " +
"swapped from the selected deposits. If there" +
"is change it is sent back to the static " +
"address.",
},
lastHopFlag,
labelFlag,
routeHintsFlag,
Expand Down Expand Up @@ -552,6 +559,7 @@ func staticAddressLoopIn(ctx *cli.Context) error {
}

quoteReq := &looprpc.QuoteRequest{
Amt: ctx.Int64("amount"),
LoopInRouteHints: hints,
LoopInLastHop: lastHop,
Private: ctx.Bool(privateFlag.Name),
Expand All @@ -564,15 +572,6 @@ func staticAddressLoopIn(ctx *cli.Context) error {

limits := getInLimits(quote)

// populate the quote request with the sum of selected deposits and
// prompt the user for acceptance.
quoteReq.Amt, err = sumDeposits(
depositOutpoints, depositList.FilteredDeposits,
)
if err != nil {
return err
}

if !(ctx.Bool("force") || ctx.Bool("f")) {
err = displayInDetails(quoteReq, quote, ctx.Bool("verbose"))
if err != nil {
Expand All @@ -585,6 +584,7 @@ func staticAddressLoopIn(ctx *cli.Context) error {
}

req := &looprpc.StaticAddressLoopInRequest{
Amount: quoteReq.Amt,
Outpoints: depositOutpoints,
MaxSwapFeeSatoshis: int64(limits.maxSwapFee),
LastHop: lastHop,
Expand Down Expand Up @@ -617,26 +617,6 @@ func containsDuplicates(outpoints []string) bool {
return false
}

func sumDeposits(outpoints []string, deposits []*looprpc.Deposit) (int64,
error) {

var sum int64
depositMap := make(map[string]*looprpc.Deposit)
for _, deposit := range deposits {
depositMap[deposit.Outpoint] = deposit
}

for _, outpoint := range outpoints {
if _, ok := depositMap[outpoint]; !ok {
return 0, fmt.Errorf("deposit %v not found", outpoint)
}

sum += depositMap[outpoint].Value
}

return sum, nil
}

func depositsToOutpoints(deposits []*looprpc.Deposit) []string {
outpoints := make([]string, 0, len(deposits))
for _, deposit := range deposits {
Expand Down
62 changes: 44 additions & 18 deletions loopd/swapclient_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ import (
"github.com/lightninglabs/loop/swap"
"github.com/lightninglabs/loop/swapserverrpc"
"github.com/lightninglabs/taproot-assets/rfqmath"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/queue"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/zpay32"
Expand Down Expand Up @@ -845,21 +847,30 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
log.Infof("Loop in quote request received")

var (
numDeposits = uint32(len(req.DepositOutpoints))
err error
selectedAmount = btcutil.Amount(req.Amt)
selectedDepositAmount btcutil.Amount
numDeposits = len(req.DepositOutpoints)
err error
)

if selectedAmount == 0 && numDeposits == 0 {
return nil, fmt.Errorf("amount and deposit outpoints " +
"cannot both be zero")
}

htlcConfTarget, err := validateLoopInRequest(
req.ConfTarget, req.ExternalHtlc, numDeposits, req.Amt,
req.ConfTarget, req.ExternalHtlc, uint32(numDeposits), req.Amt,
)
if err != nil {
return nil, err
}

// Retrieve deposits to calculate their total value.
var depositList *looprpc.ListStaticAddressDepositsResponse
amount := btcutil.Amount(req.Amt)
if len(req.DepositOutpoints) > 0 {

// If deposits are selected, we need to retrieve them to calculate the
// total value which we request a quote for. If a
if numDeposits > 0 {
depositList, err = s.ListStaticAddressDeposits(
ctx, &looprpc.ListStaticAddressDepositsRequest{
Outpoints: req.DepositOutpoints,
Expand All @@ -874,20 +885,34 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
"deposit outpoints")
}

// The requested amount should be 0 here if the request
// contained deposit outpoints.
if amount != 0 && len(depositList.FilteredDeposits) > 0 {
return nil, fmt.Errorf("amount should be 0 for " +
"deposit quotes")
if numDeposits != len(depositList.FilteredDeposits) {
return nil, fmt.Errorf("expected %d deposits, got %d",
numDeposits, len(depositList.FilteredDeposits))
}

// In case we quote for deposits we send the server both the
// total value and the number of deposits. This is so the server
// can probe the total amount and calculate the per input fee.
if amount == 0 && len(depositList.FilteredDeposits) > 0 {
for _, deposit := range depositList.FilteredDeposits {
amount += btcutil.Amount(deposit.Value)
}
// selected value and the number of deposits. This is so the
// server can probe the selected value and calculate the per
// input fee.
for _, deposit := range depositList.FilteredDeposits {
selectedDepositAmount += btcutil.Amount(
deposit.Value,
)
}

// If the selected amount would leave a dust change output or
// exceeds the total deposits value, we return an error.
dustLimit := lnwallet.DustLimitForSize(input.P2TRSize)
if selectedDepositAmount-selectedAmount < dustLimit {
return nil, fmt.Errorf("selected amount %v leaves "+
"dust or exceeds total deposit value %v",
selectedAmount, selectedDepositAmount)
}

// If the client didn't select an amount we quote for the total
// deposits value.
if selectedAmount == 0 {
selectedAmount = selectedDepositAmount
}
}

Expand All @@ -914,14 +939,14 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
}

quote, err := s.impl.LoopInQuote(ctx, &loop.LoopInQuoteRequest{
Amount: amount,
Amount: selectedAmount,
HtlcConfTarget: htlcConfTarget,
ExternalHtlc: req.ExternalHtlc,
LastHop: lastHop,
RouteHints: routeHints,
Private: req.Private,
Initiator: defaultLoopdInitiator,
NumDeposits: numDeposits,
NumDeposits: uint32(numDeposits),
})
if err != nil {
return nil, err
Expand Down Expand Up @@ -1764,6 +1789,7 @@ func (s *swapClientServer) StaticAddressLoopIn(ctx context.Context,
}

req := &loop.StaticAddressLoopInRequest{
SelectedAmount: btcutil.Amount(in.Amount),
DepositOutpoints: in.Outpoints,
MaxSwapFee: btcutil.Amount(in.MaxSwapFeeSatoshis),
Label: in.Label,
Expand Down

0 comments on commit fd6cc75

Please sign in to comment.