private async Task <CustomerBalanceResultModel> InternalGetAsync(string customerId) { var value = await GetCachedValue(customerId); if (value != null) { return(value.DeserializeJson <CustomerBalanceResultModel>()); } var walletAddressResult = await _walletsService.GetCustomerWalletAsync(customerId); switch (walletAddressResult.Error) { case CustomerWalletAddressError.CustomerWalletMissing: return(CustomerBalanceResultModel.Failed(CustomerBalanceError.CustomerWalletMissing)); case CustomerWalletAddressError.InvalidCustomerId: return(CustomerBalanceResultModel.Failed(CustomerBalanceError.InvalidCustomerId)); case CustomerWalletAddressError.None: break; default: throw new ArgumentOutOfRangeException(nameof(walletAddressResult.Error)); } var balanceResponse = await _quorumOperationExecutorClient.AddressesApi.GetBalanceForAddressAsync(walletAddressResult.WalletAddress); var transfersInProgress = await _operationsFetcher.GetTransfersInProgressAsync(walletAddressResult.WalletAddress); var transfersInProgressAmount = transfersInProgress .Select(x => JsonConvert.DeserializeObject <TokensTransferContext>(x.ContextJson)) .Sum(x => x.Amount); var seizedAmount = (await _operationsFetcher.GetSeizeOperationsInProgressAsync(customerId)) .Select(x => JsonConvert.DeserializeObject <SeizeToInternalContext>(x.ContextJson)) .Sum(x => x.Amount); var reservedAmount = transfersInProgressAmount + seizedAmount; if (balanceResponse.Balance < reservedAmount) { _log.Warning( $"The reserved amount ({reservedAmount}) is more than actual balance ({balanceResponse.Balance})", context: new { customerId }); } var availableBalance = balanceResponse.Balance - balanceResponse.StakedBalance >= reservedAmount ? balanceResponse.Balance - balanceResponse.StakedBalance - reservedAmount : 0; var result = CustomerBalanceResultModel.Succeeded(availableBalance, balanceResponse.StakedBalance); await SetCacheValueAsync(customerId, result); return(result); }
public async Task HandleAsync_CustomerHas0Balance_PublisherCalledAndWalletOwnersRepoNotCalled() { _balanceServiceMock.Setup(x => x.GetAsync(FakeCustomerId)) .ReturnsAsync(CustomerBalanceResultModel.Succeeded(0, 0)); var sut = CreateSutInstance(); await sut.HandleAsync(FakeCustomerId); _seizeBalanceFromCustomerCompletedPublisher.Verify(x => x.PublishAsync(It.Is <SeizeBalanceFromCustomerCompletedEvent>(e => e.CustomerId == FakeCustomerId))); _walletOwnersRepoMock.Verify(x => x.GetByOwnerIdAsync(FakeCustomerId), Times.Never); }
public async Task HandleAsync_WalletOwnerDoesNotExist_OperationProducerNotCalled() { _balanceServiceMock.Setup(x => x.GetAsync(FakeCustomerId)) .ReturnsAsync(CustomerBalanceResultModel.Succeeded(FakeBalance, 0)); _walletOwnersRepoMock.Setup(x => x.GetByOwnerIdAsync(FakeCustomerId)) .ReturnsAsync((IWalletOwner)null); var sut = CreateSutInstance(); await sut.HandleAsync(FakeCustomerId); _operationRequestProducerMock.Verify( x => x.AddAsync(FakeCustomerId, OperationType.SeizeToInternal, It.IsAny <SeizeToInternalContext>(), null), Times.Never); }
public async Task TransferToExternalAsync_SenderWalletNotEnoughFunds_ReturnsFail(long transferAmount, long fee, long balanceAmount) { _walletsServiceMock .Setup(x => x.GetCustomerWalletAsync(It.IsAny <string>())) .ReturnsAsync(CustomerWalletAddressResultModel.Succeeded(FakeWalletAddress)); _balanceServiceMock .Setup(x => x.GetAsync(It.IsAny <string>())) .ReturnsAsync(CustomerBalanceResultModel.Succeeded(balanceAmount, FakeStakedAmount)); var sut = CreateSutInstance(); var result = await sut.TransferToExternalAsync(FakeSenderCustomerId, FakeWalletAddress, transferAmount, fee, FakeTransferId); Assert.Equal(TransferError.NotEnoughFunds, result.Error); }
public async Task HandleAsync__OperationProducerCalled() { _balanceServiceMock.Setup(x => x.GetAsync(FakeCustomerId)) .ReturnsAsync(CustomerBalanceResultModel.Succeeded(FakeBalance, 0)); _walletOwnersRepoMock.Setup(x => x.GetByOwnerIdAsync(FakeCustomerId)) .ReturnsAsync(new WalletOwnerEntity { WalletId = FakeWalletId }); var sut = CreateSutInstance(); await sut.HandleAsync(FakeCustomerId); _operationRequestProducerMock.Verify( x => x.AddAsync(FakeCustomerId, OperationType.SeizeToInternal, It.Is <SeizeToInternalContext>(c => c.Account == FakeWalletId && c.Amount == FakeBalance), null), Times.Once); }
public async Task HandleAsync_OperationFound_FinishesSuccessfully() { _walletOwnersRepositoryMock .Setup(x => x.GetByWalletAddressAsync(It.IsAny <string>())) .ReturnsAsync(new WalletOwnerEntity()); _balanceServiceMock .Setup(x => x.ForceBalanceUpdateAsync(It.IsAny <string>(), It.IsAny <OperationType>(), It.IsAny <Guid>())) .ReturnsAsync(CustomerBalanceResultModel.Succeeded(ValidBalance, FakeStakedAmount)) .Verifiable(); _operationsFetcherMock .Setup(x => x.GetByHashAsync(It.IsAny <string>())) .ReturnsAsync(new OperationEntity { ContextJson = new TokensTransferContext { RequestId = "whatever" }.ToJson() }); _transferDetectedPublisherMock .Setup(x => x.PublishAsync(It.IsAny <TransferDetectedEvent>())) .Returns(Task.CompletedTask) .Verifiable(); var sut = CreateSutInstance(); await sut.HandleAsync( FakeWalletAddress1, FakeWalletAddress2, ValidAmount, ValidTransactionHash, DateTime.UtcNow); _balanceServiceMock.Verify( x => x.ForceBalanceUpdateAsync(It.IsAny <string>(), It.IsAny <OperationType>(), It.IsAny <Guid>()), Times.Exactly(2)); _p2PTransferPublisherMock.Verify(x => x.PublishAsync(It.IsAny <P2PTransferDetectedEvent>()), Times.Once); _transferDetectedPublisherMock.Verify(x => x.PublishAsync(It.IsAny <TransferDetectedEvent>()), Times.Once); }
public async Task TransferToExternalAsync_IsDuplicateCheck_WorksCorrectly(bool isDuplicate, TransferError expectedError) { const long amount = 100; _walletsServiceMock .Setup(x => x.GetCustomerWalletAsync(It.IsAny <string>())) .ReturnsAsync(CustomerWalletAddressResultModel.Succeeded(FakeWalletAddress)); _balanceServiceMock .Setup(x => x.GetAsync(It.IsAny <string>())) .ReturnsAsync(CustomerBalanceResultModel.Succeeded(amount, FakeStakedAmount)); _deduplicationLogMock .Setup(x => x.IsDuplicateAsync(It.IsAny <string>())) .ReturnsAsync(isDuplicate); var sut = CreateSutInstance(); var result = await sut.TransferToExternalAsync(FakeSenderCustomerId, FakeWalletAddress, amount, 0, FakeTransferId); Assert.Equal(expectedError, result.Error); }