/// <summary> /// We get the details via the wallet service's history method. /// </summary> private async Task <WalletHistoryModel> GetWatchOnlyTransactionAsync(uint256 trxid) { var accountReference = this.GetWatchOnlyWalletAccountReference(); var request = new WalletHistoryRequest() { WalletName = accountReference.WalletName, AccountName = Wallet.WatchOnlyAccountName, SearchQuery = trxid.ToString(), }; var history = await this.walletService.GetHistory(request, default); return(history); }
public IActionResult GetHistory([FromQuery] WalletHistoryRequest request) { // checks the request is valid if (!this.ModelState.IsValid) { var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors))); } try { WalletHistoryModel model = new WalletHistoryModel { Transactions = new List <TransactionItem>() }; // get transactions contained in the wallet var addresses = this.walletManager.GetHistoryByCoinType(request.WalletName, request.CoinType); foreach (var address in addresses) { foreach (var transaction in address.Transactions) { model.Transactions.Add(new TransactionItem { Amount = transaction.Amount, Confirmed = transaction.Confirmed, Timestamp = transaction.CreationTime, TransactionId = transaction.Id, Address = address.Address }); } } model.Transactions = model.Transactions.OrderByDescending(t => t.Timestamp).ToList(); return(this.Json(model)); } catch (Exception e) { return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public async Task GetWalletHistory() { const int unixTimeSeconds = 1493942400; _fakeHttpMessageHandler.HandleRequestAsync = TestHelper.HandleContent(form => { Assert.Equal(unixTimeSeconds.ToString(CultureInfo.InvariantCulture), form["date"]); }); _fakeHttpMessageHandler.ResponseMessage = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("{\"result\":true,\"error\":\"\",\"begin\":\"1493942400\",\"end\":\"1494028800\",\"history\":[{\"dt\":1461841192,\"type\":\"deposit\",\"curr\":\"RUB\",\"status\":\"processing\",\"provider\":\"Qiwi (LA) [12345]\",\"amount\":\"1\",\"account\":\"\",\"txid\":\"ec46f784ad976fd7f7539089d1a129fe46\"},{\"dt\":1463414785,\"type\":\"withdrawal\",\"curr\":\"USD\",\"status\":\"paid\",\"provider\":\"EXCODE\",\"amount\":\"-1\",\"account\":\"EX-CODE_19371_USDda\",\"txid\":\"\"}]}") }; var request = new WalletHistoryRequest { Date = DateTimeOffset.FromUnixTimeSeconds(unixTimeSeconds) }; var walletHistory = await _authenticatedApi.GetWalletHistoryAsync(request); Assert.Equal(1493942400, walletHistory.Begin.ToUnixTimeSeconds()); Assert.Equal(1494028800, walletHistory.End.ToUnixTimeSeconds()); Assert.Equal(2, walletHistory.History.Length); Assert.Equal(1461841192, walletHistory.History[0].Date.ToUnixTimeSeconds()); Assert.Equal("deposit", walletHistory.History[0].Type); Assert.Equal("RUB", walletHistory.History[0].Currency); Assert.Equal("processing", walletHistory.History[0].Status); Assert.Equal("Qiwi (LA) [12345]", walletHistory.History[0].Provider); Assert.Equal(1m, walletHistory.History[0].Amount); Assert.Equal("", walletHistory.History[0].Account); Assert.Equal("ec46f784ad976fd7f7539089d1a129fe46", walletHistory.History[0].TransactionId); Assert.Equal(1463414785, walletHistory.History[1].Date.ToUnixTimeSeconds()); Assert.Equal("withdrawal", walletHistory.History[1].Type); Assert.Equal("USD", walletHistory.History[1].Currency); Assert.Equal("paid", walletHistory.History[1].Status); Assert.Equal("EXCODE", walletHistory.History[1].Provider); Assert.Equal(-1m, walletHistory.History[1].Amount); Assert.Equal("EX-CODE_19371_USDda", walletHistory.History[1].Account); Assert.Equal("", walletHistory.History[1].TransactionId); }
public IActionResult GetHistory([FromQuery] WalletHistoryRequest request) { Guard.NotNull(request, nameof(request)); if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } try { var model = new WalletHistoryModel(); // Get a list of all the transactions found in an account (or in a wallet if no account is specified), with the addresses associated with them. IEnumerable <AccountHistory> accountsHistory = this.walletManager.GetHistory(request.WalletName, request.AccountName); foreach (AccountHistory accountHistory in accountsHistory) { var transactionItems = new List <TransactionItemModel>(); List <FlatHistory> items = accountHistory.History.OrderByDescending(o => o.Transaction.CreationTime).Take(200).ToList(); // Represents a sublist containing only the transactions that have already been spent. List <FlatHistory> spendingDetails = items.Where(t => t.Transaction.SpendingDetails != null).ToList(); // Represents a sublist of transactions associated with receive addresses + a sublist of already spent transactions associated with change addresses. // In effect, we filter out 'change' transactions that are not spent, as we don't want to show these in the history. List <FlatHistory> history = items.Where(t => !t.Address.IsChangeAddress() || (t.Address.IsChangeAddress() && !t.Transaction.IsSpendable())).ToList(); // Represents a sublist of 'change' transactions. List <FlatHistory> allchange = items.Where(t => t.Address.IsChangeAddress()).ToList(); foreach (FlatHistory item in history) { TransactionData transaction = item.Transaction; HdAddress address = item.Address; // We don't show in history transactions that are outputs of staking transactions. if (transaction.IsCoinStake != null && transaction.IsCoinStake.Value && transaction.SpendingDetails == null) { continue; } // First we look for staking transaction as they require special attention. // A staking transaction spends one of our inputs into 2 outputs, paid to the same address. if (transaction.SpendingDetails?.IsCoinStake != null && transaction.SpendingDetails.IsCoinStake.Value) { // We look for the 2 outputs related to our spending input. List <FlatHistory> relatedOutputs = items.Where(h => h.Transaction.Id == transaction.SpendingDetails.TransactionId && h.Transaction.IsCoinStake != null && h.Transaction.IsCoinStake.Value).ToList(); if (relatedOutputs.Any()) { // Add staking transaction details. // The staked amount is calculated as the difference between the sum of the outputs and the input and should normally be equal to 1. var stakingItem = new TransactionItemModel { Type = TransactionItemType.Staked, ToAddress = address.Address, Amount = relatedOutputs.Sum(o => o.Transaction.Amount) - transaction.Amount, Id = transaction.SpendingDetails.TransactionId, Timestamp = transaction.SpendingDetails.CreationTime, ConfirmedInBlock = transaction.SpendingDetails.BlockHeight }; transactionItems.Add(stakingItem); } // No need for further processing if the transaction itself is the output of a staking transaction. if (transaction.IsCoinStake != null) { continue; } } // Create a record for a 'receive' transaction. if (!address.IsChangeAddress()) { // Add incoming fund transaction details. var receivedItem = new TransactionItemModel { Type = TransactionItemType.Received, ToAddress = address.Address, Amount = transaction.Amount, Id = transaction.Id, Timestamp = transaction.CreationTime, ConfirmedInBlock = transaction.BlockHeight }; transactionItems.Add(receivedItem); } // If this is a normal transaction (not staking) that has been spent, add outgoing fund transaction details. if (transaction.SpendingDetails != null && transaction.SpendingDetails.IsCoinStake == null) { // Create a record for a 'send' transaction. uint256 spendingTransactionId = transaction.SpendingDetails.TransactionId; var sentItem = new TransactionItemModel { Type = TransactionItemType.Send, Id = spendingTransactionId, Timestamp = transaction.SpendingDetails.CreationTime, ConfirmedInBlock = transaction.SpendingDetails.BlockHeight, Amount = Money.Zero }; // If this 'send' transaction has made some external payments, i.e the funds were not sent to another address in the wallet. if (transaction.SpendingDetails.Payments != null) { sentItem.Payments = new List <PaymentDetailModel>(); foreach (PaymentDetails payment in transaction.SpendingDetails.Payments) { sentItem.Payments.Add(new PaymentDetailModel { DestinationAddress = payment.DestinationAddress, Amount = payment.Amount }); sentItem.Amount += payment.Amount; } } // Get the change address for this spending transaction. FlatHistory changeAddress = allchange.FirstOrDefault(a => a.Transaction.Id == spendingTransactionId); // Find all the spending details containing the spending transaction id and aggregate the sums. // This is our best shot at finding the total value of inputs for this transaction. var inputsAmount = new Money(spendingDetails.Where(t => t.Transaction.SpendingDetails.TransactionId == spendingTransactionId).Sum(t => t.Transaction.Amount)); // The fee is calculated as follows: funds in utxo - amount spent - amount sent as change. sentItem.Fee = inputsAmount - sentItem.Amount - (changeAddress == null ? 0 : changeAddress.Transaction.Amount); // Mined/staked coins add more coins to the total out. // That makes the fee negative. If that's the case ignore the fee. if (sentItem.Fee < 0) { sentItem.Fee = 0; } if (!transactionItems.Contains(sentItem, new SentTransactionItemModelComparer())) { transactionItems.Add(sentItem); } } } model.AccountsHistoryModel.Add(new AccountHistoryModel { TransactionsHistory = transactionItems.OrderByDescending(t => t.Timestamp).ToList(), Name = accountHistory.Account.Name, CoinType = this.coinType, HdPath = accountHistory.Account.HdPath }); } return(this.Json(model)); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public IActionResult GetHistory([FromQuery] WalletHistoryRequest request) { // checks the request is valid if (!this.ModelState.IsValid) { var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors))); } try { WalletHistoryModel model = new WalletHistoryModel { TransactionsHistory = new List <TransactionItemModel>() }; // get transactions contained in the wallet var addresses = this.walletManager.GetHistoryByCoinType(request.WalletName, this.coinType); foreach (var address in addresses.Where(a => !a.IsChangeAddress())) { foreach (var transaction in address.Transactions) { // add incoming fund transaction details TransactionItemModel receivedItem = new TransactionItemModel { Type = TransactionItemType.Received, ToAddress = address.Address, Amount = transaction.Amount, Id = transaction.Id, Timestamp = transaction.CreationTime, ConfirmedInBlock = transaction.BlockHeight }; model.TransactionsHistory.Add(receivedItem); // add outgoing fund transaction details if (transaction.SpendingDetails != null) { TransactionItemModel sentItem = new TransactionItemModel(); sentItem.Type = TransactionItemType.Send; sentItem.Id = transaction.SpendingDetails.TransactionId; sentItem.Timestamp = transaction.SpendingDetails.CreationTime; sentItem.ConfirmedInBlock = transaction.SpendingDetails.BlockHeight; sentItem.Amount = Money.Zero; if (transaction.SpendingDetails.Payments != null) { sentItem.Payments = new List <PaymentDetailModel>(); foreach (var payment in transaction.SpendingDetails.Payments) { sentItem.Payments.Add(new PaymentDetailModel { DestinationAddress = payment.DestinationAddress, Amount = payment.Amount }); sentItem.Amount += payment.Amount; } } // get the change address for this spending transaction var changeAddress = addresses.SingleOrDefault(a => a.IsChangeAddress() && a.Transactions.Any(t => t.Id == transaction.SpendingDetails.TransactionId)); // the fee is calculated as follows: fund in utxo - amount spent - amount sent as change sentItem.Fee = transaction.Amount - sentItem.Amount - (changeAddress == null ? 0 : changeAddress.Transactions.First(t => t.Id == transaction.SpendingDetails.TransactionId).Amount); // mined/staked coins add more coins to the total out // that makes the fee negative if thats the case ignore the fee if (sentItem.Fee < 0) { sentItem.Fee = 0; } model.TransactionsHistory.Add(sentItem); } } } model.TransactionsHistory = model.TransactionsHistory.OrderByDescending(t => t.Timestamp).ToList(); return(this.Json(model)); } catch (Exception e) { return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public IActionResult GetHistory([FromQuery] WalletHistoryRequest request) { Guard.NotNull(request, nameof(request)); // checks the request is valid if (!this.ModelState.IsValid) { var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors))); } try { WalletHistoryModel model = new WalletHistoryModel(); // get transactions contained in the wallet var items = this.walletManager.GetHistory(request.WalletName).ToList().OrderByDescending(o => o.Transaction.CreationTime).Take(100).ToList(); List <FlatHistory> spendingDetails = items.Where(t => t.Transaction.SpendingDetails != null).ToList(); List <FlatHistory> filtered = items.Where(t => !t.Address.IsChangeAddress() || (t.Address.IsChangeAddress() && !t.Transaction.IsSpendable())).ToList(); List <FlatHistory> allchange = items.Where(t => t.Address.IsChangeAddress()).ToList(); foreach (var item in filtered) { var transaction = item.Transaction; var address = item.Address; if (!address.IsChangeAddress()) { // add incoming fund transaction details TransactionItemModel receivedItem = new TransactionItemModel { Type = TransactionItemType.Received, ToAddress = address.Address, Amount = transaction.Amount, Id = transaction.Id, Timestamp = transaction.CreationTime, ConfirmedInBlock = transaction.BlockHeight }; model.TransactionsHistory.Add(receivedItem); } // add outgoing fund transaction details if (transaction.SpendingDetails != null) { var spendingTransactionId = transaction.SpendingDetails.TransactionId; TransactionItemModel sentItem = new TransactionItemModel { Type = TransactionItemType.Send, Id = spendingTransactionId, Timestamp = transaction.SpendingDetails.CreationTime, ConfirmedInBlock = transaction.SpendingDetails.BlockHeight, Amount = Money.Zero }; if (transaction.SpendingDetails.Payments != null) { sentItem.Payments = new List <PaymentDetailModel>(); foreach (var payment in transaction.SpendingDetails.Payments) { sentItem.Payments.Add(new PaymentDetailModel { DestinationAddress = payment.DestinationAddress, Amount = payment.Amount }); sentItem.Amount += payment.Amount; } } // get the change address for this spending transaction var changeAddress = allchange.FirstOrDefault(a => a.Transaction.Id == spendingTransactionId); // find all the spending details containing the spending transaction id and aggregate the sums. // this is our best shot at finding the total value of inputs for this transaction. var inputsAmount = new Money(spendingDetails.Where(t => t.Transaction.SpendingDetails.TransactionId == spendingTransactionId).Sum(t => t.Transaction.Amount)); // the fee is calculated as follows: funds in utxo - amount spent - amount sent as change sentItem.Fee = inputsAmount - sentItem.Amount - (changeAddress == null ? 0 : changeAddress.Transaction.Amount); // mined/staked coins add more coins to the total out // that makes the fee negative if that's the case ignore the fee if (sentItem.Fee < 0) { sentItem.Fee = 0; } if (!model.TransactionsHistory.Contains(sentItem, new SentTransactionItemModelComparer())) { model.TransactionsHistory.Add(sentItem); } } } model.TransactionsHistory = model.TransactionsHistory.OrderByDescending(t => t.Timestamp).ToList(); return(this.Json(model)); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
/// <summary> /// This method is an attempt to fetch history and its complex calculation directly from disk /// and avoid the need to fetch the entire history to memory /// </summary> public static WalletHistoryModel GetHistorySlim(IWalletManager walletManager, Network network, WalletHistoryRequest request) { if (!string.IsNullOrEmpty(request.Address)) { throw new NotImplementedException("Search by address not implemented"); } if (!string.IsNullOrEmpty(request.SearchQuery)) { throw new NotImplementedException("Search by SearchQuery not implemented"); } var model = new WalletHistoryModel(); // Get a list of all the transactions found in an account (or in a wallet if no account is specified), with the addresses associated with them. IEnumerable <AccountHistorySlim> accountsHistory = walletManager.GetHistorySlim(request.WalletName, request.AccountName, skip: request.Skip ?? 0, take: request.Take ?? int.MaxValue); foreach (AccountHistorySlim accountHistory in accountsHistory) { var transactionItems = new List <TransactionItemModel>(); foreach (FlatHistorySlim item in accountHistory.History) { var modelItem = new TransactionItemModel { Type = item.Transaction.IsSent ? TransactionItemType.Send : TransactionItemType.Received, ToAddress = item.Transaction.Address, Amount = item.Transaction.IsSent == false ? item.Transaction.Amount : Money.Zero, Id = item.Transaction.IsSent ? item.Transaction.SentTo : item.Transaction.OutPoint.Hash, Timestamp = item.Transaction.CreationTime, ConfirmedInBlock = item.Transaction.BlockHeight, BlockIndex = item.Transaction.BlockIndex }; if (item.Transaction.IsSent == true) // handle send entries { // First we look for staking transaction as they require special attention. // A staking transaction spends one of our inputs into 2 outputs or more, paid to the same address. if ((item.Transaction.IsCoinStake ?? false == true)) { if (item.Transaction.IsSent == true) { modelItem.Type = TransactionItemType.Staked; var amount = item.Transaction.SentPayments.Sum(p => p.Amount); modelItem.Amount = amount - item.Transaction.Amount; } else { // We don't show in history transactions that are outputs of staking transactions. continue; } } else { if (item.Transaction.SentPayments.All(a => a.PayToSelf == true)) { // if all outputs are to ourself // we don't show that in history continue; } modelItem.Amount = item.Transaction.SentPayments.Where(x => x.PayToSelf == false).Sum(p => p.Amount); } } else // handle receive entries { if (item.Address.IsChangeAddress()) { // we don't display transactions sent to self continue; } if (item.Transaction.IsCoinStake.HasValue && item.Transaction.IsCoinStake.Value == true) { // We don't show in history transactions that are outputs of staking transactions. continue; } } transactionItems.Add(modelItem); } model.AccountsHistoryModel.Add(new AccountHistoryModel { TransactionsHistory = transactionItems, Name = accountHistory.Account.Name, CoinType = network.Consensus.CoinType, HdPath = accountHistory.Account.HdPath }); } return(model); }
public static WalletHistoryModel GetHistory(IWalletManager walletManager, Network network, WalletHistoryRequest request) { var model = new WalletHistoryModel(); // Get a list of all the transactions found in an account (or in a wallet if no account is specified), with the addresses associated with them. IEnumerable <AccountHistory> accountsHistory = walletManager.GetHistory(request.WalletName, request.AccountName); foreach (AccountHistory accountHistory in accountsHistory) { var transactionItems = new List <TransactionItemModel>(); var uniqueProcessedTxIds = new HashSet <uint256>(); IEnumerable <FlatHistory> query = accountHistory.History; if (!string.IsNullOrEmpty(request.Address)) { query = query.Where(x => x.Address.Address == request.Address); } // Sorting the history items by descending dates. That includes received and sent dates. List <FlatHistory> items = query .OrderBy(o => o.Transaction.IsConfirmed() ? 1 : 0) .ThenByDescending(o => o.Transaction.SpendingDetails?.CreationTime ?? o.Transaction.CreationTime) .ToList(); // Represents a sublist containing only the transactions that have already been spent. List <FlatHistory> spendingDetails = items.Where(t => t.Transaction.SpendingDetails != null).ToList(); // Represents a sublist of transactions associated with receive addresses + a sublist of already spent transactions associated with change addresses. // In effect, we filter out 'change' transactions that are not spent, as we don't want to show these in the history. List <FlatHistory> history = items.Where(t => !t.Address.IsChangeAddress() || (t.Address.IsChangeAddress() && t.Transaction.IsSpent())).ToList(); // Represents a sublist of 'change' transactions. List <FlatHistory> allchange = items.Where(t => t.Address.IsChangeAddress()).ToList(); foreach (FlatHistory item in history) { // Count only unique transactions and limit it to MaxHistoryItemsPerAccount. int processedTransactions = uniqueProcessedTxIds.Count; if (processedTransactions >= WalletController.MaxHistoryItemsPerAccount) { break; } TransactionOutputData transaction = item.Transaction; HdAddress address = item.Address; // First we look for staking transaction as they require special attention. // A staking transaction spends one of our inputs into 2 outputs or more, paid to the same address. if (transaction.SpendingDetails?.IsCoinStake != null && transaction.SpendingDetails.IsCoinStake.Value) { // We look for the output(s) related to our spending input. List <FlatHistory> relatedOutputs = items.Where(h => h.Transaction.Id == transaction.SpendingDetails.TransactionId && h.Transaction.IsCoinStake != null && h.Transaction.IsCoinStake.Value).ToList(); if (relatedOutputs.Any()) { // Add staking transaction details. // The staked amount is calculated as the difference between the sum of the outputs and the input and should normally be equal to 1. var stakingItem = new TransactionItemModel { Type = TransactionItemType.Staked, ToAddress = address.Address, Amount = relatedOutputs.Sum(o => o.Transaction.Amount) - transaction.Amount, Id = transaction.SpendingDetails.TransactionId, Timestamp = transaction.SpendingDetails.CreationTime, ConfirmedInBlock = transaction.SpendingDetails.BlockHeight, BlockIndex = transaction.SpendingDetails.BlockIndex }; transactionItems.Add(stakingItem); uniqueProcessedTxIds.Add(stakingItem.Id); } // No need for further processing if the transaction itself is the output of a staking transaction. if (transaction.IsCoinStake != null) { continue; } } // If this is a normal transaction (not staking) that has been spent, add outgoing fund transaction details. if (transaction.SpendingDetails != null && transaction.SpendingDetails.IsCoinStake == null) { // Create a record for a 'send' transaction. uint256 spendingTransactionId = transaction.SpendingDetails.TransactionId; var sentItem = new TransactionItemModel { Type = TransactionItemType.Send, Id = spendingTransactionId, Timestamp = transaction.SpendingDetails.CreationTime, ConfirmedInBlock = transaction.SpendingDetails.BlockHeight, BlockIndex = transaction.SpendingDetails.BlockIndex, Amount = Money.Zero }; // If this 'send' transaction has made some external payments, i.e the funds were not sent to another address in the wallet. if (transaction.SpendingDetails.Payments != null) { sentItem.Payments = new List <PaymentDetailModel>(); foreach (PaymentDetails payment in transaction.SpendingDetails.Payments) { sentItem.Payments.Add(new PaymentDetailModel { DestinationAddress = payment.DestinationAddress, Amount = payment.Amount }); sentItem.Amount += payment.Amount; } } // Get the change address for this spending transaction. FlatHistory changeAddress = allchange.FirstOrDefault(a => a.Transaction.Id == spendingTransactionId); // Find all the spending details containing the spending transaction id and aggregate the sums. // This is our best shot at finding the total value of inputs for this transaction. var inputsAmount = new Money(spendingDetails.Where(t => t.Transaction.SpendingDetails.TransactionId == spendingTransactionId).Sum(t => t.Transaction.Amount)); // The fee is calculated as follows: funds in utxo - amount spent - amount sent as change. sentItem.Fee = inputsAmount - sentItem.Amount - (changeAddress == null ? 0 : changeAddress.Transaction.Amount); // Mined/staked coins add more coins to the total out. // That makes the fee negative. If that's the case ignore the fee. if (sentItem.Fee < 0) { sentItem.Fee = 0; } transactionItems.Add(sentItem); uniqueProcessedTxIds.Add(sentItem.Id); } // We don't show in history transactions that are outputs of staking transactions. if (transaction.IsCoinStake != null && transaction.IsCoinStake.Value && transaction.SpendingDetails == null) { continue; } // Create a record for a 'receive' transaction. if (transaction.IsCoinStake == null && !address.IsChangeAddress()) { // First check if we already have a similar transaction output, in which case we just sum up the amounts TransactionItemModel existingReceivedItem = FindSimilarReceivedTransactionOutput(transactionItems, transaction); if (existingReceivedItem == null) { // Add incoming fund transaction details. var receivedItem = new TransactionItemModel { Type = TransactionItemType.Received, ToAddress = address.Address, Amount = transaction.Amount, Id = transaction.Id, Timestamp = transaction.CreationTime, ConfirmedInBlock = transaction.BlockHeight, BlockIndex = transaction.BlockIndex }; transactionItems.Add(receivedItem); uniqueProcessedTxIds.Add(receivedItem.Id); } else { existingReceivedItem.Amount += transaction.Amount; } } } transactionItems = transactionItems.Distinct(new SentTransactionItemModelComparer()).Select(e => e).ToList(); // Sort and filter the history items. List <TransactionItemModel> itemsToInclude = transactionItems.OrderByDescending(t => t.Timestamp) .Where(x => String.IsNullOrEmpty(request.SearchQuery) || (x.Id.ToString() == request.SearchQuery || x.ToAddress == request.SearchQuery || x.Payments.Any(p => p.DestinationAddress == request.SearchQuery))) .Skip(request.Skip ?? 0) .Take(request.Take ?? transactionItems.Count) .ToList(); model.AccountsHistoryModel.Add(new AccountHistoryModel { TransactionsHistory = itemsToInclude, Name = accountHistory.Account.Name, CoinType = network.Consensus.CoinType, HdPath = accountHistory.Account.HdPath }); } return(model); }
public async Task <IActionResult> GetHistory([FromQuery] WalletHistoryRequest request, CancellationToken cancellationToken = default(CancellationToken)) { return(await this.Execute(request, cancellationToken, async (req, token) => this.Json(await this.walletService.GetHistory(req, token)))); }
public IActionResult GetHistory([FromQuery] WalletHistoryRequest request) { // checks the request is valid if (!this.ModelState.IsValid) { var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors))); } try { WalletHistoryModel model = new WalletHistoryModel { TransactionsHistory = new List <TransactionItemModel>() }; // get transactions contained in the wallet var addresses = this.walletManager.GetHistoryByCoinType(request.WalletName, this.coinType); foreach (var address in addresses.Where(a => !a.IsChangeAddress())) { foreach (var transaction in address.Transactions) { TransactionItemModel item = new TransactionItemModel(); if (transaction.Amount > Money.Zero) { item.Type = TransactionItemType.Received; item.ToAddress = address.Address; item.Amount = transaction.Amount; } else { item.Type = TransactionItemType.Send; item.Amount = Money.Zero; if (transaction.Payments != null) { item.Payments = new List <PaymentDetailModel>(); foreach (var payment in transaction.Payments) { item.Payments.Add(new PaymentDetailModel { DestinationAddress = payment.DestinationAddress, Amount = payment.Amount }); item.Amount += payment.Amount; } } var changeAddress = addresses.Single(a => a.IsChangeAddress() && a.Transactions.Any(t => t.Id == transaction.Id)); item.Fee = transaction.Amount.Abs() - item.Amount - changeAddress.Transactions.First(t => t.Id == transaction.Id).Amount; } item.Id = transaction.Id; item.Timestamp = transaction.CreationTime; item.ConfirmedInBlock = transaction.BlockHeight; model.TransactionsHistory.Add(item); } } model.TransactionsHistory = model.TransactionsHistory.OrderByDescending(t => t.Timestamp).ToList(); return(this.Json(model)); } catch (Exception e) { return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public Task <WalletHistory> GetWalletHistoryAsync(WalletHistoryRequest request, CancellationToken cancellationToken = default) { return(_client.PostAsync <WalletHistory>("wallet_history", request, cancellationToken)); }