@@ -893,22 +893,62 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
893
893
infof ("Loop in quote request received" )
894
894
895
895
var (
896
- numDeposits = uint32 (len (req .DepositOutpoints ))
897
- err error
896
+ selectedAmount = btcutil .Amount (req .Amt )
897
+ totalDepositAmount btcutil.Amount
898
+ autoSelectDeposits = req .SelectDeposits
899
+ err error
898
900
)
899
901
900
902
htlcConfTarget , err := validateLoopInRequest (
901
- req .ConfTarget , req .ExternalHtlc , numDeposits , req .Amt ,
903
+ req .ConfTarget , req .ExternalHtlc ,
904
+ uint32 (len (req .DepositOutpoints )), int64 (selectedAmount ),
905
+ autoSelectDeposits ,
902
906
)
903
907
if err != nil {
904
908
return nil , err
905
909
}
906
910
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 (
912
952
ctx , & looprpc.ListStaticAddressDepositsRequest {
913
953
Outpoints : req .DepositOutpoints ,
914
954
},
@@ -922,20 +962,34 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
922
962
"deposit outpoints" )
923
963
}
924
964
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
+ numDeposits , len (depositList .FilteredDeposits ))
970
+ } else {
971
+ numDeposits = len (depositList .FilteredDeposits )
930
972
}
931
973
932
974
// 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
+ // selected value and the number of deposits. This is so the
976
+ // server can probe the selected value and calculate the per
977
+ // input fee.
978
+ for _ , deposit := range depositList .FilteredDeposits {
979
+ totalDepositAmount += btcutil .Amount (
980
+ deposit .Value ,
981
+ )
982
+ }
983
+
984
+ // If a fractional amount is also selected, we check if it would
985
+ // lead to a dust change output.
986
+ selectedAmount , err = loopin .SwapAmountFromSelectedAmount (
987
+ totalDepositAmount , selectedAmount ,
988
+ )
989
+ if err != nil {
990
+ return nil , fmt .Errorf ("error calculating " +
991
+ "swap amount from selected amount: %v" ,
992
+ err )
939
993
}
940
994
}
941
995
@@ -962,14 +1016,14 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
962
1016
}
963
1017
964
1018
quote , err := s .impl .LoopInQuote (ctx , & loop.LoopInQuoteRequest {
965
- Amount : amount ,
1019
+ Amount : selectedAmount ,
966
1020
HtlcConfTarget : htlcConfTarget ,
967
1021
ExternalHtlc : req .ExternalHtlc ,
968
1022
LastHop : lastHop ,
969
1023
RouteHints : routeHints ,
970
1024
Private : req .Private ,
971
1025
Initiator : defaultLoopdInitiator ,
972
- NumDeposits : numDeposits ,
1026
+ NumDeposits : uint32 ( numDeposits ) ,
973
1027
})
974
1028
if err != nil {
975
1029
return nil , err
@@ -1065,8 +1119,11 @@ func (s *swapClientServer) LoopIn(ctx context.Context,
1065
1119
1066
1120
infof ("Loop in request received" )
1067
1121
1122
+ selectDeposits := false
1123
+ numDeposits := uint32 (0 )
1068
1124
htlcConfTarget , err := validateLoopInRequest (
1069
- in .HtlcConfTarget , in .ExternalHtlc , 0 , in .Amt ,
1125
+ in .HtlcConfTarget , in .ExternalHtlc , numDeposits , in .Amt ,
1126
+ selectDeposits ,
1070
1127
)
1071
1128
if err != nil {
1072
1129
return nil , err
@@ -1868,6 +1925,7 @@ func (s *swapClientServer) StaticAddressLoopIn(ctx context.Context,
1868
1925
}
1869
1926
1870
1927
req := & loop.StaticAddressLoopInRequest {
1928
+ SelectedAmount : btcutil .Amount (in .Amount ),
1871
1929
DepositOutpoints : in .Outpoints ,
1872
1930
MaxSwapFee : btcutil .Amount (in .MaxSwapFeeSatoshis ),
1873
1931
Label : in .Label ,
@@ -2166,10 +2224,17 @@ func validateConfTarget(target, defaultTarget int32) (int32, error) {
2166
2224
// validateLoopInRequest fails if the mutually exclusive conf target and
2167
2225
// external parameters are both set.
2168
2226
func validateLoopInRequest (htlcConfTarget int32 , external bool ,
2169
- numDeposits uint32 , amount int64 ) (int32 , error ) {
2227
+ numDeposits uint32 , amount int64 , autoSelectDeposits bool ) (int32 ,
2228
+ error ) {
2170
2229
2171
2230
if amount == 0 && numDeposits == 0 {
2172
- return 0 , errors .New ("either amount or deposits must be set" )
2231
+ return 0 , errors .New ("either amount, or deposits or both " +
2232
+ "must be set" )
2233
+ }
2234
+
2235
+ if autoSelectDeposits && numDeposits > 0 {
2236
+ return 0 , errors .New ("cannot auto-select deposits while " +
2237
+ "providing deposits at the same time" )
2173
2238
}
2174
2239
2175
2240
// If the htlc is going to be externally set, the htlcConfTarget should
@@ -2187,7 +2252,7 @@ func validateLoopInRequest(htlcConfTarget int32, external bool,
2187
2252
2188
2253
// If the loop in uses static address deposits, we do not need to set a
2189
2254
// confirmation target since the HTLC won't be published by the client.
2190
- if numDeposits > 0 {
2255
+ if numDeposits > 0 || autoSelectDeposits {
2191
2256
return 0 , nil
2192
2257
}
2193
2258
0 commit comments