public void Setup() { _calendar = new Mock <Calendar>(); _txHistory = new TxHistory(_calendar.Object); _console = new Mock <BankConsole>(); _txRecordPrinter = new Mock <IPrinter <TxRecord> >(); _statementPrinter = new StatementPrinter(_console.Object, _txRecordPrinter.Object, _calendar.Object); }
public async Task InsertOrReplaceAsync(TxDirectionType direction, TxHistory history) { var table = GetTable(direction); // history entry var entity = history.ToEntity(); await table.InsertOrReplaceAsync(entity); }
public void SetUp() { _calendar = new Mock <Calendar>(); _console = new Mock <BankConsole>(); _txHistory = new TxHistory(_calendar.Object); _txRecordPrinter = new TxRecordPrinter(_console.Object, new CultureInfo("en-GB")); _statementPrinter = new StatementPrinter(_console.Object, _txRecordPrinter, _calendar.Object); _account = new Account(_txHistory, _statementPrinter); }
public void not_equal_tx_history_of_same_withdrawal_amount_on_different_date() { _calendar.SetupSequence(c => c.GetDate()) .Returns(new DateTime(2000, 1, 1)) .Returns(new DateTime(2000, 1, 2)); var otherTxHistory = new TxHistory(_calendar.Object); var txHistory = new TxHistory(_calendar.Object); txHistory.HandleWithdrawal(10); otherTxHistory.HandleWithdrawal(10); Assert.That(txHistory, Is.Not.EqualTo(otherTxHistory)); }
private async Task <List <TxHistory> > GetDepositBaseHistory(TxDirectionType direction, string address, int take, string afterPagingToken) { string afterKey = null; if (afterPagingToken != null) { afterKey = TxHistory.GetKey(afterPagingToken, 999); } var memo = _balanceService.GetPublicAddressExtension(address); var result = await _txHistoryRepository.GetAllAfterHashAsync(direction, memo, take, afterKey); return(result); }
public static TxHistory ToDomain(this TxHistoryEntity entity) { var domain = new TxHistory { FromAddress = entity.FromAddress, ToAddress = entity.ToAddress, AssetId = entity.AssetId, Amount = entity.Amount, Hash = entity.Hash, CreatedAt = entity.CreatedAt, PaymentType = entity.PaymentType, Memo = entity.Memo }; return(domain); }
public static TxHistoryEntity ToEntity(this TxHistory domain) { var entity = new TxHistoryEntity { PartitionKey = TxHistory.GetKey(domain.PagingToken, domain.OperationIndex), RowKey = domain.Memo ?? string.Empty, FromAddress = domain.FromAddress, ToAddress = domain.ToAddress, AssetId = domain.AssetId, Amount = domain.Amount, Hash = domain.Hash, CreatedAt = domain.CreatedAt, PaymentType = domain.PaymentType }; return(entity); }
public static TxHistory ToDomain(this TxHistoryEntity entity) { var domain = new TxHistory { OperationId = entity.OperationId, FromAddress = entity.FromAddress, ToAddress = entity.ToAddress, AssetId = entity.AssetId, Amount = entity.Amount, Hash = entity.Hash, PaymentId = entity.PaymentId, CreatedAt = entity.CreatedAt, PaymentType = entity.PaymentType, Memo = entity.Memo, LastModified = entity.Timestamp }; return(domain); }
public static TxHistoryEntity ToEntity(this TxHistory domain, string partitionKey) { var entity = new TxHistoryEntity { PartitionKey = partitionKey, RowKey = UInt64.Parse(domain.PaymentId).ToString("D20"), OperationId = domain.OperationId, FromAddress = domain.FromAddress, ToAddress = domain.ToAddress, AssetId = domain.AssetId, Amount = domain.Amount, Hash = domain.Hash, PaymentId = domain.PaymentId, CreatedAt = domain.CreatedAt, PaymentType = domain.PaymentType, Memo = domain.Memo }; return(entity); }
private async Task <int> QueryAndProcessTransactions(string address, TransactionContext context, Func <TxDirectionType, TxHistory, Task <bool> > process) { var transactions = await _horizonService.GetTransactions(address, OrderDirection.ASC, context.Cursor); var count = 0; context.Cursor = null; foreach (var transaction in transactions) { try { context.Cursor = transaction.PagingToken; count++; var xdr = Convert.FromBase64String(transaction.EnvelopeXdr); var reader = new XdrDataInputStream(xdr); var txEnvelope = TransactionEnvelope.Decode(reader); var tx = txEnvelope.V1; var operations = txEnvelope?.V1?.Tx?.Operations ?? txEnvelope.V0.Tx.Operations; for (short i = 0; i < operations.Length; i++) { var operation = operations[i]; var operationType = operation.Body.Discriminant.InnerValue; DateTime.TryParse(transaction.CreatedAt, out var createdAt); var history = new TxHistory { FromAddress = transaction.SourceAccount, AssetId = _blockchainAssetsService.GetNativeAsset().Id, Hash = transaction.Hash, OperationIndex = i, PagingToken = transaction.PagingToken, CreatedAt = createdAt, Memo = _horizonService.GetMemo(transaction) }; // ReSharper disable once SwitchStatementMissingSomeCases switch (operationType) { case OperationType.OperationTypeEnum.CREATE_ACCOUNT: { var op = operation.Body.CreateAccountOp; var keyPair = KeyPair.FromXdrPublicKey(op.Destination.InnerValue); history.ToAddress = keyPair.Address; history.Amount = op.StartingBalance.InnerValue; history.PaymentType = PaymentType.CreateAccount; break; } case OperationType.OperationTypeEnum.PAYMENT: { var op = operation.Body.PaymentOp; if (op.Asset.Discriminant.InnerValue == AssetType.AssetTypeEnum.ASSET_TYPE_NATIVE) { var keyPair = KeyPair.FromPublicKey(op.Destination.Ed25519.InnerValue); history.ToAddress = keyPair.Address; history.Amount = op.Amount.InnerValue; history.PaymentType = PaymentType.Payment; } break; } case OperationType.OperationTypeEnum.ACCOUNT_MERGE: { var op = operation.Body; var keyPair = KeyPair.FromPublicKey(op.Destination.Ed25519.InnerValue); history.ToAddress = keyPair.Address; history.Amount = _horizonService.GetAccountMergeAmount(transaction.ResultXdr, i); history.PaymentType = PaymentType.AccountMerge; break; } case OperationType.OperationTypeEnum.PATH_PAYMENT_STRICT_RECEIVE: { var op = operation.Body.PathPaymentStrictReceiveOp; if (op.DestAsset.Discriminant.InnerValue == AssetType.AssetTypeEnum.ASSET_TYPE_NATIVE) { var keyPair = KeyPair.FromPublicKey(op.Destination.Ed25519.InnerValue); history.ToAddress = keyPair.Address; history.Amount = op.DestAmount.InnerValue; history.PaymentType = PaymentType.PathPayment; } break; } default: continue; } if (!ForbiddenCharacterAzureStorageUtils.IsValidRowKey(history.Memo)) { await _log.WriteErrorAsync(nameof(TransactionHistoryService), nameof(QueryAndProcessTransactions), history.Memo, new Exception("Possible cashin skipped. It has forbiddden characters in memo.")); continue; } var cancel = false; if (address.Equals(history.ToAddress, StringComparison.OrdinalIgnoreCase)) { cancel = await process(TxDirectionType.Incoming, history); } if (address.Equals(history.FromAddress, StringComparison.OrdinalIgnoreCase)) { cancel = await process(TxDirectionType.Outgoing, history); } if (cancel) { return(count); } } } catch (Exception ex) { throw new BusinessException($"Failed to process transaction. hash={transaction?.Hash}", ex); } } return(count); }
private async Task <bool> SaveTransactionHistory(TxDirectionType direction, TxHistory history) { await _txHistoryRepository.InsertOrReplaceAsync(direction, history); return(false); }
private async Task <int> QueryAndProcessPayments(string address, PaymentContext context) { int count = 0; var payments = await _horizonService.GetPayments(address, StellarSdkConstants.OrderAsc, context.Cursor); if (payments == null) { await _log.WriteWarningAsync(nameof(TransactionHistoryService), nameof(QueryAndProcessPayments), $"Address not found: {address}"); context.Cursor = null; return(count); } context.Cursor = null; foreach (var payment in payments.Embedded.Records) { try { context.Cursor = payment.PagingToken; count++; // create_account, payment or account_merge if (payment.TypeI == (int)OperationType.OperationTypeEnum.CREATE_ACCOUNT || payment.TypeI == (int)OperationType.OperationTypeEnum.PAYMENT && Core.Domain.Asset.Stellar.TypeName.Equals(payment.AssetType, StringComparison.OrdinalIgnoreCase) || payment.TypeI == (int)OperationType.OperationTypeEnum.ACCOUNT_MERGE) { if (context.Transaction == null || !context.Transaction.Hash.Equals(payment.TransactionHash, StringComparison.OrdinalIgnoreCase)) { var tx = await _horizonService.GetTransactionDetails(payment.TransactionHash); context.Transaction = tx ?? throw new BusinessException($"Transaction not found. hash={payment.TransactionHash}"); context.AccountMerge = 0; } var history = new TxHistory { AssetId = Core.Domain.Asset.Stellar.Id, Hash = payment.TransactionHash, PaymentId = payment.Id, CreatedAt = payment.CreatedAt, Memo = GetMemo(context.Transaction) }; // create_account if (payment.TypeI == (int)OperationType.OperationTypeEnum.CREATE_ACCOUNT) { history.FromAddress = payment.Funder; history.ToAddress = payment.Account; history.PaymentType = PaymentType.CreateAccount; decimal amount = Decimal.Parse(payment.StartingBalance); history.Amount = Convert.ToInt64(amount * One.Value); } // payment else if (payment.TypeI == (int)OperationType.OperationTypeEnum.PAYMENT) { history.FromAddress = payment.From; history.ToAddress = payment.To; history.PaymentType = PaymentType.Payment; decimal amount = Decimal.Parse(payment.Amount); history.Amount = Convert.ToInt64(amount * One.Value); } // account_merge else if (payment.TypeI == (int)OperationType.OperationTypeEnum.ACCOUNT_MERGE) { history.FromAddress = payment.Account; history.ToAddress = payment.Into; history.PaymentType = PaymentType.AccountMerge; var resultXdrBase64 = context.Transaction.ResultXdr; history.Amount = _horizonService.GetAccountMergeAmount(resultXdrBase64, context.AccountMerge); context.AccountMerge++; } else { throw new BusinessException($"Invalid payment type. type=${payment.TypeI}"); } history.OperationId = await _txBroadcastRepository.GetOperationId(payment.TransactionHash); if (address.Equals(history.ToAddress, StringComparison.OrdinalIgnoreCase)) { await _txHistoryRepository.InsertOrReplaceAsync(context.TableId, TxDirectionType.Incoming, history); context.Sequence++; } if (address.Equals(history.FromAddress, StringComparison.OrdinalIgnoreCase)) { await _txHistoryRepository.InsertOrReplaceAsync(context.TableId, TxDirectionType.Outgoing, history); context.Sequence++; } } } catch (Exception ex) { throw new BusinessException($"Failed to process payment of transaction. payment={payment?.Id}, hash={context?.Transaction?.Hash}", ex); } } return(count); }
public void setup() { _calendar = new Mock <Calendar>(); _otherTxHistory = new TxHistory(_calendar.Object); _txHistory = new TxHistory(_calendar.Object); }