public static TransactionEntity ToTransactionEntity(this ITransactionModel transactionModel) { return(new TransactionEntity { // Common Id = transactionModel.Id.ToGuid(), Version = transactionModel.Version, // Foreign AccountId = transactionModel.AccountId.ToGuid(), ProfileId = transactionModel.ProfileId, // Properties Amount = transactionModel.Amount, Info = transactionModel.Info, // Approvable Approved = transactionModel.Approved, Pending = transactionModel.Pending, Blocked = transactionModel.Blocked, // Concurrent SequentialNumber = transactionModel.SequentialNumber }); }
public async Task <AccountDto?> ProcessTransactionUpdatedEventAsync(ITransactionModel transactionModel) { if (!transactionModel.IsApproved()) { return(null); } var transactionEntity = transactionModel.ToTransactionEntity(); var mappedAccount = await _accountsService.GetAccountByIdAsync(transactionEntity.AccountId); if (mappedAccount != null) { // Optimistic Concurrency Control: check version if (!mappedAccount.CheckConcurrentController(transactionEntity)) { return(null); } mappedAccount.SetBalance(transactionEntity); mappedAccount.IncrementConcurrentController(); // Optimistic Concurrency Control: update incrementing the version var updatedAccount = await _accountsService.UpdateAccountAsync(mappedAccount); await _publishEndpoint.Publish(updatedAccount?.ToAccountEvent <AccountUpdatedEvent>()); await _publishEndpoint.Publish(updatedAccount?.ToAccountEvent <AccountCheckCommand>()); return(updatedAccount?.ToAccountModel <AccountDto>()); } return(null); }
private void HandleReversions() { foreach (KeyValuePair <string, List <ITransactionModel> > currencyTransactionPair in _transactions) { List <ITransactionModel> transactionsToRemove = new List <ITransactionModel>(); List <ITransactionModel> reversionTransactions = currencyTransactionPair.Value.Where(t => t.TransactionType == TransactionType.Reversion).ToList(); foreach (ITransactionModel reversionTransaction in reversionTransactions) { ITransactionModel revertedTransaction = currencyTransactionPair.Value.Where(t => t.CryptoCurrencyAmount == reversionTransaction.CryptoCurrencyAmount * -1 && t.TimeStamp < reversionTransaction.TimeStamp).OrderBy(t => Math.Abs((t.TimeStamp - reversionTransaction.TimeStamp).Ticks)).FirstOrDefault(); if (revertedTransaction != null) { reversionTransaction.CryptoCurrencyAmount = 0; reversionTransaction.NativeAmount = 0; revertedTransaction.CryptoCurrencyAmount = 0; revertedTransaction.NativeAmount = 0; transactionsToRemove.Add(reversionTransaction); transactionsToRemove.Add(revertedTransaction); } } foreach (ITransactionModel transactionToRemove in transactionsToRemove) { currencyTransactionPair.Value.Remove(transactionToRemove); } } }
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); }
public static TransactionEntity ToTransactionEntity(this ITransactionModel transactionModel) { return(new TransactionEntity { Id = transactionModel.Id.ToGuid(), Amount = transactionModel.Amount, AccountId = transactionModel.AccountId.ToGuid(), Approved = transactionModel.Approved, Pending = transactionModel.Pending, Version = transactionModel.Version, SequentialNumber = transactionModel.SequentialNumber }); }
public async Task <ITransactionModel> SetNextSequentialNumber(ITransactionModel transactionModel) { var allTransactions = await _transactionsService.GetManyByParameterAsync( entity => entity !.ProfileId == transactionModel.ProfileId && entity !.AccountId == transactionModel.AccountId.ToGuid() ); var lastTransactionNumber = allTransactions.Max(t => t?.SequentialNumber); transactionModel.SequentialNumber = lastTransactionNumber.GetValueOrDefault(0) + 1; return(transactionModel); }
public int CompareTo(ITransactionModel other) { int date = DateTime.Compare(TimeStamp, other.TimeStamp); if (date == 0) { if (TransactionType == TransactionType.Purchase) { return(-1); } return(1); } return(date); }
public static TransactionResult MakeDeposit(ITransactionModel transaction) { try { if (transaction.RecieverAcct == null) { return(TransactionResult.NoReciever); } transaction.RecieverAcct.Balance += ExchangeService.ConvertCurrency(transaction.TransactionAmt, transaction.Currency, transaction.RecieverAcct.Currency); } catch (Exception e) { throw (e); } return(TransactionResult.Success); }
public static BillingEntity ToBillingEntity(this ITransactionModel transactionModel) { return(new BillingEntity { Id = Guid.NewGuid(), ProfileId = transactionModel.ProfileId, AccountId = transactionModel.AccountId.ToGuid(), TransactionId = transactionModel.Id.ToGuid(), Amount = transactionModel.Amount, Approved = transactionModel.Approved, Pending = transactionModel.Pending, Created = DateTime.Now, Updated = DateTime.Now, Version = 0 }); }
public ProfileDto?UpdateTransactionOnProfile(ITransactionModel transactionModel) { if ( string.IsNullOrEmpty(transactionModel.ProfileId) || string.IsNullOrEmpty(transactionModel.AccountId) ) { return(null); } var updated = _profilesService.UpdateInArray( transactionModel.AccountId, transactionModel.ToTransactionSubEntity() ); if (updated != null || !string.IsNullOrEmpty(updated?.Id)) { return(updated.ToProfileDto()); } return(null); }
public async Task <TransactionDto?> ProcessTransactionCheckedEventAsync(ITransactionModel transactionModel) { var transactionEntity = await _transactionsService.GetTransactionByIdAsync(transactionModel.Id.ToGuid()); if (transactionEntity != null) { if (transactionModel.IsBlocked()) { transactionEntity.SetBlocked(); } else { if (transactionModel.IsApproved()) { transactionEntity.SetApproval(); } else { transactionEntity.SetDenial(); } } // Optimistic Concurrency Control: increment the version on update var updatedTransaction = await _transactionsService.UpdateTransactionAsync(transactionEntity); if (updatedTransaction != null) { await _publishEndpoint.Publish( updatedTransaction.ToTransactionModel <TransactionUpdatedEvent>() ); await _publishEndpoint.Publish(updatedTransaction.ToNotificationEvent()); return(updatedTransaction.ToTransactionModel <TransactionDto>()); } } return(null); }
public static TransactionResult MakeWithdrawal(ITransactionModel transaction) { try { if (transaction.SenderAcct == null) { return(TransactionResult.NoSender); } if (transaction.SenderAcct.Balance < ExchangeService.ConvertCurrency(transaction.TransactionAmt, transaction.Currency, transaction.SenderAcct.Currency)) { return(TransactionResult.InsufficientFunds); } transaction.SenderAcct.Balance -= ExchangeService.ConvertCurrency(transaction.TransactionAmt, transaction.Currency, transaction.SenderAcct.Currency); } catch (Exception e) { throw (e); } return(TransactionResult.Success); }
public async Task <ITransactionModel?> EvaluateTransactionAsync(ITransactionModel transactionCreatedEvent) { if ( string.IsNullOrEmpty(transactionCreatedEvent.ProfileId) || string.IsNullOrEmpty(transactionCreatedEvent.AccountId) ) { return(null); } var isTransactionAllowed = await _licenseManager.EvaluateNewEntityAsync(transactionCreatedEvent); if (isTransactionAllowed) { transactionCreatedEvent.SetApproval(); } else { transactionCreatedEvent.SetDenial(); } var processedEntity = await _billingsService.CreateBillingAsync( transactionCreatedEvent.ToBillingEntity() ); if (processedEntity != null) { var transactionProcessedEvent = processedEntity.ToTransactionModel <TransactionIsCheckedEvent>( transactionCreatedEvent ); await _publishEndpoint.Publish(transactionProcessedEvent); return(transactionProcessedEvent); } return(null); }
public static TModel ToTransactionModel <TModel>( this BillingEntity billingEntity, ITransactionModel transactionModel ) where TModel : class, ITransactionModel, new() { return(new TModel { Id = transactionModel.Id, Version = transactionModel.Version, Timestamp = transactionModel.Timestamp, AccountId = transactionModel.AccountId, ProfileId = transactionModel.ProfileId, Amount = transactionModel.Amount, Info = transactionModel.Info, Approved = billingEntity.Approved, Pending = billingEntity.Pending, SequentialNumber = transactionModel.SequentialNumber }); }
public static TransactionResult MakeTransfer(ITransactionModel transaction) { try { TransactionResult result = MakeWithdrawal(transaction); if (result != TransactionResult.Success) { return(result); } result = MakeDeposit(transaction); //desposit amount to reciever account, convert currency to currency of reciever account if (result != TransactionResult.Success) { return(result); } } catch (Exception e) { throw (e); } return(TransactionResult.Success); }
//private static async Task<List<ITransactionModel>> InitFromBinanceApi(string address) //{ // using(CallRateLimiter explorerBinanceLimiter = new CallRateLimiter("BinanceExplorerApi", 10, TimeSpan.FromSeconds(1))) // { // HttpResponseMessage transactionsAmount = await explorerBinanceLimiter.GetDataAsync($"https://explorer.binance.org/api/v1/txs?page=1&rows=1&address={address}"); // } // List<ITransactionModel> transactionModels = new List<ITransactionModel> { this }; // using (CallRateLimiter apiCallRateLimiter = new CallRateLimiter("BinanceApiCall", 10, TimeSpan.FromSeconds(1))) // { // HttpResponseMessage httpResponse = await apiCallRateLimiter.GetDataAsync($"https://dex.binance.org/api/v1/tx/{transactionId}?format=json"); // if (httpResponse.IsSuccessStatusCode) // { // BinanceChain.TransactionFromHash transactionFromHash = JsonConvert.DeserializeObject<BinanceChain.TransactionFromHash>(await httpResponse.Content.ReadAsStringAsync()); // if (transactionFromHash.Ok) // { // if (FULL_TAX.Contains(transactionFromHash.Tx.Value.Memo)) // { // IsFullyTaxed = true; // } // foreach (BinanceChain.TransactionInformationMessage transactionInformationMessage in transactionFromHash.Tx.Value.Msg) // { // List<BinanceChain.TransactionAddressAndCoins> transactionInformationMessageValues = transactionInformationMessage.Value.Outputs.Where(b => b.Address == _address).ToList(); // if (transactionInformationMessageValues.Count > 0) // { // for (int i = 1; i < transactionInformationMessageValues.Count; i++) // { // ITransactionModel blockChainTransactionModel = Clone(); // foreach (BinanceChain.TransactionCoin coin in transactionInformationMessageValues[i].Coins) // { // blockChainTransactionModel.NativeAmount += ValueForOneCryptoTokenInNative * coin.Amount; // blockChainTransactionModel.CryptoCurrency += coin.Denom + "|"; // } // blockChainTransactionModel.CryptoCurrency.Remove(blockChainTransactionModel.CryptoCurrency.Length - 1); // transactionModels.Add(blockChainTransactionModel); // } // BinanceChain.TransactionAddressAndCoins first = transactionInformationMessageValues[0]; // NativeAmount = 0; // foreach (BinanceChain.TransactionCoin coin in first.Coins) // { // CryptoCurrency = coin.Denom; // CryptoCurrencyAmount += coin.Amount; // NativeAmount += ValueForOneCryptoTokenInNative * coin.Amount; // } // } // } // } // } // else // { // Debug.Log("Binance api call failed with code: " + httpResponse.StatusCode + " and message " + await httpResponse.Content.ReadAsStringAsync()); // } // } // return transactionModels; //} private async Task <List <ITransactionModel> > InitFromEthereumApi() { List <ITransactionModel> transactionModels = new List <ITransactionModel> { this }; APIKeys keys; using (StreamReader streamReader = new StreamReader(API_KEYS_PATH)) { string apiKeys = await streamReader.ReadToEndAsync(); keys = JsonConvert.DeserializeObject <APIKeys>(apiKeys); } using (CallRateLimiter apiCallRateLimiter = new CallRateLimiter("EtherScan", 5, TimeSpan.FromSeconds(1))) { HttpResponseMessage etherTransactionsResponse = await apiCallRateLimiter.GetDataAsync($"https://api.etherscan.io/api?module=account&action=txlist&address={_address}&sort=asc&apikey={keys.EtherScanKey}"); HttpResponseMessage erc20TransactionsResponse = await apiCallRateLimiter.GetDataAsync($"https://api.etherscan.io/api?module=account&action=tokentx&address={_address}&sort=asc&apikey={keys.EtherScanKey}"); if (etherTransactionsResponse.IsSuccessStatusCode && erc20TransactionsResponse.IsSuccessStatusCode) { EthereumChain.EtherAddressTransactions etherAddressTransactions = JsonConvert.DeserializeObject <EthereumChain.EtherAddressTransactions>(await etherTransactionsResponse.Content.ReadAsStringAsync()); EthereumChain.Erc20AddressTransactions erc20AddressTransactions = JsonConvert.DeserializeObject <EthereumChain.Erc20AddressTransactions>(await erc20TransactionsResponse.Content.ReadAsStringAsync()); List <EthereumChain.IEtherScanTransaction> transactions = new List <EthereumChain.IEtherScanTransaction>(); transactions.AddRange(erc20AddressTransactions.Result); foreach (var ethTransaction in etherAddressTransactions.Result) { if (!transactions.Any(t => t.Hash == ethTransaction.Hash)) { transactions.Add(ethTransaction); } } if (transactions.Count > 0) { for (int i = 1; i < transactions.Count; i++) { ITransactionModel blockChainTransactionModel = Clone(); NativeAmount = transactions[i].Value * ValueForOneCryptoTokenInNative; CryptoCurrency = transactions[i].TokenSymbol; CryptoCurrencyAmount = transactions[i].Value; } EthereumChain.IEtherScanTransaction first = transactions[0]; NativeAmount = first.Value * ValueForOneCryptoTokenInNative; CryptoCurrency = first.TokenSymbol; CryptoCurrencyAmount = first.Value; } } else { Debug.Log("Etherscan api call finished with code: " + etherTransactionsResponse.StatusCode + " and message " + await etherTransactionsResponse.Content.ReadAsStringAsync()); Debug.Log("Etherscan api call finished with code: " + erc20TransactionsResponse.StatusCode + " and message " + await erc20TransactionsResponse.Content.ReadAsStringAsync()); } } return(transactionModels); }
/// <summary> /// Specify the transactional model to be used. /// </summary> /// <param name="model"></param> /// <remarks> /// Typically you wouldn't need to do this at all.</remarks> public static void TransactionModel(ITransactionModel model) { Birch.Transactions.TransactionModel.Current = model ?? new Threaded(); }
public bool Transferencia(ITransactionModel transaction, IAccount account) { throw new NotImplementedException(); }
public bool Saque(ITransactionModel transaction) { throw new NotImplementedException(); }
public void RunCalculations() { _gains.Clear(); _losses.Clear(); HandleReversions(); WriteOverview(); List <ITransactionModel> purchaseTransactions = new List <ITransactionModel>(); foreach (KeyValuePair <string, List <ITransactionModel> > currencyTransaction in _transactions) { foreach (ITransactionModel transaction in currencyTransaction.Value) { ITransactionModel transactionClone = transaction.Clone(); if (transactionClone.TransactionType == TransactionType.Purchase || transactionClone.TransactionType == TransactionType.Interest || transactionClone.TransactionType == TransactionType.Rebate) { purchaseTransactions.Add(transactionClone); } else if (transactionClone.TransactionType == TransactionType.Sale) { decimal cryptoCurrencyAmountFromTransactions = 0; for (int i = 0; i < purchaseTransactions.Count; i++) { cryptoCurrencyAmountFromTransactions += purchaseTransactions[i].CryptoCurrencyAmount; if (cryptoCurrencyAmountFromTransactions >= transactionClone.CryptoCurrencyAmount) { List <ITransactionModel> purchaseTransactionsNeededToCoverSale = purchaseTransactions.Take(i + 1).ToList(); CalculateSaleFromPurchases(purchaseTransactionsNeededToCoverSale, transactionClone); if (purchaseTransactions[i].CryptoCurrencyAmount > 0) { purchaseTransactions.RemoveRange(0, i); } else { purchaseTransactions.RemoveRange(0, i + 1); } break; } } } } purchaseTransactions.Clear(); } _gains.Sort((x, y) => x.CompareTo(y)); _losses.Sort((x, y) => x.CompareTo(y)); if (_gains.Count > 0) { _gains[0].TotalAmount = _gains[0].Amount; for (int i = 1; i < _gains.Count; i++) { _gains[i].TotalAmount = _gains[i].Amount + _gains[i - 1].TotalAmount; } } if (_losses.Count > 0) { _losses[0].TotalAmount = _losses[0].Amount; for (int i = 1; i < _losses.Count; i++) { _losses[i].TotalAmount = _losses[i].Amount + _losses[i - 1].TotalAmount; } } WriteTansactionGains(); WriteTranactionLosses(); }
public bool Deposito(ITransactionModel transaction) { throw new NotImplementedException(); }
private void CalculateSaleFromPurchases(List <ITransactionModel> purchaseTransactionsNeededToCoverSale, ITransactionModel saleTransaction) { decimal originalSaleValueForeachToken = saleTransaction.ValueForOneCryptoTokenInNative; foreach (ITransactionModel purchaseTransaction in purchaseTransactionsNeededToCoverSale) { decimal cryptoCurrencySoldAmount = decimal.Zero; if (saleTransaction.CryptoCurrencyAmount > purchaseTransaction.CryptoCurrencyAmount) { saleTransaction.CryptoCurrencyAmount -= purchaseTransaction.CryptoCurrencyAmount; cryptoCurrencySoldAmount = purchaseTransaction.CryptoCurrencyAmount; purchaseTransaction.CryptoCurrencyAmount = 0; } else { purchaseTransaction.CryptoCurrencyAmount -= saleTransaction.CryptoCurrencyAmount; cryptoCurrencySoldAmount = saleTransaction.CryptoCurrencyAmount; saleTransaction.CryptoCurrencyAmount = 0; } decimal transactionProfit = decimal.Zero; if (purchaseTransaction.IsFullyTaxed) { transactionProfit = originalSaleValueForeachToken * cryptoCurrencySoldAmount; } else { transactionProfit = (saleTransaction.ValueForOneCryptoTokenInNative - purchaseTransaction.ValueForOneCryptoTokenInNative) * cryptoCurrencySoldAmount; } if (transactionProfit < 0) { _losses.Add(new TaxableEvent(purchaseTransaction.TransactionId, saleTransaction.TransactionId, saleTransaction.CryptoCurrency, purchaseTransaction.TimeStamp, saleTransaction.TimeStamp, transactionProfit * -1, MainComponent.Instance.TargetCurrency, saleTransaction.WalletName, cryptoCurrencySoldAmount)); } else if (transactionProfit > 0) { _gains.Add(new TaxableEvent(purchaseTransaction.TransactionId, saleTransaction.TransactionId, saleTransaction.CryptoCurrency, purchaseTransaction.TimeStamp, saleTransaction.TimeStamp, transactionProfit, MainComponent.Instance.TargetCurrency, saleTransaction.WalletName, cryptoCurrencySoldAmount)); } } }
public double Saldo(ITransactionModel transaction) { throw new NotImplementedException(); }