diff --git a/src/Helpers/CustomExceptions.cs b/src/Helpers/CustomExceptions.cs index 1a996553..be69d1e5 100644 --- a/src/Helpers/CustomExceptions.cs +++ b/src/Helpers/CustomExceptions.cs @@ -22,4 +22,9 @@ public PeerNotOnlineException(string? message = null): base(message) {} public class RemoteCanceledFundingException : Exception { public RemoteCanceledFundingException(string? message = null): base(message) {} +} + +public class NotEnoughRoomInUtxosForFeesException : Exception +{ + public NotEnoughRoomInUtxosForFeesException(): base("Not enough room in the UTXOs to cover the fees") {} } \ No newline at end of file diff --git a/src/Helpers/ValidationHelper.cs b/src/Helpers/ValidationHelper.cs index ec533bcb..3ff4f325 100644 --- a/src/Helpers/ValidationHelper.cs +++ b/src/Helpers/ValidationHelper.cs @@ -128,7 +128,7 @@ public static void ValidatePubKey(ValidatorEventArgs obj, List nodes, stri } } - public static void validateDestNode(ValidatorEventArgs obj, Node? destNode) + public static void ValidateDestNode(ValidatorEventArgs obj, Node? destNode) { obj.Status = ValidationStatus.Success; if (destNode == null) @@ -138,6 +138,21 @@ public static void validateDestNode(ValidatorEventArgs obj, Node? destNode) } } + public static void ValidateAmount(ValidatorEventArgs obj, decimal amount, decimal selectedUtxosAmount, bool isChangeless) + { + obj.Status = ValidationStatus.Success; + if (!isChangeless && amount > selectedUtxosAmount) + { + obj.Status = ValidationStatus.Error; + obj.ErrorText = "The amount is greater than the selected UTXOs amount"; + } + else if (!isChangeless && amount == selectedUtxosAmount) + { + obj.Status = ValidationStatus.Error; + obj.ErrorText = "The amount to send is equal to the selected UTXOs amount, there is no room in the UTXOs for change"; + } + } + /// /// Validated a xpub expect header and lenght size /// diff --git a/src/Jobs/ChannelOpenJob.cs b/src/Jobs/ChannelOpenJob.cs index 80a2ebb9..9e530f68 100644 --- a/src/Jobs/ChannelOpenJob.cs +++ b/src/Jobs/ChannelOpenJob.cs @@ -85,7 +85,7 @@ private async Task LogToChannelRequest(int openRequestId, Exception e, IJo try { var request = await _channelOperationRequestRepository.GetById(openRequestId); - if (e is PeerNotOnlineException or RemoteCanceledFundingException) + if (e is PeerNotOnlineException or RemoteCanceledFundingException or NotEnoughRoomInUtxosForFeesException) { request.StatusLogs.Add(ChannelStatusLog.Error(e.Message)); } diff --git a/src/Pages/ChannelRequests.razor b/src/Pages/ChannelRequests.razor index 23be98ff..d018c42f 100644 --- a/src/Pages/ChannelRequests.razor +++ b/src/Pages/ChannelRequests.razor @@ -55,7 +55,7 @@ - + @@ -141,16 +141,22 @@ - - - @{ - decimal amountToShow = _amount < _maxChannelCapacity - ? _amount - : _maxChannelCapacity; - decimal convertedAmount = Math.Round(PriceConversionService.SatToUsdConversion(new Money(amountToShow, MoneyUnit.BTC).Satoshi, _btcPrice), 2); - } - @($"Minimum {_minimumChannelCapacity:f8}. Current amount: {convertedAmount} USD") + + + + + + + + @{ + decimal amountToShow = _amount < _maxChannelCapacity + ? _amount + : _maxChannelCapacity; + decimal convertedAmount = Math.Round(PriceConversionService.SatToUsdConversion(new Money(amountToShow, MoneyUnit.BTC).Satoshi, _btcPrice), 2); + } + @($"Minimum {_minimumChannelCapacity:f8}. Current amount: {convertedAmount} USD") +
or use @@ -423,7 +429,8 @@ + OnClose="@OnCloseCoinSelectionModal" + IsWalletWithdrawalValidation="false"/> @inject IChannelOperationRequestRepository ChannelOperationRequestRepository @inject IChannelOperationRequestPSBTRepository ChannelOperationRequestPsbtRepository @@ -477,6 +484,7 @@ private Validation? _sourceNodeValidation; private Validation? _destNodeValidation; private Validation? _capacityValidation; + private Validation? _changelessValidation; private decimal _btcPrice; @@ -653,7 +661,7 @@ { if (LoggedUser == null) return; - List validators = new() { _destNodeValidation, _sourceNodeValidation, _walletValidation }; + List validators = new() { _destNodeValidation, _sourceNodeValidation, _walletValidation, _changelessValidation }; if (_selectedUTXOs.Count == 0) { validators.Add(_capacityValidation); @@ -999,6 +1007,11 @@ { _amount = SelectedUTXOsValue(); } + // Most probably, if the user selected all UTXOs is because they want to do a changeless operation + if (_selectedUTXOs.Count == _utxoSelectorModalRef.UTXOList.Count) + { + _isChangeless = true; + } StateHasChanged(); } diff --git a/src/Pages/Withdrawals.razor b/src/Pages/Withdrawals.razor index a3275bbf..533721ce 100644 --- a/src/Pages/Withdrawals.razor +++ b/src/Pages/Withdrawals.razor @@ -426,7 +426,7 @@ + IsWalletWithdrawalValidation="true"/> @inject IToastService ToastService @inject IWalletWithdrawalRequestRepository WalletWithdrawalRequestRepository diff --git a/src/Services/LightningService.cs b/src/Services/LightningService.cs index c2abe5fe..85553a2f 100644 --- a/src/Services/LightningService.cs +++ b/src/Services/LightningService.cs @@ -324,6 +324,10 @@ public async Task OpenChannel(ChannelOperationRequest channelOperationRequest) o.Value != channelOperationRequest.SatsAmount) ?? channelfundingTx.Outputs.First(); changeOutput.Value = totalIn - totalOut - totalChangefulFees; + if (changeOutput.Value < 0) + { + throw new NotEnoughRoomInUtxosForFeesException(); + } //We merge changeFixedPSBT with the other PSBT with the change fixed fundedPSBT = channelfundingTx.CreatePSBT(network).UpdateFrom(fundedPSBT); diff --git a/src/Shared/UTXOSelectorModal.razor b/src/Shared/UTXOSelectorModal.razor index f20d320b..7be055ca 100644 --- a/src/Shared/UTXOSelectorModal.razor +++ b/src/Shared/UTXOSelectorModal.razor @@ -226,17 +226,11 @@ { minimumValue = new Money(Constants.MINIMUM_CHANNEL_CAPACITY_SATS).ToUnit(MoneyUnit.BTC); } - var maxChannelRegtestValue = new Money(Constants.MAXIMUM_CHANNEL_CAPACITY_SATS_REGTEST).ToUnit(MoneyUnit.BTC); if (selectedUTXOsValue < minimumValue) { e.ErrorText = $"The combined amount of the UTXOs selected must be greater than {minimumValue:f8} BTC"; e.Status = ValidationStatus.Error; } - else if (selectedUTXOsValue > maxChannelRegtestValue && network == Network.RegTest && IsWalletWithdrawalValidation) - { - e.ErrorText = $"The combined amount of the UTXOs selected must be lower than {maxChannelRegtestValue:f8} BTC"; - e.Status = ValidationStatus.Error; - } else { e.Status = ValidationStatus.Success;