Skip to content

Commit

Permalink
Cancel withdrawal request when no available utxos (#370)
Browse files Browse the repository at this point in the history
* Cancel withdrawal request when no available utxos

* removed weird line break
  • Loading branch information
RodriFS committed Apr 23, 2024
1 parent 97aff15 commit fcc3a69
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 18 deletions.
4 changes: 3 additions & 1 deletion src/Data/Repositories/WalletWithdrawalRequestRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ public async Task<(bool, string?)> AddAsync(WalletWithdrawalRequest type)
return (false, "The wallet could not be found.");
}

type.Wallet = wallet;

var derivationStrategyBase = wallet.GetDerivationStrategy();

if (derivationStrategyBase == null)
Expand Down Expand Up @@ -279,4 +281,4 @@ public async Task<List<WalletWithdrawalRequest>> GetOnChainPendingWithdrawals()
return walletWithdrawalRequests;
}
}
}
}
7 changes: 6 additions & 1 deletion src/Helpers/CustomExceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,9 @@ public class PeerNotOnlineException : Exception
public class RemoteCanceledFundingException : Exception
{
public RemoteCanceledFundingException(string? message = null): base(message) {}
}
}

public class NotEnoughBalanceInWalletException : Exception
{
public NotEnoughBalanceInWalletException(string? message = null): base(message) {}
}
64 changes: 48 additions & 16 deletions src/Rpc/NodeGuardService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,17 @@ IFMUTXORepository fmutxoRepository
throw new RpcException(new Status(StatusCode.NotFound, "Wallet not found"));
}

if (request.Amount <= 0)
{
throw new RpcException(new Status(StatusCode.InvalidArgument, "Amount must be greater than 0"));
}

if (request.Address == "")
{
throw new RpcException(new Status(StatusCode.InvalidArgument,
"A destination address must be provided"));
}

//Create withdrawal request
var amount = new Money(request.Amount, MoneyUnit.Satoshi).ToUnit(MoneyUnit.BTC);

Expand All @@ -192,10 +203,10 @@ IFMUTXORepository fmutxoRepository

// Search the utxos and lock them
var derivationStrategyBase = wallet.GetDerivationStrategy();
if(derivationStrategyBase == null)

if (derivationStrategyBase == null)
throw new RpcException(new Status(StatusCode.Internal, "Derivation strategy not found"));

utxos = await _coinSelectionService.GetUTXOsByOutpointAsync(derivationStrategyBase, outpoints);
amount = utxos.Sum(u => ((Money)u.Value).ToUnit(MoneyUnit.BTC));
}
Expand All @@ -211,12 +222,17 @@ IFMUTXORepository fmutxoRepository
: WalletWithdrawalRequestStatus.Pending,
RequestMetadata = request.RequestMetadata,
Changeless = request.Changeless,
MempoolRecommendedFeesType = (MempoolRecommendedFeesType) request.MempoolFeeRate,
MempoolRecommendedFeesType = (MempoolRecommendedFeesType)request.MempoolFeeRate,
CustomFeeRate = request.CustomFeeRate
};

//Save withdrawal request
var withdrawalSaved = await _walletWithdrawalRequestRepository.AddAsync(withdrawalRequest);
if (!withdrawalSaved.Item1 && withdrawalSaved.Item2!.Contains("does not have enough funds"))
{
_logger.LogError(withdrawalSaved.Item2);
throw new NotEnoughBalanceInWalletException(withdrawalSaved.Item2);
}

if (!withdrawalSaved.Item1)
{
Expand All @@ -239,7 +255,7 @@ IFMUTXORepository fmutxoRepository
_logger.LogError("Error saving withdrawal request for wallet with id {walletId}", request.WalletId);
throw new RpcException(new Status(StatusCode.Internal, "Error saving withdrawal request for wallet"));
}

//Template PSBT generation with SIGHASH_ALL
var psbt = await _bitcoinService.GenerateTemplatePSBT(withdrawalRequest ?? throw new ArgumentException(nameof(withdrawalRequest)));

Expand All @@ -264,25 +280,41 @@ IFMUTXORepository fmutxoRepository
}
catch (NoUTXOsAvailableException)
{
CancelWithdrawalRequest(withdrawalRequest);
_logger.LogError("No available UTXOs for wallet with id {walletId}", request.WalletId);
throw new RpcException(new Status(StatusCode.Internal, "No available UTXOs for wallet"));
throw new RpcException(new Status(StatusCode.ResourceExhausted, "No available UTXOs for wallet"));
}
catch (NotEnoughBalanceInWalletException e)
{
_logger.LogError(e.Message);
throw new RpcException(new Status(StatusCode.ResourceExhausted, e.Message));
}
catch (RpcException e)
{
CancelWithdrawalRequest(withdrawalRequest);
_logger.LogError(e.Message);
throw new RpcException(new Status(e.Status.StatusCode, e.Status.Detail));
}
catch (Exception e)
{
if (withdrawalRequest != null)
{
withdrawalRequest.Status = WalletWithdrawalRequestStatus.Cancelled;
var (success, error) = _walletWithdrawalRequestRepository.Update(withdrawalRequest);
if (!success)
{
_logger.LogError(e, "Error updating status of withdrawal request {RequestId} for wallet {WalletId}", withdrawalRequest.Id, request.WalletId);
}
}
CancelWithdrawalRequest(withdrawalRequest);
_logger.LogError(e, "Error requesting withdrawal for wallet with id {walletId}", request.WalletId);
throw new RpcException(new Status(StatusCode.Internal, "Error requesting withdrawal for wallet"));
}
}

private void CancelWithdrawalRequest(WalletWithdrawalRequest? withdrawalRequest)
{
if (withdrawalRequest != null)
{
withdrawalRequest.Status = WalletWithdrawalRequestStatus.Cancelled;
var (success, error) = _walletWithdrawalRequestRepository.Update(withdrawalRequest);
if (!success)
{
_logger.LogError(error, "Error updating status of withdrawal request {RequestId} for wallet {WalletId}", withdrawalRequest.Id, withdrawalRequest.WalletId);
}
}
}
public override async Task<GetAvailableWalletsResponse> GetAvailableWallets(GetAvailableWalletsRequest request,
ServerCallContext context)
{
Expand Down Expand Up @@ -965,4 +997,4 @@ private bool ValidateBitcoinAddress(string address)

return true;
}
}
}

0 comments on commit fcc3a69

Please sign in to comment.