public async Task <AmountAndPrice> GetConvertedAmountAndPriceAsync(string fromAssetId, string toAssetId, double fromAmount) { if (string.IsNullOrEmpty(fromAssetId)) { throw new ArgumentNullException(nameof(fromAssetId)); } if (string.IsNullOrEmpty(toAssetId)) { throw new ArgumentNullException(nameof(toAssetId)); } if (fromAssetId == toAssetId) { return(new AmountAndPrice(fromAmount, 1, 1)); } var toAsset = await _assetsDict.GetItemAsync(toAssetId); var assetPair = (await _assetPairsDict.Values()).PairWithAssets(fromAssetId, toAssetId); var feedData = await _bestPriceRepository.GetAsync(assetPair.Id); var price = (assetPair.BaseAssetId == fromAssetId ? feedData.Ask : 1 / feedData.Ask).TruncateDecimalPlaces(assetPair.Accuracy); var invertedPrice = (assetPair.BaseAssetId == fromAssetId ? 1 / feedData.Ask : feedData.Ask).TruncateDecimalPlaces(assetPair.InvertedAccuracy); return(new AmountAndPrice((price * fromAmount).TruncateDecimalPlaces(toAsset.Accuracy), price, invertedPrice)); }
private async Task <IAssetSetting> GetAssetSetting(string asset) { var setting = await _assetSettings.GetItemAsync(asset) ?? await _assetSettings.GetItemAsync(LykkeConstants.DefaultAssetSetting); if (setting == null) { throw new Exception($"Setting is not found for {asset}"); } return(setting); }
public async Task <double> GetLkkSoldAmount() { var lkk = await _assetsDictionary.GetItemAsync(LykkeConstants.LykkeAssetId); var walletsToTrack = await _lkkSourceWalletsRepository.GetRecordsAsync(); double result = 0; var balancesTasks = walletsToTrack.Select( x => _srvBlockchainReader.GetBalanceForAdress(x.Address, lkk) .ContinueWith(task => x.StartBalance - task.Result.Balance)); var balances = await Task.WhenAll(balancesTasks); result += balances.Sum(); result += (await _appGlobalSettingsRepositry.GetAsync()).IcoLkkSold; var maxValue = (await _tempDataRepository.RetrieveData <IcoCoinsBoughtData>())?.MaxValue ?? 0; if (result > maxValue) { await _tempDataRepository.InsertOrReplaceDataAsync(new IcoCoinsBoughtData { MaxValue = result }); maxValue = result; } return(maxValue); }
private async Task <IAsset> GetAsset(string assetId) { var asset = await _assetRepository.GetItemAsync(assetId); if (asset == null) { throw new BackendException("Provided asset is missing in database", ErrorCode.AssetNotFound); } return(asset); }
public async Task <IActionResult> Transfer([FromBody] TransferRequest model) { if (model.Amount <= 0) { throw new BackendException("Amount can't be less or equal to zero", ErrorCode.BadInputParameter); } await ValidateAddress(model.SourceAddress); await ValidateAddress(model.DestinationAddress); var asset = await _assetRepository.GetItemAsync(model.Asset); if (asset == null) { throw new BackendException("Provided asset is missing in database", ErrorCode.AssetNotFound); } var transactionId = await _builder.AddTransactionId(model.TransactionId, $"Transfer: {model.ToJson()}"); await _transactionQueueWriter.AddCommand(transactionId, TransactionCommandType.Transfer, new TransferCommand { Amount = model.Amount, SourceAddress = model.SourceAddress, Asset = model.Asset, DestinationAddress = model.DestinationAddress }.ToJson()); return(Ok(new TransactionIdResponse { TransactionId = transactionId })); }
public async Task <Asset> GetBaseAssetForClient(string clientId, bool isIosDevice, string partnerId) { var baseAsset = (await _clientAccountSettingsClient.GetBaseAssetAsync(clientId)).BaseAssetId; if (string.IsNullOrEmpty(baseAsset)) { var assetsForClient = (await GetAssetsForClient(clientId, isIosDevice, partnerId)).Where(x => x.IsBase); baseAsset = assetsForClient.GetFirstAssetId(); } return(await _cachedAssetsDictionary.GetItemAsync(baseAsset)); }
private async void AttachSenderTransferToRefLink(IReferralLink refLink, string transferId) { var transfer = await _offchainTransferRepository.GetTransfer(transferId); refLink.Amount = (double)transfer.Amount; refLink.Asset = (await _assets.GetItemAsync(transfer.AssetId)).Id; refLink.SenderOffchainTransferId = transferId; refLink.State = ReferralLinkState.SentToLykkeSharedWallet.ToString(); await _referralLinksService.UpdateAsync(refLink); await LogInfo(new { RefLink = refLink, TransferId = transferId }, ControllerContext, $"Transfer complete for ref link id {refLink.Id} with amount {transfer.Amount} and asset Id {refLink.Asset}. Offchain transfer Id {transferId} attached with ref link. "); }
public async Task ProcessMessage(BroadcastCommitmentMessage msg, QueueTriggeringContext context) { var asset = await _assetCache.GetItemAsync(msg.Asset); if (asset == null) { msg.Error = "Asset is not found"; context.MoveMessageToPoison(msg.ToJson()); return; } await _offchainService.BroadcastCommitment(msg.Multisig, asset, msg.UseFees); }
public async Task <double> GetCapitalization(string market) { double rate = 1; if (market != LykkeConstants.LykkeAssetId) { var assetPairs = await _assetPairsDict.Values(); var pair = assetPairs.PairWithAssets(LykkeConstants.LykkeAssetId, market); if (pair == null) { return(0); } rate = await _srvRatesHelper.GetRate(market, pair); } CacheRecord record; var asset = await _assetsDict.GetItemAsync(market); var cacheKey = GetMarketCapitalizationCacheKey(); if (!_memCache.TryGetValue(cacheKey, out record)) { double amount = 0; await _walletsRepository.GetWalletsByChunkAsync(pairs => { var c = pairs.Select(x => x.Value?.FirstOrDefault(y => y.AssetId == LykkeConstants.LykkeAssetId)) .Sum(x => x?.Balance ?? 0); amount += c; return(Task.CompletedTask); }); record = record ?? new CacheRecord(); record.AssetId = LykkeConstants.LykkeAssetId; record.Dt = DateTime.UtcNow; record.Amount = amount; var cacheEntryOptions = new MemoryCacheEntryOptions() .SetAbsoluteExpiration(_cacheExpTime); _memCache.Set(cacheKey, record, cacheEntryOptions); } return((record.Amount * rate).TruncateDecimalPlaces(asset.Accuracy)); }
private Task GenerateColorOutputs(string assetId) { return(Retry.Try(async() => { var asset = await _assetRepostory.GetItemAsync(assetId); var setting = await GetAssetSetting(assetId); var hotWallet = OpenAssetsHelper.ParseAddress(setting.HotWallet); var assetIdObj = new BitcoinAssetId(asset.BlockChainAssetId).AssetId; var outputs = await _bitcoinOutputsService.GetColoredUnspentOutputs(setting.HotWallet, assetIdObj, 0, false); var balance = outputs.Aggregate(new AssetMoney(assetIdObj, 0), (accum, coin) => accum + coin.Amount); var outputSize = new AssetMoney(assetIdObj, setting.OutputSize, asset.MultiplierPower); var changeBalance = new AssetMoney(assetIdObj); if (setting.ChangeWallet != setting.HotWallet && !string.IsNullOrEmpty(setting.ChangeWallet)) { var changeOutputs = await _bitcoinOutputsService.GetColoredUnspentOutputs(setting.ChangeWallet, assetIdObj, 0, false); changeBalance = changeOutputs.Aggregate(new AssetMoney(assetIdObj, 0), (accum, coin) => accum + coin.Amount); } if ((balance + changeBalance).ToDecimal(asset.MultiplierPower) < setting.MinBalance) { await SendBalanceNotifications(assetId, setting.HotWallet, setting.MinBalance); } var existingCoinsCount = outputs.Count(o => o.Amount <= outputSize && o.Amount.Quantity > outputSize.Quantity / 2); if (existingCoinsCount > setting.MinOutputsCount) { return; } var generateCnt = setting.MaxOutputsCount - existingCoinsCount; var coins = outputs.Where(o => o.Amount > outputSize * 2).ToList(); balance = coins.Aggregate(new AssetMoney(assetIdObj, 0), (accum, coin) => accum + coin.Amount); generateCnt = Math.Min(generateCnt, (int)(balance.Quantity / outputSize.Quantity)); if (generateCnt == 0) { return; } await GenerateOutputs(generateCnt, coins, hotWallet, outputSize, asset, setting); }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _logger)); }
public async Task <IAsset> GetBaseAssetForClient(string clientId, bool isIosDevice) { var assetsForClient = (await GetAssetsForClient(clientId, isIosDevice)).Where(x => x.IsBase); var exchangeSettings = await _exchangeSettingsRepository.GetOrDefaultAsync(clientId); var baseAsset = exchangeSettings.BaseAsset(isIosDevice); if (string.IsNullOrEmpty(baseAsset)) { baseAsset = assetsForClient.GetFirstAssetId(); } return(await _assetsDict.GetItemAsync(baseAsset)); }
public async Task <CreateTransactionResponse> GetTransferFromSegwitWallet(BitcoinAddress source, Guid transactionId) { var assetSetting = await _assetSettingCache.GetItemAsync("BTC"); var asset = await _assetRepository.GetItemAsync("BTC"); var hotWallet = OpenAssetsHelper.ParseAddress(!string.IsNullOrEmpty(assetSetting.ChangeWallet) ? assetSetting.ChangeWallet : assetSetting.HotWallet); var context = _transactionBuildContextFactory.Create(_connectionParams.Network); var lowVolume = new Money((decimal)asset.LowVolumeAmount, MoneyUnit.BTC); return(await context.Build(async() => { var outputs = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(source.ToString())).OfType <Coin>() .Where(o => o.Amount >= lowVolume).ToList(); if (!outputs.Any()) { throw new BackendException($"Address {source} has not unspent outputs", ErrorCode.NoCoinsFound); } var totalAmount = new Money(outputs.Sum(o => o.Amount)); var builder = new TransactionBuilder(); builder.DustPrevention = false; builder.AddCoins(outputs); builder.Send(hotWallet, totalAmount); builder.SubtractFees(); builder.SendEstimatedFees(await _feeProvider.GetFeeRate()); builder.SetChange(hotWallet); var tx = builder.BuildTransaction(true); _transactionBuildHelper.AggregateOutputs(tx); if (tx.Outputs[0].Value <= tx.Outputs[0].GetDustThreshold(builder.StandardTransactionPolicy.MinRelayTxFee)) { throw new BackendException($"Address {source} balance is too low", ErrorCode.NoCoinsFound); } await _spentOutputService.SaveSpentOutputs(transactionId, tx); await SaveNewOutputs(transactionId, tx, context); return new CreateTransactionResponse(tx.ToHex(), transactionId); })); }
public async Task <IActionResult> Cashout([FromBody] CashoutRequest model) { model.DestinationAddress = model.DestinationAddress.Trim('\n', ' ', '\t'); if (model.Amount <= 0) { throw new BackendException("Amount can't be less or equal to zero", ErrorCode.BadInputParameter); } await ValidateAddress(model.DestinationAddress, false); var asset = await _assetRepository.GetItemAsync(model.Asset); if (asset == null) { throw new BackendException("Provided asset is missing in database", ErrorCode.AssetNotFound); } var transactionId = await _builder.AddTransactionId(model.TransactionId, $"Cashout: {model.ToJson()}"); if (OpenAssetsHelper.IsBitcoin(model.Asset)) { await _cashoutRequestRepository.CreateCashoutRequest(transactionId, model.Amount, model.DestinationAddress); } else { var assetSetting = await _assetSettingCache.GetItemAsync(asset.Id); var hotWallet = !string.IsNullOrEmpty(assetSetting.ChangeWallet) ? assetSetting.ChangeWallet : assetSetting.HotWallet; await _transactionQueueWriter.AddCommand(transactionId, TransactionCommandType.Transfer, new TransferCommand { Amount = model.Amount, SourceAddress = hotWallet, Asset = model.Asset, DestinationAddress = model.DestinationAddress }.ToJson()); } return(Ok(new TransactionIdResponse { TransactionId = transactionId })); }
public async Task <bool> IsKycNeeded(string clientId, string assetId) { if (string.IsNullOrEmpty(assetId)) { throw new ArgumentException(nameof(assetId)); } var asset = await _assets.GetItemAsync(assetId); if (asset == null) { throw new ArgumentException(nameof(assetId)); } var userKycStatus = await _kycRepository.GetKycStatusAsync(clientId); return(asset.KycNeeded && userKycStatus != KycStatus.Ok); }
public async Task <bool> IsKycNeeded(string clientId, string assetId) { if (string.IsNullOrEmpty(assetId)) { throw new ArgumentException(nameof(assetId)); } var asset = await _assets.GetItemAsync(assetId); if (asset == null) { throw new ArgumentException(nameof(assetId)); } var userKycStatus = await _kycStatusService.GetKycStatusAsync(clientId); return(asset.KycNeeded && !userKycStatus.IsKycOkOrReviewDone()); }
public async Task <CommandHandlingResult> Handle(StartCashoutCommand command, IEventPublisher eventPublisher) { var address = command.Address.Trim('\n', ' ', '\t'); try { var transactionId = await _builder.AddTransactionId(command.Id, $"Cashout: {command.ToJson()}"); if (OpenAssetsHelper.IsBitcoin(command.AssetId)) { await _cashoutRequestRepository.CreateCashoutRequest(transactionId, command.Amount, address); } else { var assetSetting = await _assetSettingCache.GetItemAsync(command.AssetId); var hotWallet = !string.IsNullOrEmpty(assetSetting.ChangeWallet) ? assetSetting.ChangeWallet : assetSetting.HotWallet; await _transactionQueueWriter.AddCommand(transactionId, TransactionCommandType.Transfer, new TransferCommand { Amount = command.Amount, SourceAddress = hotWallet, Asset = command.AssetId, DestinationAddress = command.Address }.ToJson()); } } catch (BackendException ex) when(ex.Code == ErrorCode.DuplicateTransactionId) { _logger.WriteWarning(nameof(CashinCommandHandler), nameof(Handle), $"Duplicated id: {command.Id}"); } return(CommandHandlingResult.Ok()); }
public async Task <IActionResult> Get(string assetPairId = null) { assetPairId = string.IsNullOrEmpty(assetPairId) ? null : assetPairId.ToUpper(); AssetPair pair = null; if (!string.IsNullOrEmpty(assetPairId)) { pair = await _assetPairs.GetItemAsync(assetPairId); } if (!string.IsNullOrEmpty(assetPairId) && pair == null) { return(NotFound($"Asset pair {assetPairId} not found")); } IEnumerable <IOrderBook> result = string.IsNullOrEmpty(assetPairId) ? await _orderBooksService.GetAllAsync() : await _orderBooksService.GetAsync(assetPairId); return(Ok(result.ToApiModel())); }
public Task <CreateMultiCashoutTransactionResult> GetMultipleCashoutTransaction(List <ICashoutRequest> cashoutRequests, Guid transactionId) { return(Retry.Try(async() => { var context = _transactionBuildContextFactory.Create(_connectionParams.Network); var assetSetting = await _assetSettingCache.GetItemAsync("BTC"); var hotWallet = OpenAssetsHelper.ParseAddress(assetSetting.HotWallet); var changeWallet = OpenAssetsHelper.ParseAddress(string.IsNullOrWhiteSpace(assetSetting.ChangeWallet) ? assetSetting.HotWallet : assetSetting.ChangeWallet); return await context.Build(async() => { var builder = new TransactionBuilder(); var hotWalletOutputs = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(hotWallet.ToString())).OfType <Coin>().ToList(); var hotWalletBalance = new Money(hotWalletOutputs.Select(o => o.Amount).DefaultIfEmpty().Sum(o => o?.Satoshi ?? 0)); var maxFeeForTransaction = Money.FromUnit(0.099M, MoneyUnit.BTC); var selectedCoins = new List <Coin>(); var maxInputsCount = maxFeeForTransaction.Satoshi / (await _feeProvider.GetFeeRate()).GetFee(Constants.InputSize).Satoshi; var tryCount = 100; do { if (selectedCoins.Count > maxInputsCount && cashoutRequests.Count > 1) { cashoutRequests = cashoutRequests.Take(cashoutRequests.Count - 1).ToList(); selectedCoins.Clear(); } else if (selectedCoins.Count > 0) { break; } var totalAmount = Money.FromUnit(cashoutRequests.Select(o => o.Amount).Sum(), MoneyUnit.BTC); if (hotWalletBalance < totalAmount + maxFeeForTransaction) { var changeBalance = Money.Zero; List <Coin> changeWalletOutputs = new List <Coin>(); if (hotWallet != changeWallet) { changeWalletOutputs = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(changeWallet.ToString())) .OfType <Coin>().ToList(); changeBalance = new Money(changeWalletOutputs.Select(o => o.Amount).DefaultIfEmpty().Sum(o => o?.Satoshi ?? 0)); } if (changeBalance + hotWalletBalance >= totalAmount + maxFeeForTransaction) { selectedCoins.AddRange(hotWalletOutputs); selectedCoins.AddRange(OpenAssetsHelper .CoinSelect(changeWalletOutputs, totalAmount + maxFeeForTransaction - hotWalletBalance).OfType <Coin>()); } else { selectedCoins.AddRange(hotWalletOutputs); selectedCoins.AddRange(changeWalletOutputs); int cashoutsUsedCount = 0; var cashoutsAmount = await _transactionBuildHelper.CalcFee(selectedCoins.Count, cashoutRequests.Count + 1); foreach (var cashoutRequest in cashoutRequests) { cashoutsAmount += Money.FromUnit(cashoutRequest.Amount, MoneyUnit.BTC); if (cashoutsAmount > hotWalletBalance + changeBalance) { break; } cashoutsUsedCount++; } if (cashoutsUsedCount == 0) { throw new BackendException("Not enough bitcoin available", ErrorCode.NotEnoughBitcoinAvailable); } cashoutRequests = cashoutRequests.Take(cashoutsUsedCount).ToList(); } if (changeWallet != hotWallet) { if (assetSetting.Asset == Constants.DefaultAssetSetting) { assetSetting = await CreateAssetSetting("BTC", assetSetting); } if (assetSetting.Asset != Constants.DefaultAssetSetting) { await _assetSettingRepository.UpdateHotWallet(assetSetting.Asset, assetSetting.ChangeWallet); } } } else { selectedCoins.AddRange(OpenAssetsHelper.CoinSelect(hotWalletOutputs, totalAmount + maxFeeForTransaction).OfType <Coin>()); } } while (tryCount-- > 0); var selectedCoinsAmount = new Money(selectedCoins.Sum(o => o.Amount)); var sendAmount = new Money(cashoutRequests.Sum(o => o.Amount), MoneyUnit.BTC); builder.AddCoins(selectedCoins); foreach (var cashout in cashoutRequests) { var amount = Money.FromUnit(cashout.Amount, MoneyUnit.BTC); builder.Send(OpenAssetsHelper.ParseAddress(cashout.DestinationAddress), amount); } builder.Send(changeWallet, selectedCoinsAmount - sendAmount); builder.SubtractFees(); builder.SendEstimatedFees(await _feeProvider.GetFeeRate()); builder.SetChange(changeWallet); var tx = builder.BuildTransaction(true); _transactionBuildHelper.AggregateOutputs(tx); await _broadcastedOutputRepository.InsertOutputs( tx.Outputs.AsCoins().Where(o => o.ScriptPubKey == changeWallet.ScriptPubKey).Select(o => new BroadcastedOutput(o, transactionId, _connectionParams.Network)).ToList()); await _spentOutputService.SaveSpentOutputs(transactionId, tx); return new CreateMultiCashoutTransactionResult { Transaction = tx, UsedRequests = cashoutRequests }; }); }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log)); }
public Task <AssetPair> GetAssetPairAsync(string assetPairId) { return(_assetPairsCache.GetItemAsync(assetPairId)); }
public Task <Asset> GetAssetAsync(string assetId) { return(_assetsCache.GetItemAsync(assetId)); }
public async Task <IAssetDefinition> GetAssetAsync(string assetId) { return(await _assetDefinitionCachedDictionary.GetItemAsync(assetId)); }