public async Task <IActionResult> SetDefaultAssets([FromBody] UpdateMerchantWalletDefaultAssetsModel request) { if (!request.Network.HasValue || request.Network == BlockchainType.None) { return(BadRequest( ErrorResponse.Create( "Invalid network value, possible values are: Bitcoin, Ethereum, EthereumIata"))); } var assetsToValidate = new List <string>(); if (request.IncomingPaymentDefaults != null) { assetsToValidate.AddRange(request.IncomingPaymentDefaults); } if (request.OutgoingPaymentDefaults != null) { assetsToValidate.AddRange(request.OutgoingPaymentDefaults); } try { foreach (string assetToValidateId in assetsToValidate) { string lykkeAssetId = await _lykkeAssetsResolver.GetLykkeId(assetToValidateId); if (await _assetsLocalCache.GetAssetByIdAsync(lykkeAssetId) == null) { throw new AssetUnknownException(lykkeAssetId); } } await _merchantWalletService.SetDefaultAssetsAsync( request.MerchantId, request.Network.Value, request.WalletAddress, request.IncomingPaymentDefaults, request.OutgoingPaymentDefaults); return(NoContent()); } catch (AssetUnknownException e) { _log.ErrorWithDetails(e, new { e.Asset }); return(NotFound(ErrorResponse.Create($"Asset not found [{e.Asset}]"))); } catch (MerchantWalletNotFoundException e) { _log.ErrorWithDetails(e, new { e.MerchantId, e.Network, e.WalletAddress }); return(NotFound(ErrorResponse.Create(e.Message))); } }
public async Task <AssetPairSetting> GetAsync(string baseAssetId, string quotingAssetId) { Asset baseAsset = await _assetsLocalCache.GetAssetByIdAsync(baseAssetId); Asset quotingAsset = await _assetsLocalCache.GetAssetByIdAsync(quotingAssetId); return(_assetPairLocalStorageSettings.SingleOrDefault(x => x.BaseAssetId == baseAsset.DisplayId && x.QuotingAssetId == quotingAsset.DisplayId)); }
public async Task <IActionResult> SetAssetGeneralSettings([FromBody] UpdateAssetGeneralSettingsRequest request) { try { string lykkeAssetId = await _lykkeAssetsResolver.GetLykkeId(request.AssetDisplayId); Asset asset = await _assetsLocalCache.GetAssetByIdAsync(lykkeAssetId); if (asset == null) { return(NotFound(ErrorResponse.Create($"Asset {request.AssetDisplayId} not found"))); } await _assetSettingsService.SetGeneralAsync(Mapper.Map <AssetGeneralSettings>(request)); return(NoContent()); } catch (InvalidRowKeyValueException e) { _log.ErrorWithDetails(e, new { e.Variable, e.Value }); return(NotFound(ErrorResponse.Create("Asset not found"))); } catch (AssetUnknownException e) { _log.ErrorWithDetails(e, new { e.Asset }); return(NotFound(ErrorResponse.Create($"Asset {e.Asset} can't be resolved"))); } }
public async Task <IActionResult> SetGeneralAssetsSettings([FromBody] UpdateAssetAvailabilityRequest request) { try { string lykkeAssetId = await _lykkeAssetsResolver.GetLykkeId(request.AssetId); Asset asset = await _assetsLocalCache.GetAssetByIdAsync(lykkeAssetId); if (asset == null) { return(NotFound(ErrorResponse.Create($"Asset {request.AssetId} not found"))); } await _assetsAvailabilityService.SetGeneralAsync(request.AssetId, request.AvailabilityType, request.Value); return(NoContent()); } catch (AssetUnknownException assetEx) { await _log.WriteErrorAsync(nameof(AssetsController), nameof(SetGeneralAssetsSettings), new { assetEx.Asset }.ToJson(), assetEx); return(NotFound(ErrorResponse.Create($"Asset {assetEx.Asset} can't be resolved"))); } catch (Exception ex) { await _log.WriteErrorAsync(nameof(AssetsController), nameof(SetGeneralAssetsSettings), ex); throw; } }
public async Task <IActionResult> AddRate([FromBody] AddAssetRateModel request) { try { string lykkeBaseAssetId = await _lykkeAssetsResolver.GetLykkeId(request.BaseAssetId); if (await _assetsLocalCache.GetAssetByIdAsync(lykkeBaseAssetId) == null) { return(NotFound(ErrorResponse.Create("Base asset not found"))); } string lykkeQuotingAssetId = await _lykkeAssetsResolver.GetLykkeId(request.QuotingAssetId); if (await _assetsLocalCache.GetAssetByIdAsync(lykkeQuotingAssetId) == null) { return(NotFound(ErrorResponse.Create("Quoting asset not found"))); } IAssetPairRate newRate = await _assetRatesService.AddAsync(Mapper.Map <AddAssetPairRateCommand>(request, opt => { opt.Items["BaseAssetId"] = lykkeBaseAssetId; opt.Items["QuotingAssetId"] = lykkeQuotingAssetId; })); return(Ok(Mapper.Map <AssetRateResponse>(newRate, opt => { opt.Items["BaseAssetId"] = request.BaseAssetId; opt.Items["QuotingAssetId"] = request.QuotingAssetId; }))); } catch (AssetUnknownException e) { _log.ErrorWithDetails(e, new { e.Asset }); return(NotFound(ErrorResponse.Create($"Asset not found [{e.Asset}]"))); } catch (AssetPairRateStorageNotSupportedException e) { _log.ErrorWithDetails(e, new { e.BaseAssetId, e.QuotingAssetId }); return(StatusCode((int)HttpStatusCode.NotImplemented, ErrorResponse.Create(e.Message))); } }
public string Resolve(object source, object destination, string sourceMember, string destMember, ResolutionContext context) { if (!sourceMember.IsGuid()) { return(sourceMember); } return(_assetsLocalCache.GetAssetByIdAsync(sourceMember).GetAwaiter().GetResult().DisplayId); }
public async Task <IAssetGeneralSettings> GetGeneralAsync(string assetId) { string assetIdAdjusted = assetId == LykkeConstants.SatoshiAsset ? LykkeConstants.BitcoinAsset : assetId; string assetDisplayId = assetIdAdjusted.IsGuid() ? (await _assetsLocalCache.GetAssetByIdAsync(assetIdAdjusted)).DisplayId : assetIdAdjusted; return(await _assetGeneralSettingsRepository.GetAsync(assetDisplayId)); }
public async Task <decimal> GetAmountAsync(string baseAssetId, string quotingAssetId, decimal amount, IRequestMarkup requestMarkup, IMarkup merchantMarkup) { var rate = await GetRateAsync(baseAssetId, quotingAssetId, requestMarkup.Percent, requestMarkup.Pips, merchantMarkup); _log.Info("Rate calculation", $"Calculation details: {new {baseAssetId, quotingAssetId, amount, requestMarkup, merchantMarkup, rate}.ToJson()}"); if (rate == decimal.Zero) { throw new ZeroRateException(); } decimal result = (amount + requestMarkup.FixedFee + merchantMarkup.FixedFee) / rate; Asset baseAsset = await _assetsLocalCache.GetAssetByIdAsync(baseAssetId); decimal roundedResult = decimal.Round(result, baseAsset.Accuracy, MidpointRounding.AwayFromZero); return(roundedResult); }
public async Task <decimal> GetAmountAsync(string baseAssetId, string quotingAssetId, decimal amount, IRequestMarkup requestMarkup, IMarkup merchantMarkup) { var rate = await GetRateAsync(baseAssetId, quotingAssetId, requestMarkup.Percent, requestMarkup.Pips, merchantMarkup); await _log.WriteInfoAsync(nameof(CalculationService), nameof(GetAmountAsync), new { baseAssetId, quotingAssetId, amount, requestMarkup, merchantMarkup, rate }.ToJson(), "Rate calculation"); decimal result = (amount + (decimal)requestMarkup.FixedFee + merchantMarkup.FixedFee) / rate; Asset baseAsset = await _assetsLocalCache.GetAssetByIdAsync(baseAssetId); decimal roundedResult = decimal.Round(result, baseAsset.Accuracy, MidpointRounding.AwayFromZero); return(roundedResult); }
public async Task <string> GetLykkeId(string assetId) { Asset asset = await _assetsLocalCache.GetAssetByIdAsync(assetId); if (asset != null) { return(asset.Id); } if (_assetsMapSettings.Values.TryGetValue(assetId, out string lykkeId)) { return(lykkeId); } throw new AssetUnknownException(assetId); }
public async Task <IActionResult> ResolvePaymentAssets(string merchantId, [FromQuery] string settlementAssetId) { IMerchant merchant = await _merchantService.GetAsync(merchantId); if (merchant == null) { return(NotFound(ErrorResponse.Create("Couldn't find merchant"))); } string lykkeAssetId = await _lykkeAssetsResolver.GetLykkeId(settlementAssetId); Asset asset = await _assetsLocalCache.GetAssetByIdAsync(lykkeAssetId); if (asset == null) { return(NotFound(ErrorResponse.Create("Couldn't find asset"))); } try { IReadOnlyList <string> assets = await _assetsAvailabilityService.ResolvePaymentAsync(merchantId, settlementAssetId); return(Ok(new AvailableAssetsResponseModel { Assets = assets })); } catch (AssetUnknownException assetEx) { await _log.WriteErrorAsync(nameof(MerchantsController), nameof(ResolvePaymentAssets), new { assetEx.Asset }.ToJson(), assetEx); return(BadRequest(ErrorResponse.Create(assetEx.Message))); } catch (Exception ex) { await _log.WriteErrorAsync(nameof(MerchantsController), nameof(ResolvePaymentAssets), new { merchantId, settlementAssetId }.ToJson(), ex); throw; } }
public async Task <IActionResult> ResolvePaymentAssets(string merchantId, [FromQuery] string settlementAssetId) { merchantId = Uri.UnescapeDataString(merchantId); if (string.IsNullOrEmpty(settlementAssetId)) { return(BadRequest(ErrorResponse.Create("Settlement asset id is invalid"))); } try { string lykkeAssetId = await _lykkeAssetsResolver.GetLykkeId(settlementAssetId); Asset asset = await _assetsLocalCache.GetAssetByIdAsync(lykkeAssetId); if (asset == null) { return(NotFound(ErrorResponse.Create("Couldn't find asset"))); } IReadOnlyList <string> assets = await _assetSettingsService.ResolvePaymentAsync(merchantId, settlementAssetId); return(Ok(new AvailableAssetsResponseModel { Assets = assets })); } catch (InvalidRowKeyValueException e) { _log.ErrorWithDetails(e, new { e.Variable, e.Value }); return(BadRequest(ErrorResponse.Create(e.Message))); } catch (AssetUnknownException e) { _log.ErrorWithDetails(e, new { e.Asset }); return(BadRequest(ErrorResponse.Create(e.Message))); } }
public async Task <IMerchantWallet> GetDefaultAsync(string merchantId, string assetId, PaymentDirection paymentDirection) { BlockchainType network = await _assetSettingsService.GetNetworkAsync(assetId); IReadOnlyList <IMerchantWallet> merchantWallets = (await _merchantWalletRespository.GetByMerchantAsync(merchantId)).Where(x => x.Network == network) .ToList(); string assetDisplayId = assetId.IsGuid() ? (await _assetsLocalCache.GetAssetByIdAsync(assetId)).DisplayId : assetId; IReadOnlyList <IMerchantWallet> assetDefaultWallets = merchantWallets .Where(w => w.GetDefaultAssets(paymentDirection).Contains(assetDisplayId)) .ToList(); if (assetDefaultWallets.MoreThanOne()) { throw new MultipleDefaultMerchantWalletsException(merchantId, assetId, paymentDirection); } if (assetDefaultWallets.Any()) { return(assetDefaultWallets.Single()); } IReadOnlyList <IMerchantWallet> anyAssetDefaultWallets = merchantWallets .Where(w => !w.GetDefaultAssets(paymentDirection).Any()) .ToList(); if (anyAssetDefaultWallets.MoreThanOne()) { throw new MultipleDefaultMerchantWalletsException(merchantId, assetId, paymentDirection); } if (anyAssetDefaultWallets.Any()) { return(anyAssetDefaultWallets.Single()); } throw new DefaultMerchantWalletNotFoundException(merchantId, assetId, paymentDirection); }
public async Task <BlockchainTransferResult> TransferAsync(BlockchainTransferCommand transfer) { BlockchainTransferResult result = new BlockchainTransferResult { Blockchain = BlockchainType.Ethereum }; string lykkeAssetId = await _lykkeAssetsResolver.GetLykkeId(transfer.AssetId); Asset asset = await _assetsLocalCache.GetAssetByIdAsync(lykkeAssetId); if (asset.Type != AssetType.Erc20Token || !asset.IsTradable) { throw new AssetNotSupportedException(asset.Name); } ListOfErc20Token tokenSpecification = await _assetsService.Erc20TokenGetBySpecificationAsync(new Erc20TokenSpecification { Ids = new[] { asset.Id } }); string tokenAddress = tokenSpecification?.Items.SingleOrDefault(x => x.AssetId == asset.Id)?.Address; foreach (TransferAmount transferAmount in transfer.Amounts) { var transferRequest = Mapper.Map <TransferFromDepositRequest>(transferAmount, opts => opts.Items["TokenAddress"] = tokenAddress); object response = await _ethereumServiceClient.ApiLykkePayErc20depositsTransferPostAsync( _ethereumSettings.ApiKey, transferRequest); var errorMessage = string.Empty; var operationId = string.Empty; if (response is ApiException ex) { await _log.WriteWarningAsync(nameof(TransferAsync), transferAmount.ToJson(), ex.Error?.ToJson()); errorMessage = ex.Error?.Message; } else if (response is OperationIdResponse op) { operationId = op.OperationId; } else { throw new UnrecognizedApiResponse(response?.GetType().FullName ?? "Response object is null"); } result.Transactions.Add(new BlockchainTransactionResult { Amount = transferAmount.Amount, AssetId = asset.Name, Hash = string.Empty, IdentityType = TransactionIdentityType.Specific, Identity = operationId, Sources = new List <string> { transferAmount.Source }, Destinations = new List <string> { transferAmount.Destination }, Error = errorMessage }); } return(result); }
public async Task <BlockchainTransferResult> TransferAsync(BlockchainTransferCommand transfer) { BlockchainTransferResult result = new BlockchainTransferResult { Blockchain = BlockchainType.EthereumIata }; string lykkeAssetId = await _lykkeAssetsResolver.GetLykkeId(transfer.AssetId); Asset asset = await _assetsLocalCache.GetAssetByIdAsync(lykkeAssetId); if (asset.Type != AssetType.Erc20Token) { throw new AssetNotSupportedException(asset.Name); } ListOfErc20Token tokenSpecification = await _assetsService.Erc20TokenGetBySpecificationAsync(new Erc20TokenSpecification { Ids = new[] { asset.Id } }); string tokenAddress = tokenSpecification?.Items.SingleOrDefault(x => x.AssetId == asset.Id)?.Address; foreach (TransferAmount transferAmount in transfer.Amounts) { var transferRequest = Mapper.Map <AirlinesTransferFromDepositRequest>(transferAmount, opts => { opts.Items["TokenAddress"] = tokenAddress; opts.Items["AssetMultiplier"] = asset.MultiplierPower; opts.Items["AssetAccuracy"] = asset.Accuracy; }); object response = await _retryPolicy.ExecuteAsync(() => InvokeTransfer(transferRequest)); var ex = response as ApiException; var operation = response as OperationIdResponse; if (ex != null) { _log.Warning(ex.Error?.Message); } if (ex == null && operation == null) { throw new UnrecognizedApiResponse(response?.GetType().FullName ?? "Response object is null"); } result.Transactions.Add(new BlockchainTransactionResult { Amount = transferAmount.Amount ?? 0, AssetId = asset.DisplayId, Hash = string.Empty, IdentityType = TransactionIdentityType.Specific, Identity = operation?.OperationId ?? string.Empty, Sources = new List <string> { transferAmount.Source }, Destinations = new List <string> { transferAmount.Destination }, Error = ex?.Error?.Message ?? string.Empty, ErrorType = ex.GetDomainError() }); } return(result); }