Exemple #1
0
 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);
 }
Exemple #2
0
        public async Task InsertOrReplaceAsync(TxDirectionType direction, TxHistory history)
        {
            var table = GetTable(direction);

            // history entry
            var entity = history.ToEntity();
            await table.InsertOrReplaceAsync(entity);
        }
Exemple #3
0
 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);
 }
Exemple #4
0
        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));
        }
Exemple #5
0
        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);
        }
Exemple #6
0
        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);
        }
Exemple #7
0
        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);
        }
Exemple #8
0
        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);
        }
Exemple #9
0
        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);
        }
Exemple #10
0
        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);
        }
Exemple #11
0
        private async Task <bool> SaveTransactionHistory(TxDirectionType direction, TxHistory history)
        {
            await _txHistoryRepository.InsertOrReplaceAsync(direction, history);

            return(false);
        }
Exemple #12
0
        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);
        }
Exemple #13
0
 public void setup()
 {
     _calendar       = new Mock <Calendar>();
     _otherTxHistory = new TxHistory(_calendar.Object);
     _txHistory      = new TxHistory(_calendar.Object);
 }