@@ -893,22 +893,62 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
893893 infof ("Loop in quote request received" )
894894
895895 var (
896- numDeposits = uint32 (len (req .DepositOutpoints ))
897- err error
896+ selectedAmount = btcutil .Amount (req .Amt )
897+ totalDepositAmount btcutil.Amount
898+ autoSelectDeposits = req .AutoSelectDeposits
899+ err error
898900 )
899901
900902 htlcConfTarget , err := validateLoopInRequest (
901- req .ConfTarget , req .ExternalHtlc , numDeposits , req .Amt ,
903+ req .ConfTarget , req .ExternalHtlc ,
904+ uint32 (len (req .DepositOutpoints )), selectedAmount ,
905+ autoSelectDeposits ,
902906 )
903907 if err != nil {
904908 return nil , err
905909 }
906910
907- // Retrieve deposits to calculate their total value.
908- var depositList * looprpc.ListStaticAddressDepositsResponse
909- amount := btcutil .Amount (req .Amt )
910- if len (req .DepositOutpoints ) > 0 {
911- depositList , err = s .ListStaticAddressDeposits (
911+ // If deposits should be automatically selected, we do so and count the
912+ // number of deposits to quote for.
913+ numDeposits := 0
914+ if autoSelectDeposits {
915+ deposits , err := s .depositManager .GetActiveDepositsInState (
916+ deposit .Deposited ,
917+ )
918+ if err != nil {
919+ return nil , fmt .Errorf ("unable to retrieve all " +
920+ "deposits: %w" , err )
921+ }
922+
923+ // TODO(hieblmi): add params to deposit for multi-address
924+ // support.
925+ params , err := s .staticAddressManager .GetStaticAddressParameters (
926+ ctx ,
927+ )
928+ if err != nil {
929+ return nil , fmt .Errorf ("unable to retrieve static " +
930+ "address parameters: %w" , err )
931+ }
932+
933+ info , err := s .lnd .Client .GetInfo (ctx )
934+ if err != nil {
935+ return nil , fmt .Errorf ("unable to get lnd info: %w" ,
936+ err )
937+ }
938+ selectedDeposits , err := loopin .SelectDeposits (
939+ selectedAmount , deposits , params .Expiry ,
940+ info .BlockHeight ,
941+ )
942+ if err != nil {
943+ return nil , fmt .Errorf ("unable to select deposits: %w" ,
944+ err )
945+ }
946+
947+ numDeposits = len (selectedDeposits )
948+ } else if len (req .DepositOutpoints ) > 0 {
949+ // If deposits are selected, we need to retrieve them to
950+ // calculate the total value which we request a quote for.
951+ depositList , err := s .ListStaticAddressDeposits (
912952 ctx , & looprpc.ListStaticAddressDepositsRequest {
913953 Outpoints : req .DepositOutpoints ,
914954 },
@@ -922,20 +962,35 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
922962 "deposit outpoints" )
923963 }
924964
925- // The requested amount should be 0 here if the request
926- // contained deposit outpoints.
927- if amount != 0 && len (depositList .FilteredDeposits ) > 0 {
928- return nil , fmt .Errorf ("amount should be 0 for " +
929- "deposit quotes" )
965+ if len (req .DepositOutpoints ) !=
966+ len (depositList .FilteredDeposits ) {
967+
968+ return nil , fmt .Errorf ("expected %d deposits, got %d" ,
969+ len (req .DepositOutpoints ),
970+ len (depositList .FilteredDeposits ))
971+ } else {
972+ numDeposits = len (depositList .FilteredDeposits )
930973 }
931974
932- // In case we quote for deposits we send the server both the
933- // total value and the number of deposits. This is so the server
934- // can probe the total amount and calculate the per input fee.
935- if amount == 0 && len (depositList .FilteredDeposits ) > 0 {
936- for _ , deposit := range depositList .FilteredDeposits {
937- amount += btcutil .Amount (deposit .Value )
938- }
975+ // In case we quote for deposits, we send the server both the
976+ // selected value and the number of deposits. This is so the
977+ // server can probe the selected value and calculate the per
978+ // input fee.
979+ for _ , deposit := range depositList .FilteredDeposits {
980+ totalDepositAmount += btcutil .Amount (
981+ deposit .Value ,
982+ )
983+ }
984+
985+ // If a fractional amount is also selected, we check if it
986+ // leads to a dust change output.
987+ selectedAmount , err = loopin .DeduceSwapAmount (
988+ totalDepositAmount , selectedAmount ,
989+ )
990+ if err != nil {
991+ return nil , fmt .Errorf ("error calculating " +
992+ "swap amount from selected amount: %v" ,
993+ err )
939994 }
940995 }
941996
@@ -962,14 +1017,14 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
9621017 }
9631018
9641019 quote , err := s .impl .LoopInQuote (ctx , & loop.LoopInQuoteRequest {
965- Amount : amount ,
1020+ Amount : selectedAmount ,
9661021 HtlcConfTarget : htlcConfTarget ,
9671022 ExternalHtlc : req .ExternalHtlc ,
9681023 LastHop : lastHop ,
9691024 RouteHints : routeHints ,
9701025 Private : req .Private ,
9711026 Initiator : defaultLoopdInitiator ,
972- NumDeposits : numDeposits ,
1027+ NumDeposits : uint32 ( numDeposits ) ,
9731028 })
9741029 if err != nil {
9751030 return nil , err
@@ -1065,8 +1120,11 @@ func (s *swapClientServer) LoopIn(ctx context.Context,
10651120
10661121 infof ("Loop in request received" )
10671122
1123+ selectDeposits := false
1124+ numDeposits := uint32 (0 )
10681125 htlcConfTarget , err := validateLoopInRequest (
1069- in .HtlcConfTarget , in .ExternalHtlc , 0 , in .Amt ,
1126+ in .HtlcConfTarget , in .ExternalHtlc , numDeposits ,
1127+ btcutil .Amount (in .Amt ), selectDeposits ,
10701128 )
10711129 if err != nil {
10721130 return nil , err
@@ -1980,6 +2038,7 @@ func (s *swapClientServer) StaticAddressLoopIn(ctx context.Context,
19802038 }
19812039
19822040 req := & loop.StaticAddressLoopInRequest {
2041+ SelectedAmount : btcutil .Amount (in .Amount ),
19832042 DepositOutpoints : in .Outpoints ,
19842043 MaxSwapFee : btcutil .Amount (in .MaxSwapFeeSatoshis ),
19852044 Label : in .Label ,
@@ -2282,12 +2341,24 @@ func validateConfTarget(target, defaultTarget int32) (int32, error) {
22822341}
22832342
22842343// validateLoopInRequest fails if the mutually exclusive conf target and
2285- // external parameters are both set.
2344+ // external parameters are both set. It returns the confirmation target of the
2345+ // legacy loop-in.
22862346func validateLoopInRequest (htlcConfTarget int32 , external bool ,
2287- numDeposits uint32 , amount int64 ) (int32 , error ) {
2347+ numDeposits uint32 , amount btcutil.Amount ,
2348+ autoSelectDeposits bool ) (int32 , error ) {
2349+
2350+ if amount < 0 {
2351+ return 0 , errors .New ("amount cannot be negative" )
2352+ }
22882353
22892354 if amount == 0 && numDeposits == 0 {
2290- return 0 , errors .New ("either amount or deposits must be set" )
2355+ return 0 , errors .New ("either amount, or deposits or both " +
2356+ "must be set" )
2357+ }
2358+
2359+ if autoSelectDeposits && numDeposits > 0 {
2360+ return 0 , errors .New ("cannot auto-select deposits while " +
2361+ "providing deposits at the same time" )
22912362 }
22922363
22932364 // If the htlc is going to be externally set, the htlcConfTarget should
@@ -2305,7 +2376,7 @@ func validateLoopInRequest(htlcConfTarget int32, external bool,
23052376
23062377 // If the loop in uses static address deposits, we do not need to set a
23072378 // confirmation target since the HTLC won't be published by the client.
2308- if numDeposits > 0 {
2379+ if numDeposits > 0 || autoSelectDeposits {
23092380 return 0 , nil
23102381 }
23112382
0 commit comments