public async Task <IPaymentRequestTransaction> CreateTransactionAsync(ICreateTransactionCommand command) { IPaymentRequestTransaction transaction = await _transactionsService.CreateTransactionAsync(command); await _paymentRequestService.UpdateStatusAsync(command.WalletAddress); return(transaction); }
public async Task <ActionResult <AuthenticatedUser> > Register([FromBody] RegisterCredentials credentials) { var isAdded = await _users.AddUserAsync(credentials); if (isAdded) { var user = await _authenticateService.Authenticate(new LoginCredentials() { Email = credentials.Email, Password = credentials.Password }); if (user != null) { var transaction = await _transactions.CreateTransactionAsync(null, user.Id, REGISTRATION_BONUS, DateTime.Now); if (transaction != null) { var result = await _transactions.CommitTransactionAsync(transaction); if (result != null) { return(Ok(user)); } } } return(BadRequest(new { message = "Registration failed" })); } else { return(BadRequest(new { message = "User already registered" })); } }
public async Task <TransactionDto?> CreateNewTransactionAsync(ITransactionModel transactionModel) { if ( string.IsNullOrEmpty(transactionModel.ProfileId) || transactionModel.AccountId == Guid.Empty.ToString() || !await _licenseManager.EvaluateNewEntityAsync(transactionModel) ) { return(null); } // Optimistic Concurrency Control: set the sequential number var sequencedTransaction = await _concurrencyManager.SetNextSequentialNumber(transactionModel); var newTransaction = await _transactionsService.CreateTransactionAsync( sequencedTransaction.ToTransactionEntity() ); if (newTransaction != null) { await _publishEndpoint.Publish(newTransaction.ToTransactionModel <TransactionCreatedEvent>()); await _publishEndpoint.Publish(newTransaction.ToTransactionModel <TransactionCheckCommand>()); return(newTransaction.ToTransactionModel <TransactionDto>()); } return(null); }
private async Task RegisterTransferTxsAsync(TransferResult transfer, bool outgoing = true) { foreach (var transferTransactionResult in transfer.Transactions) { string historyId = outgoing ? await _walletHistoryService.PublishOutgoingExchangeAsync(Mapper .Map <WalletHistoryOutgoingExchangeCommand>(transferTransactionResult).Map(transfer)) : await _walletHistoryService.PublishIncomingExchangeAsync(Mapper .Map <WalletHistoryIncomingExchangeCommand>(transferTransactionResult).Map(transfer)); await _transactionsService.CreateTransactionAsync( new CreateTransactionCommand { Amount = transferTransactionResult.Amount, Blockchain = transfer.Blockchain, AssetId = transferTransactionResult.AssetId, Confirmations = 0, Hash = transferTransactionResult.Hash, IdentityType = transferTransactionResult.IdentityType, Identity = transferTransactionResult.Identity, TransferId = transfer.Id, Type = TransactionType.Exchange, SourceWalletAddresses = transferTransactionResult.Sources.ToArray(), ContextData = new ExchangeTransactonContext { HistoryOperationId = historyId }.ToJson() }); } }
public async Task <ActionResult <Transaction> > CreateTransaction([FromBody] UserTransaction userTransaction) { var transaction = await _transactions.CreateTransactionAsync(UserId, userTransaction.RecipientId, userTransaction.Amount, DateTime.Now); if (transaction != null) { return(Ok(transaction)); } return(BadRequest(new { message = $"Could not create transaction" })); }
public async void Should_CreateTransactionAsync_Valid() { var newTransactionEntity = new TransactionEntity { Amount = 1, Approved = true, ProfileId = 1.ToString(), Version = 0 }; var newCreatedTransactionsEntity = await _service.CreateTransactionAsync(newTransactionEntity); Assert.NotNull(newCreatedTransactionsEntity); }
public async Task <ActionResult <CreateTransactionResponse> > Post([FromBody] CreateTransactionRequest model) { var serviceModel = Mapper.Map <CreateTransactionModel>(model); try { var transaction = await _transactionsService.CreateTransactionAsync(serviceModel); var transactionItem = Mapper.Map <TransactionItem>(transaction); return(Ok(new CreateTransactionResponse(transactionItem))); } catch (CreateTransactionException ex) { if (ex.Error == CreateTransactionErrors.NotEnoughBalance) { return(BadRequest("Balance is low")); } throw; } }
public async Task <RefundResult> ExecuteAsync(string merchantId, string paymentRequestId, string destinationWalletAddress) { IPaymentRequest paymentRequest = await _paymentRequestService.GetAsync(merchantId, paymentRequestId); if (paymentRequest == null) { throw new RefundValidationException(RefundErrorType.PaymentRequestNotFound); } if (!paymentRequest.StatusValidForRefund()) { throw new RefundValidationException(RefundErrorType.NotAllowedInStatus); } IEnumerable <IPaymentRequestTransaction> paymentTxs = (await _transactionsService.GetByWalletAsync(paymentRequest.WalletAddress)).Where(x => x.IsPayment()).ToList(); if (!paymentTxs.Any()) { throw new RefundValidationException(RefundErrorType.NoPaymentTransactions); } if (paymentTxs.MoreThanOne()) { throw new RefundValidationException(RefundErrorType.MultitransactionNotSupported); } IPaymentRequestTransaction tx = paymentTxs.Single(); bool isValidAddress = string.IsNullOrWhiteSpace(destinationWalletAddress) || await _blockchainAddressValidator.Execute(destinationWalletAddress, tx.Blockchain); if (!isValidAddress) { throw new RefundValidationException(RefundErrorType.InvalidDestinationAddress); } if (!tx.SourceWalletAddresses.Any()) { throw new RefundValidationException(RefundErrorType.InvalidDestinationAddress); } if (string.IsNullOrWhiteSpace(destinationWalletAddress)) { if (tx.SourceWalletAddresses.MoreThanOne()) { throw new RefundValidationException(RefundErrorType.InvalidDestinationAddress); } } //validation finished, refund request accepted await _paymentRequestService.UpdateStatusAsync(paymentRequest.WalletAddress, PaymentRequestStatusInfo.RefundInProgress()); TransferResult transferResult; DateTime refundDueDate; try { TransferCommand refundTransferCommand = Mapper.Map <TransferCommand>(tx, opts => opts.Items["destinationAddress"] = destinationWalletAddress); transferResult = await _transferService.ExecuteAsync(refundTransferCommand); refundDueDate = transferResult.Timestamp.Add(_refundExpirationPeriod); foreach (var transferResultTransaction in transferResult.Transactions) { if (!string.IsNullOrEmpty(transferResultTransaction.Error)) { await _log.WriteWarningAsync(nameof(RefundService), nameof(ExecuteAsync), transferResultTransaction.ToJson(), "Transaction failed"); continue; } IPaymentRequestTransaction refundTransaction = await _transactionsService.CreateTransactionAsync( new CreateTransactionCommand { Amount = transferResultTransaction.Amount, AssetId = transferResultTransaction.AssetId, Confirmations = 0, Hash = transferResultTransaction.Hash, WalletAddress = paymentRequest.WalletAddress, Type = TransactionType.Refund, Blockchain = transferResult.Blockchain, FirstSeen = null, DueDate = refundDueDate, TransferId = transferResult.Id, IdentityType = transferResultTransaction.IdentityType, Identity = transferResultTransaction.Identity }); await _transactionPublisher.PublishAsync(refundTransaction); } if (transferResult.Transactions.All(x => x.HasError)) { throw new RefundOperationFailedException { TransferErrors = transferResult.Transactions.Select(x => x.Error) } } ; IEnumerable <TransferTransactionResult> errorTransactions = transferResult.Transactions.Where(x => x.HasError).ToList(); if (errorTransactions.Any()) { throw new RefundOperationPartiallyFailedException(errorTransactions.Select(x => x.Error)); } } catch (Exception) { await _paymentRequestService.UpdateStatusAsync(paymentRequest.WalletAddress, PaymentRequestStatusInfo.Error(PaymentRequestProcessingError.UnknownRefund)); throw; } return(await PrepareRefundResult(paymentRequest, transferResult, refundDueDate)); }
public async Task <PaymentResult> PayAsync(PaymentCommand cmd) { IPaymentRequest paymentRequest = await _paymentRequestRepository.GetAsync(cmd.MerchantId, cmd.PaymentRequestId); if (paymentRequest == null) { throw new PaymentRequestNotFoundException(cmd.MerchantId, cmd.PaymentRequestId); } string payerWalletAddress = (await _merchantWalletService.GetDefaultAsync( cmd.PayerMerchantId, paymentRequest.PaymentAssetId, PaymentDirection.Outgoing)).WalletAddress; string destinationWalletAddress = await _walletsManager.ResolveBlockchainAddressAsync( paymentRequest.WalletAddress, paymentRequest.PaymentAssetId); bool locked = await _paymentLocksService.TryAcquireLockAsync( paymentRequest.Id, cmd.MerchantId, paymentRequest.DueDate); if (!locked) { throw new DistributedLockAcquireException(paymentRequest.Id); } TransferResult transferResult; try { await UpdateStatusAsync(paymentRequest.WalletAddress, PaymentRequestStatusInfo.InProcess()); transferResult = await _paymentRetryPolicy .ExecuteAsync(() => _transferService.PayThrowFail( paymentRequest.PaymentAssetId, payerWalletAddress, destinationWalletAddress, cmd.Amount)); foreach (var transferResultTransaction in transferResult.Transactions) { IPaymentRequestTransaction paymentTx = await _transactionsService.CreateTransactionAsync( new CreateTransactionCommand { Amount = transferResultTransaction.Amount, Blockchain = transferResult.Blockchain, AssetId = transferResultTransaction.AssetId, WalletAddress = paymentRequest.WalletAddress, DueDate = paymentRequest.DueDate, IdentityType = transferResultTransaction.IdentityType, Identity = transferResultTransaction.Identity, Confirmations = 0, Hash = transferResultTransaction.Hash, TransferId = transferResult.Id, Type = TransactionType.Payment, SourceWalletAddresses = transferResultTransaction.Sources.ToArray() }); await _transactionPublisher.PublishAsync(paymentTx); } } catch (Exception e) { PaymentRequestStatusInfo newStatus = e is InsufficientFundsException ? PaymentRequestStatusInfo.New() : PaymentRequestStatusInfo.Error(PaymentRequestProcessingError.UnknownPayment); await UpdateStatusAsync(paymentRequest.WalletAddress, newStatus); await _paymentLocksService.ReleaseLockAsync(paymentRequest.Id, cmd.MerchantId); throw; } return(new PaymentResult { PaymentRequestId = paymentRequest.Id, PaymentRequestWalletAddress = paymentRequest.WalletAddress, AssetId = transferResult.Transactions.Unique(x => x.AssetId).Single(), Amount = transferResult.GetSuccedeedTxs().Sum(x => x.Amount) }); }
public async Task <CashoutResult> ExecuteAsync(CashoutCommand cmd) { BlockchainType network = await _assetSettingsService.GetNetworkAsync(cmd.SourceAssetId); string hotwallet = _bcnSettingsResolver.GetCashoutHotWallet(network); if (string.IsNullOrEmpty(hotwallet)) { throw new CashoutHotwalletNotDefinedException(network); } string sourceAddress = await GetSourceAddressAsync(cmd); await _walletBalanceValidator.ValidateTransfer(sourceAddress, cmd.SourceAssetId, cmd.SourceAmount); TransferResult toHotWallet = await _retryPolicy .ExecuteAsync(() => _transferService.CashoutThrowFail( cmd.SourceAssetId, sourceAddress, hotwallet, cmd.SourceAmount)); foreach (var transferTransactionResult in toHotWallet.Transactions) { string historyId = await _walletHistoryService.PublishCashoutAsync(new WalletHistoryCashoutCommand { Blockchain = toHotWallet.Blockchain, AssetId = transferTransactionResult.AssetId, Amount = transferTransactionResult.Amount, DesiredAsset = cmd.DesiredAsset, EmployeeEmail = cmd.EmployeeEmail, TransactionHash = transferTransactionResult.Hash, WalletAddress = string.Join(Constants.Separator, transferTransactionResult.Sources) }); await _transactionsService.CreateTransactionAsync(new CreateTransactionCommand { Amount = transferTransactionResult.Amount, Blockchain = toHotWallet.Blockchain, AssetId = transferTransactionResult.AssetId, Confirmations = 0, Hash = transferTransactionResult.Hash, IdentityType = transferTransactionResult.IdentityType, Identity = transferTransactionResult.Identity, TransferId = toHotWallet.Id, Type = TransactionType.CashOut, SourceWalletAddresses = transferTransactionResult.Sources.ToArray(), ContextData = new CashoutTransactionContext { DesiredAsset = cmd.DesiredAsset, EmployeeEmail = cmd.EmployeeEmail, HistoryOperationId = historyId }.ToJson() }); } return(new CashoutResult { Amount = cmd.SourceAmount, AssetId = cmd.SourceAssetId, SourceWalletAddress = sourceAddress, DestWalletAddress = hotwallet }); }