public override async Task <PricesResponse> GetPrices(PricesRequest request, ServerCallContext context) { var entities = _pricesReader.Get(PriceEntity.GetPk()); List <PriceUpdate> result; if (entities.Any()) { result = _mapper.Map <List <PriceUpdate> >(entities); } else { var marketData = await _marketDataClient.GetMarketDataAsync(new Empty()); result = _mapper.Map <List <PriceUpdate> >(marketData.Items.ToList()); } if (request.AssetPairIds.Any()) { result = result.Where(x => request.AssetPairIds.Contains(x.AssetPairId, StringComparer.InvariantCultureIgnoreCase)) .ToList(); } var response = new PricesResponse(); response.Payload.AddRange(result); return(response); }
async Task <IWatchList> IWatchListsClient.GetCustomWatchListAsync(string clientId, string watchListId) { try { var data = _readerWatchListCustomNoSql.Get(WatchListCustomNoSql.GeneratePartitionKey(clientId), WatchListCustomNoSql.GenerateRowKey(watchListId)); if (data != null) { return(data); } } catch (Exception ex) { _log.Error(ex, $"Cannot read from MyNoSQL. Table: ${WatchListCustomNoSql.TableNameCustomWatchList}, PK: {WatchListCustomNoSql.GeneratePartitionKey(clientId)}", ex); } try { var result = await HttpClient.WatchListGetCustomAsync(watchListId, clientId); var data = FromWatchListResponse(result); return(data); } catch (Exception ex) { _log.Error(ex, $"Cannot read from API. Method: WatchListGetCustomAsync, clientId: {clientId}, watchListId: {watchListId}"); throw; } }
public override Task <GetApprovalResponse> GetApprovalResults(GetApprovalResultsRequest request, ServerCallContext context) { var vaultId = context.GetVaultId(); var list = _dataReader.Get() .Where(e => e.VaultId == vaultId) .Where(e => !e.IsOpen) .ToList(); var resp = new GetApprovalResponse(); foreach (var entity in list) { var item = new GetApprovalResponse.Types.ApprovalResponse { ValidatorId = entity.ValidatorId, TransferSigningRequestId = entity.TransferSigningRequestId, ResolutionDocumentEncBase64 = entity.ResolutionDocumentEncBase64, Signature = entity.ResolutionSignature }; resp.Payload.Add(item); _logger.LogInformation("GetApprovalResults response. TransferSigningRequestId={TransferSigningRequestId}; VaultId={VaultId}; ValidatorId={ValidatorId}", item.TransferSigningRequestId, vaultId, item.ValidatorId); } return(Task.FromResult(resp)); }
public async Task <OperationUpdateList> GetOperationsHistory(GetOperationsRequest request) { var data = _reader .Get(OperationHistoryNoSqlEntity.GeneratePartitionKey(request.WalletId, request.AssetId)) .Where(e => e.Entity.TimeStamp < request.LastDate) .Take(request.BatchSize) .Select(t => t.Entity) .OrderByDescending(e => e.TimeStamp) .ToList(); var cacheSize = _reader .Get(OperationHistoryNoSqlEntity.GeneratePartitionKey(request.WalletId, request.AssetId)).Count; if (data.Count == request.BatchSize || (cacheSize < _maxCachedEntities && cacheSize > 0)) { return new OperationUpdateList() { OperationUpdates = data } } ; return(await _operationHistoryService.GetBalanceUpdatesAsync(request)); } }
public long ConvertAmountToBitgo(string coin, double amount) { var coinSettings = _bitgoCoins.Get(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(coin)); if (coinSettings == null) { throw new System.Exception($"Do not found settings for bitgo coin {coin} in nosql table {BitgoCoinEntity.TableName}"); } return(coinSettings.AmountToAbsoluteValue(amount)); }
public (string, string) AssetToBitgoCoinAndWallet(string brokerId, string assetSymbol) { var map = _assetMap.Get(BitgoAssetMapEntity.GeneratePartitionKey(brokerId), BitgoAssetMapEntity.GenerateRowKey(assetSymbol)); if (map == null) { return(string.Empty, string.Empty); } return(map.BitgoCoin, map.BitgoWalletId); }
public IBitGoApi GetByUser(string brokerId, string userId, string coinId, string newApiKey) { var bitGoUser = _bitgoUserReader.Get( BitGoUserNoSqlEntity.GeneratePartitionKey(brokerId), BitGoUserNoSqlEntity.GenerateRowKey(BitGoUserNoSqlEntity.TechSignerId, coinId)) ?? _bitgoUserReader.Get( BitGoUserNoSqlEntity.GeneratePartitionKey(brokerId), BitGoUserNoSqlEntity.GenerateRowKey(BitGoUserNoSqlEntity.TechSignerId, BitGoUserNoSqlEntity.DefaultCoin)); var apiKeyEnc = bitGoUser?.User?.ApiKey; if (string.IsNullOrEmpty(apiKeyEnc) && string.IsNullOrEmpty(newApiKey)) { _logger.LogError("Tech account is not configured, id = {techSignerName}", BitGoUserNoSqlEntity.TechSignerId); return(null); } lock (_clients) { if (!string.IsNullOrEmpty(apiKeyEnc) && _clients.TryGetValue(apiKeyEnc, out var api)) { return(api); } } var coin = _bitgoCointReader.Get(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(coinId)); if (coin == null) { _logger.LogError("Cannot fond bitgo coin id = {symbol}", coinId); return(null); } var apiKey = string.IsNullOrEmpty(apiKeyEnc) ? newApiKey : _encryptionService.Decrypt(apiKeyEnc); var client = new BitGoClient( apiKey, Program.Settings.BitgoExpressUrlMainNet, apiKey, Program.Settings.BitgoExpressUrlTestNet); lock (_clients) { _clients[apiKey] = coin.IsMainNet ? client.MainNet : client.TestNet; return(_clients[apiKey]); } }
public override async Task <OrdersResponse> GetActiveOrders(OrdersRequest request, ServerCallContext context) { var result = await _validationService.ValidateOrdersRequestAsync(request.AssetPairId, request.Offset, request.Take); if (result != null) { return(new OrdersResponse { Error = new Error { Code = (int)result.Code, Message = result.Message } }); } var statuses = new List <string> { OrderStatus.Placed.ToString(), OrderStatus.PartiallyMatched.ToString() }; var orders = _ordersReader.Get(context.GetHttpContext().User.GetWalletId(), request.Offset, request.Take, x => (string.IsNullOrEmpty(request.AssetPairId) || x.AssetPairId == request.AssetPairId) && statuses.Contains(x.Status)); var res = new OrdersResponse(); res.Payload.AddRange(_mapper.Map <List <Order> >(orders)); return(res); }
public async Task <GetDepositAddressResponse> GetDepositAddressAsync(GetDepositAddressRequest request) { var entity = _depositAddressReader.Get(DepositAddressEntity.GeneratePartitionKey(request.WalletId), DepositAddressEntity.GenerateRowKey(request.AssetSymbol, request.Blockchain)); if (entity != null) { return(new GetDepositAddressResponse() { Address = entity.Address, Error = GetDepositAddressResponse.ErrorCode.Ok }); } return(await _service.GetDepositAddressAsync(request)); }
public async Task <IActionResult> GetTickers([FromQuery] string[] assetPairIds) { var entities = _tickersReader.Get(TickerEntity.GetPk()); List <TickerModel> result; if (entities.Any()) { result = _mapper.Map <List <TickerModel> >(entities); } else { var marketData = await _marketDataClient.GetMarketDataAsync(new Empty()); result = _mapper.Map <List <TickerModel> >(marketData.Items.ToList()); } if (assetPairIds.Any()) { result = result.Where(x => assetPairIds.Contains(x.AssetPairId, StringComparer.InvariantCultureIgnoreCase)) .ToList(); } return(Ok(ResponseModel <IReadOnlyCollection <TickerModel> > .Ok(result))); }
public override Task <ActiveValidatorsResponse> GetActiveValidators(ActiveValidatorsRequest request, ServerCallContext context) { var tenantId = request.TenantId; var listAll = _validatorLinkReader.Get() .Where(v => v.TenantId == tenantId) .Where(v => v.IsAccepted) .Where(v => !v.IsBlocked) .Select(v => new { v.ValidatorId, v.PublicKeyPem }); var response = new ActiveValidatorsResponse(); var hashset = new HashSet <string>(); foreach (var item in listAll) { if (!hashset.Contains(item.ValidatorId)) { response.ActiveValidatorsRequest.Add(new ActiveValidatorsResponse.Types.ActiveValidator() { ValidatorId = item.ValidatorId, ValidatorPublicKeyPem = item.PublicKeyPem }); hashset.Add(item.ValidatorId); } } _logger.LogInformation("Return validator list TenantId={TenantId}; Count={Count}", tenantId, response.ActiveValidatorsRequest.Count); return(Task.FromResult(response)); }
private async Task <BitgoCoinEntity> GetCoin(string bitgoCoin) { var coin = _bitgoCoinReader.Get(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(bitgoCoin)); if (coin == null) { await Task.Delay(5000); coin = _bitgoCoinReader.Get(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(bitgoCoin)); } if (coin == null) { throw new Exception($"BitGo coin '{bitgoCoin}' does not exist."); } return(coin); }
IAssetPair IMarketProfileClient.Get(string id) { try { var data = _readerAssetPairNoSql.Get( AssetPairPriceNoSql.GeneratePartitionKey(), AssetPairPriceNoSql.GenerateRowKey(id)); return(data?.AssetPair); } catch (Exception ex) { Console.WriteLine($"Cannot read from MyNoSQL. Table: ${AssetPairPriceNoSql.TableName}, " + $"PK: {AssetPairPriceNoSql.GeneratePartitionKey()}, " + $"RK: {AssetPairPriceNoSql.GenerateRowKey(id)}, Ex: {ex}"); throw; } }
public async Task <IReadOnlyList <AssetPair> > GetAssetPairsByTenant(string tenantId) { var pairs = _assetPairsReader.Get(AssetPairsEntity.GetPartitionKey(tenantId), AssetPairsEntity.GetRowKey()); if (pairs?.AssetPairs == null) { return(new List <AssetPair>()); } return(pairs.AssetPairs); }
public async Task <IReadOnlyList <Asset> > GetAssetsByTenant(string tenantId) { var assets = _assetsReader.Get(AssetsEntity.GetPartitionKey(tenantId), AssetsEntity.GetRowKey()); if (assets?.Assets == null) { return(new List <Asset>()); } return(assets.Assets); }
public async Task <ClientProfileEntity> GetClientProfile(string tenantId, long clientId) { var profile = _clientProfileDataReader.Get(ClientProfileEntity.GeneratePartitionKey(tenantId), ClientProfileEntity.GenerateRowKey(clientId)); if (profile == null) { profile = await CreateClientProfile(tenantId, clientId); } return(profile); }
public async Task RemoveValidatorApiKeyAsync([FromBody] ValidatorRequest request) { var(auth, tenantId, adminId, adminEmail) = Authorize(); if (!auth) { return; } var entity = _validationReader.Get(ValidatorLinkEntity.GeneratePartitionKey(tenantId), ValidatorLinkEntity.GenerateRowKey(request.ApiKeyId)); if (entity == null) { return; } await _validationWriter.DeleteAsync(entity.PartitionKey, entity.RowKey); _logger.LogInformation("Removed validator Api Key: {ApiKeyId}; AdminId: {AdminId}; Name: {Name}; Device: {Device}; TenantId: {TenantId}", request.ApiKeyId, adminId, entity.Name, entity.DeviceInfo, tenantId); }
public async Task <GetBlockchainAddressInfoResponse> GetBlockchainAddressDetailsAsync( GetAddressInfoRequest request) { var entity = _blockchainDepositAddressReader.Get( BlockchainDepositAddressEntity.GeneratePartitionKey(request.AssetSymbol, request.Blockchain, request.Address), BlockchainDepositAddressEntity.GenerateRowKey()); if (entity != null) { return new GetBlockchainAddressInfoResponse { Address = new DepositAddress(entity.Address) } } ; return(await _service.GetBlockchainAddressDetailsAsync(request)); } }
public override async Task <PingResponse> GetPing(PingRequest request, ServerCallContext context) { var validatorId = context.GetHttpContext().User.GetClaimOrDefault(Claims.KeyKeeperId); var publicKey = context.GetHttpContext().User.GetClaimOrDefault(Claims.PublicKeyPem); if (string.IsNullOrEmpty(publicKey)) { return(new PingResponse() { Error = new ValidatorApiError() { Code = ValidatorApiError.Types.ErrorCodes.InternalServerError, Message = "Incorrect Bearer Token." } }); } var message = _pingMessageReader.Get(PingMessageMyNoSqlEntity.GeneratePartitionKey(validatorId), PingMessageMyNoSqlEntity.GenerateRowKey()); var response = new PingResponse(); if (message == null) { response.MessageEnc = string.Empty; response.SignatureMessage = string.Empty; } else { var asynccrypto = new AsymmetricEncryptionService(); var messageEnc = asynccrypto.Encrypt(Encoding.UTF8.GetBytes(message.Message), publicKey); response.MessageEnc = Convert.ToBase64String(messageEnc); response.SignatureMessage = "not-implemented-please-skip"; await _pingMessageWriter.DeleteAsync(message.PartitionKey, message.RowKey); } _logger.LogInformation("GetPing response. ValidatorId='{ValidatorId}'; HasMessage={HasMessage}", validatorId, !string.IsNullOrEmpty(response.MessageEnc)); return(response); }
public async Task <IReadOnlyCollection <Balance> > GetBalancesAsync(string walletId) { var result = new List <Balance>(); var balanceEntities = _balancesReader.Get(walletId); if (balanceEntities.Any()) { result.AddRange(_mapper.Map <IReadOnlyCollection <Balance> >(balanceEntities)); } else { var balances = await _balanceClient.GetBalanceAsync(walletId); result.AddRange(balances); } await SetBalancesAccuracyAsync(result); return(result); }
async Task <List <string> > IAvailableAssetClient.GetAssetIds(string clientId, bool isIosDevice) { try { var data = _readerAssetConditionNoSql.Get( AssetConditionNoSql.GeneratePartitionKey(clientId), AssetConditionNoSql.GenerateRowKey()); if (data?.AssetConditions != null) { return(data.AssetConditions.Where(o => o.AvailableToClient == true).Select(o => o.Asset).ToList()); } } catch (Exception ex) { _log.Error(ex, $"Cannot read from MyNoSQL. Table: ${AssetConditionNoSql.TableName}, PK: {AssetConditionNoSql.GeneratePartitionKey(clientId)}, RK: {AssetConditionNoSql.GenerateRowKey()}"); throw; } var result = await HttpClient.ClientGetAssetIdsAsync(clientId, isIosDevice); return(result.ToList()); }
public async Task <IActionResult> GetActiveOrders( [FromQuery] string assetPairId = null, [FromQuery] int?offset = 0, [FromQuery] int?take = 100 ) { var result = await _validationService.ValidateOrdersRequestAsync(assetPairId, offset, take); if (result != null) { throw HftApiException.Create(result.Code, result.Message).AddField(result.FieldName); } var statuses = new List <string> { OrderStatus.Placed.ToString(), OrderStatus.PartiallyMatched.ToString() }; var orders = _ordersReader.Get(User.GetWalletId(), offset ?? 0, take ?? 100, x => (string.IsNullOrEmpty(assetPairId) || x.AssetPairId == assetPairId) && statuses.Contains(x.Status)); var ordersModel = _mapper.Map <IReadOnlyCollection <OrderModel> >(orders); return(Ok(ResponseModel <IReadOnlyCollection <OrderModel> > .Ok(ordersModel))); }
public async Task <SendTransactionResponse> SignAndSendTransactionAsync(SendTransactionRequest request) { _logger.LogInformation("Transfer Request: {jsonText}", JsonConvert.SerializeObject(request)); try { var client = _bitGoClientService.GetByUser(request.BrokerId, BitGoUserNoSqlEntity.TechSignerId, request.BitgoCoin); if (client == null) { throw new Exception($"Tech account is not configured, id = {BitGoUserNoSqlEntity.TechSignerId}, coin = {request.BitgoCoin}"); } var wallet = _myNoSqlServerWalletDataReader.Get( BitGoWalletNoSqlEntity.GeneratePartitionKey(request.BrokerId), BitGoWalletNoSqlEntity.GenerateRowKey(request.BitgoWalletId)); if (string.IsNullOrEmpty(wallet?.Wallet?.ApiKey)) { _logger.LogError("Cannot find pass phase for wallet {bitgoWalletIdText}", request.BitgoWalletId); throw new Exception($"Cannot find pass phase for wallet {request.BitgoWalletId}"); } var walletPass = _encryptionService.Decrypt(wallet.Wallet.ApiKey); var result = await client.SendCoinsAsync(request.BitgoCoin, request.BitgoWalletId, walletPass, request.SequenceId, request.Amount, request.Address); if (!result.Success) { switch (result.Error.Code) { case "DuplicateSequenceIdError": { var transaction = await client.GetTransferBySequenceIdAsync(request.BitgoCoin, request.BitgoWalletId, request.SequenceId); if (!transaction.Success || transaction.Data == null) { _logger.LogError("Transfer is Duplicate, but cannot found transaction: {jsonText}", JsonConvert.SerializeObject(transaction.Error)); return(new SendTransactionResponse() { Error = result.Error }); } _logger.LogInformation("Transfer is Duplicate, Result: {jsonText}", JsonConvert.SerializeObject(transaction.Data)); return(new SendTransactionResponse() { DuplicateTransaction = transaction.Data }); } case "needs unlock": await _sessionPublisher.PublishAsync(new SignalBitGoSessionStateUpdate() { State = BitGoSessionState.Locked }); return(new SendTransactionResponse() { Error = { Code = "needs unlock", ErrorMessage = "Session is locked" } }); } } if (!result.Success) { _logger.LogError("Transfer Result: {jsonText}", JsonConvert.SerializeObject(result.Error)); return(new SendTransactionResponse() { Error = result.Error }); } await AddVolumeToApiKey(request.BrokerId, _encryptionService.GetSha256Hash(wallet.Wallet.ApiKey), request.BitgoCoin, _assetMapper.ConvertAmountFromBitgo(request.BitgoCoin, long.Parse(request.Amount))); _logger.LogInformation("Transfer Result: {jsonText}", JsonConvert.SerializeObject(result.Data)); return(new SendTransactionResponse() { Result = result.Data }); } catch (Exception ex) { _logger.LogError(ex, "Transfer Request ERROR: {jsonText}. Error: {message}", JsonConvert.SerializeObject(request), ex.Message); throw; } }
public SessionEntity GetSession(string sessionId) { return(_sessionsReader.Get(SessionEntity.GetPk(), sessionId.ToSha256())); }
public override async Task <AcceptResponse> Accept(AcceptRequest request, ServerCallContext context) { var validatorId = request.ValidatorId; var validatorLinkEntity = _validatorLinkReader.Get().FirstOrDefault(v => v.InvitationToken == request.InviteId); if (validatorLinkEntity == null) { _logger.LogInformation("Cannot accept invitation: 'Invitation token is not correct'. InviteId='{InviteId}'; ValidatorId='{ValidatorId}'", request.InviteId, request.ValidatorId); return(new AcceptResponse() { Error = new ValidatorApiError() { Code = ValidatorApiError.Types.ErrorCodes.WrongInvitation, Message = "Invitation token is not correct" } }); } if (validatorLinkEntity.IsAccepted) { _logger.LogInformation("Cannot accept invitation: 'Invitation token already accepted'. InviteId='{InviteId}'; ValidatorId='{ValidatorId}'", request.InviteId, request.ValidatorId); return(new AcceptResponse() { Error = new ValidatorApiError() { Code = ValidatorApiError.Types.ErrorCodes.WrongInvitation, Message = "Invitation token already accepted" } }); } if (string.IsNullOrEmpty(request.PublicKeyPem)) { _logger.LogInformation("Cannot accept invitation: 'PublicKeyPem cannot be empty'. InviteId='{InviteId}'; ValidatorId='{ValidatorId}'", request.InviteId, request.ValidatorId); return(new AcceptResponse() { Error = new ValidatorApiError() { Code = ValidatorApiError.Types.ErrorCodes.WrongInvitation, Message = "PublicKeyPem cannot be empty" } }); } var token = GenerateJwtToken(validatorId, request.PublicKeyPem, validatorLinkEntity.ApiKeyId, validatorLinkEntity.TenantId); var resp = new AcceptResponse { ApiKey = token, Name = validatorLinkEntity.Name, Position = validatorLinkEntity.Position, Description = validatorLinkEntity.Description }; validatorLinkEntity.ValidatorId = request.ValidatorId; validatorLinkEntity.PublicKeyPem = request.PublicKeyPem; validatorLinkEntity.IsAccepted = true; validatorLinkEntity.DeviceInfo = request.DeviceInfo; validatorLinkEntity.PushNotificationFcmToken = request.PushNotificationFCMToken; await _validatorLinkWriter.InsertOrReplaceAsync(validatorLinkEntity); _logger.LogInformation("Invitation accepted. InviteId='{InviteId}'; ValidatorId='{ValidatorId}'; PushNotificationFcmToken='{PushNotificationFcmToken}'", request.InviteId, request.ValidatorId, request.PushNotificationFCMToken); return(resp); }
public async Task HandledDepositAsync(SignalBitGoTransfer transferId) { transferId.AddToActivityAsJsonTag("bitgo signal"); _logger.LogInformation("Request to handle transfer from BitGo: {transferJson}", JsonConvert.SerializeObject(transferId)); var(brokerId, assetSymbol) = _assetMapper.BitgoCoinToAsset(transferId.Coin, transferId.WalletId); if (string.IsNullOrEmpty(brokerId) || string.IsNullOrEmpty(assetSymbol)) { _logger.LogWarning("Cannot handle BitGo deposit, asset do not found {transferJson}", JsonConvert.SerializeObject(transferId)); return; } var coin = _bitgoCoinReader.Get(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(transferId.Coin)); var transferResp = await _bitgoClient.Get(coin.IsMainNet) .GetTransferAsync(transferId.Coin, transferId.WalletId, transferId.TransferId); var transfer = transferResp.Data; if (transfer == null) { _logger.LogWarning("Cannot handle BitGo deposit, transfer do not found {transferJson}", JsonConvert.SerializeObject(transferId)); Activity.Current?.SetStatus(Status.Error); return; } transfer.AddToActivityAsJsonTag("bitgo-transfer"); _logger.LogInformation("Transfer from BitGo: {transferJson}", JsonConvert.SerializeObject(transfer)); var requirement = _assetMapper.GetRequiredConfirmations(transfer.Coin); if (transfer.Confirmations < requirement) { _logger.LogError( $"Transaction do not has enough conformations. Transaction has: {transfer.Confirmations}, requirement: {requirement}"); Activity.Current?.SetStatus(Status.Error); throw new Exception( $"Transaction do not has enough conformations. Transaction has: {transfer.Confirmations}, requirement: {requirement}"); } if (!_assetMapper.IsWalletEnabled(transfer.Coin, transfer.WalletId)) { _logger.LogError( "Transfer {transferIdString} from BitGo is skipped, Wallet do not include in enabled wallet list", transfer.TransferId); Activity.Current?.SetStatus(Status.Error); return; } foreach (var entryGroup in transfer.Entries .Where(e => e.Value > 0 && !string.IsNullOrEmpty(e.Label) && e.WalletId == transferId.WalletId && (e.Token == null || e.Token == transferId.Coin)) .GroupBy(e => e.Label)) { var label = entryGroup.Key; var wallet = _walletMapper.BitgoLabelToWallet(label); if (wallet == null) { _logger.LogWarning("Cannot found wallet for transfer entry with label={label} address={address}", label, entryGroup.First().Address); continue; } wallet.WalletId.AddToActivityAsTag("walletId"); wallet.ClientId.AddToActivityAsTag("clientId"); var bitgoAmount = entryGroup.Sum(e => e.Value); var meAmount = _assetMapper.ConvertAmountFromBitgo(transferId.Coin, bitgoAmount); var accuracy = _assetsDictionary.GetAssetById(new AssetIdentity() { Symbol = assetSymbol, BrokerId = wallet.BrokerId }).Accuracy; var roundedAmount = Math.Round(meAmount, accuracy, MidpointRounding.ToNegativeInfinity); try { await using var ctx = DatabaseContext.Create(_dbContextOptionsBuilder); await ctx.InsertAsync(new DepositEntity { BrokerId = wallet.BrokerId, WalletId = wallet.WalletId, ClientId = wallet.ClientId, TransactionId = $"{transfer.TransferId}:{wallet.WalletId}", Amount = (decimal)roundedAmount, AssetSymbol = assetSymbol, Comment = $"Bitgo transfer [{transferId.Coin}:{transferId.WalletId}] entry label='{label}', count entry={entryGroup.Count()}", Integration = "BitGo", Txid = transfer.TxId, Status = DepositStatus.New, EventDate = DateTime.UtcNow, UpdateDate = DateTime.UtcNow, FeeAmount = 0, FeeAssetSymbol = assetSymbol, CardLast4 = string.Empty }); } catch (Exception e) { Console.WriteLine(e); throw; } } _logger.LogInformation("Deposit request from BitGo {transferIdString} is handled", transfer.TransferId); }
public OrderBookEntity OrderBook(string tenantId, string assetPairId) { var book = _orderBookDataReader.Get(OrderBookEntity.GeneratePartitionKey(tenantId), OrderBookEntity.GenerateRowKey(assetPairId)); return(book); }
public void Start() { _pricesReader.SubscribeToChanges(prices => { var tasks = new List <Task>(); foreach (var price in prices) { tasks.Add(_priceStream.WriteToStreamAsync(_mapper.Map <PriceUpdate>(price), price.AssetPairId)); } Task.WhenAll(tasks).GetAwaiter().GetResult(); }); _candlesReader.SubscribeToChanges(candles => { var tasks = new List <Task>(); foreach (var candle in candles) { var key = $"{candle.AssetPairId}_{candle.PriceType}_{candle.TimeInterval}"; tasks.Add(_candlesStream.WriteToStreamAsync(_mapper.Map <CandleUpdate>(candle), key)); } Task.WhenAll(tasks).GetAwaiter().GetResult(); }); _tickersReader.SubscribeToChanges(tickers => { var tasks = new List <Task>(); foreach (var ticker in tickers) { var priceEntity = _pricesReader.Get(PriceEntity.GetPk(), ticker.AssetPairId); var priceUpdate = new PriceUpdate { AssetPairId = ticker.AssetPairId, VolumeBase24H = ticker.VolumeBase.ToString(CultureInfo.InvariantCulture), VolumeQuote24H = ticker.VolumeQuote.ToString(CultureInfo.InvariantCulture), PriceChange24H = ticker.PriceChange.ToString(CultureInfo.InvariantCulture), Timestamp = Timestamp.FromDateTime(ticker.UpdatedDt.ToUniversalTime()) }; if (priceEntity != null) { priceUpdate.Ask = priceEntity.Ask.ToString(CultureInfo.InvariantCulture); priceUpdate.Bid = priceEntity.Bid.ToString(CultureInfo.InvariantCulture); } tasks.Add(_priceStream.WriteToStreamAsync(priceUpdate, priceUpdate.AssetPairId)); } Task.WhenAll(tasks).GetAwaiter().GetResult(); }); _orderbooksReader.SubscribeToChanges(orderbooks => { var tasks = new List <Task>(); foreach (var orderbook in orderbooks) { var item = _mapper.Map <Orderbook>(orderbook); item.Asks.AddRange(_mapper.Map <List <Orderbook.Types.PriceVolume> >(orderbook.Asks)); item.Bids.AddRange(_mapper.Map <List <Orderbook.Types.PriceVolume> >(orderbook.Bids)); tasks.Add(_orderbookStream.WriteToStreamAsync(item, orderbook.AssetPairId)); } Task.WhenAll(tasks).GetAwaiter().GetResult(); }); _sessionsReader.SubscribeToChanges(sessions => { }); Console.WriteLine("Stream services started."); }
public async Task SendPushNotifications(ApprovalRequestMyNoSqlEntity approvalRequest) { var traceLog = string.Empty; try { if (!_isActive) { return; } var validators = _validatorLinkReader.Get() .Where(v => v.TenantId == approvalRequest.TenantId) .Where(v => v.ValidatorId == approvalRequest.ValidatorId) .Where(v => v.IsAccepted) .Where(v => !v.IsBlocked) .Where(v => !string.IsNullOrEmpty(v.DeviceInfo)) .Where(v => !string.IsNullOrEmpty(v.PushNotificationFcmToken)); var hashset = new HashSet <string>(); var tokens = new List <string>(); foreach (var validator in validators) { if (!hashset.Contains(validator.DeviceInfo)) { tokens.Add(validator.PushNotificationFcmToken); hashset.Add(validator.DeviceInfo); } } if (!tokens.Any()) { _logger.LogInformation( "Push notification for TransferSigningRequestId={TransferSigningRequestId} is sent to {ValidatorId}. SuccessCount: {SuccessCount}. FailureCount: {FailureCount}.", approvalRequest.TransferSigningRequestId, approvalRequest.ValidatorId, 0, 0); return; } var message = new MulticastMessage() { Notification = new Notification() { Title = "New Approval Request", Body = "You receive a new approval request. Please check the transfer details in the application." }, Tokens = tokens }; traceLog = JsonConvert.SerializeObject(message); var response = await FirebaseMessaging.DefaultInstance.SendMulticastAsync(message); _logger.LogInformation( "Push notification for TransferSigningRequestId={TransferSigningRequestId} is sent to {ValidatorId}. SuccessCount: {SuccessCount}. FailureCount: {FailureCount}.", approvalRequest.TransferSigningRequestId, approvalRequest.ValidatorId, response.SuccessCount, response.FailureCount); if (response.FailureCount > 0) { var tokensList = JsonConvert.SerializeObject(tokens); foreach (var result in response.Responses.Where(r => r.IsSuccess == false)) { _logger.LogWarning( "Fail push notification. TransferSigningRequestId: {TransferSigningRequestId}; ValidatorId: {ValidatorId}; MessageId: {MessageId}; MessagingErrorCode: {MessagingErrorCode}; Message: {Message}; Tokens: {TokensList}", approvalRequest.TransferSigningRequestId, approvalRequest.ValidatorId, result.MessageId, result.Exception.MessagingErrorCode, result.Exception.Message, tokensList); } } } catch (Exception ex) { Console.WriteLine(traceLog); _logger.LogError(ex, "Cannot send push notification to validator. TransferSigningRequestId={TransferSigningRequestId}; ValidatorId={ValidatorId}", approvalRequest.TransferSigningRequestId, approvalRequest.ValidatorId); } }
public IReadOnlyList <PriceEntity> GetPrices(string tenantId) { var prices = _priceDataReader.Get(PriceEntity.GeneratePartitionKey(tenantId)); return(prices); }