public async Task <IActionResult> Execute([FromBody] CashoutModel request) { try { var clientRequest = Mapper.Map <CashoutRequest>(request, opt => { opt.Items["MerchantId"] = this.GetUserMerchantId(); opt.Items["EmployeeEmail"] = this.GetUserEmail(); }); CashoutResponse response = await _payInternalClient.CashoutAsync(clientRequest); return(Ok(Mapper.Map <CashoutResponseModel>(response))); } catch (DefaultErrorResponseException e) when(e.StatusCode == HttpStatusCode.BadRequest) { var apiException = e.InnerException as ApiException; if (apiException?.StatusCode == HttpStatusCode.BadRequest) { return(BadRequest(apiException.GetContentAs <ErrorResponse>())); } _log.Error(e, null, $"request:{request.ToJson()}"); return(BadRequest(ErrorResponse.Create(e.Message))); } }
public async Task <OffchainClosingResponse> Cashout(CashoutData data) { var request = new CashoutModel(data.ClientPubKey, data.CashoutAddress, data.HotWalletAddress, data.AssetId, data.Amount); var response = await _apiClient.ApiOffchainCashoutPostAsync(request); return(PrepareOffchainClosingResult(response)); }
public static HistoryModel ToHistoryModel(this CashoutModel cashout) { return(new HistoryModel { Id = cashout.Id.ToString(), DateTime = cashout.Timestamp, Type = HistoryType.CashOut, Asset = cashout.AssetId, Amount = cashout.Volume, State = cashout.State, FeeSize = cashout.FeeSize.GetValueOrDefault(0), FeeAssetId = cashout.AssetId }); }
public async Task <IActionResult> Cashout([FromBody] CashoutModel model) { if (!ModelState.IsValid) { throw new ClientSideException(ExceptionType.WrongParams, JsonConvert.SerializeObject(ModelState.Errors())); } await Log("Cashout", $"Begin Process {this.GetIp()}", model); var amount = BigInteger.Parse(model.Amount); var operationId = await _pendingOperationService.CashOut(model.Id, model.CoinAdapterAddress, _addressUtil.ConvertToChecksumAddress(model.FromAddress), _addressUtil.ConvertToChecksumAddress(model.ToAddress), amount, model.Sign); await Log("Cashout", "End Process", model, operationId); return(Ok(new OperationIdResponse { OperationId = operationId })); }
/// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='model'> /// </param> /// <param name='cancellationToken'> /// The cancellation token. /// </param> public static async Task <object> ApiExchangeCashoutPostAsync(this IEthereumApi operations, CashoutModel model = default(CashoutModel), CancellationToken cancellationToken = default(CancellationToken)) { using (var _result = await operations.ApiExchangeCashoutPostWithHttpMessagesAsync(model, null, cancellationToken).ConfigureAwait(false)) { return(_result.Body); } }
/// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='model'> /// </param> public static object ApiExchangeCashoutPost(this IEthereumApi operations, CashoutModel model = default(CashoutModel)) { return(operations.ApiExchangeCashoutPostAsync(model).GetAwaiter().GetResult()); }
/// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='model'> /// </param> /// <param name='cancellationToken'> /// The cancellation token. /// </param> public static async System.Threading.Tasks.Task <object> ApiOffchainCashoutPostAsync(this IBitcoinApi operations, CashoutModel model = default(CashoutModel), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { using (var _result = await operations.ApiOffchainCashoutPostWithHttpMessagesAsync(model, null, cancellationToken).ConfigureAwait(false)) { return(_result.Body); } }
/// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='model'> /// </param> public static object ApiOffchainCashoutPost(this IBitcoinApi operations, CashoutModel model = default(CashoutModel)) { return(System.Threading.Tasks.Task.Factory.StartNew(s => ((IBitcoinApi)s).ApiOffchainCashoutPostAsync(model), operations, System.Threading.CancellationToken.None, System.Threading.Tasks.TaskCreationOptions.None, System.Threading.Tasks.TaskScheduler.Default).Unwrap().GetAwaiter().GetResult()); }
public async Task <CashoutOffchainApiResponse> CreateCashout([FromBody] CashoutModel model) { var asset = await GetAsset(model.Asset); return(new CashoutOffchainApiResponse(await _offchain.CreateCashout(model.ClientPubKey, model.CashoutAddress, model.Amount, asset))); }
public async Task <IActionResult> Execute([FromBody] CashoutModel request) { try { CashoutResult cashoutResult = await _cashoutService.ExecuteAsync(Mapper.Map <CashoutCommand>(request)); return(Ok(Mapper.Map <CashoutResponse>(cashoutResult))); } catch (AssetNetworkNotDefinedException e) { _log.ErrorWithDetails(e, new { e.AssetId }); return(BadRequest(ErrorResponse.Create(e.Message))); } catch (InvalidOperationException e) { _log.ErrorWithDetails(e, request); return(BadRequest(ErrorResponse.Create(e.Message))); } catch (InsufficientFundsException e) { _log.ErrorWithDetails(e, new { e.WalletAddress, e.AssetId }); return(BadRequest(ErrorResponse.Create(e.Message))); } catch (CashoutOperationFailedException e) { _log.ErrorWithDetails(e, new { errors = e.TransferErrors }); return(BadRequest(ErrorResponse.Create(e.Message))); } catch (MultipleDefaultMerchantWalletsException e) { _log.ErrorWithDetails(e, new { e.AssetId, e.MerchantId, e.PaymentDirection }); return(BadRequest(ErrorResponse.Create(e.Message))); } catch (DefaultMerchantWalletNotFoundException e) { _log.ErrorWithDetails(e, new { e.AssetId, e.MerchantId, e.PaymentDirection }); return(BadRequest(ErrorResponse.Create(e.Message))); } catch (MerchantWalletOwnershipException e) { _log.ErrorWithDetails(e, new { e.MerchantId, e.WalletAddress }); return(BadRequest(ErrorResponse.Create(e.Message))); } catch (CashoutHotwalletNotDefinedException e) { _log.ErrorWithDetails(e, new { e.Blockchain }); return(BadRequest(ErrorResponse.Create(e.Message))); } }
/// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='model'> /// </param> public static object ApiOffchainCashoutPost(this IBitcoinApi operations, CashoutModel model = default(CashoutModel)) { return(operations.ApiOffchainCashoutPostAsync(model).GetAwaiter().GetResult()); }
/// <summary> /// /// </summary> /// <param name="cashoutModel"></param> /// <returns> /// ValidationError - client error /// ArgumentValidationException - developer error /// </returns> public async Task <IReadOnlyCollection <ValidationError> > ValidateAsync(CashoutModel cashoutModel) { var errors = new List <ValidationError>(1); if (cashoutModel == null) { return(FieldNotValidResult("cashoutModel can't be null")); } if (string.IsNullOrEmpty(cashoutModel.AssetId)) { return(FieldNotValidResult("cashoutModel.AssetId can't be null or empty")); } Asset asset; try { asset = await _assetsService.TryGetAssetAsync(cashoutModel.AssetId); } catch (Exception) { throw new ArgumentValidationException($"Asset with Id-{cashoutModel.AssetId} does not exists", "assetId"); } if (asset.IsDisabled) { errors.Add(ValidationError.Create(ValidationErrorType.None, $"Asset {asset.Id} is disabled")); } if (asset == null) { throw new ArgumentValidationException($"Asset with Id-{cashoutModel.AssetId} does not exists", "assetId"); } var isAddressValid = true; IBlockchainApiClient blockchainClient = null; if (asset.Id != LykkeConstants.SolarAssetId) { if (string.IsNullOrEmpty(asset.BlockchainIntegrationLayerId)) { throw new ArgumentValidationException( $"Given asset Id-{cashoutModel.AssetId} is not a part of Blockchain Integration Layer", "assetId"); } blockchainClient = _blockchainApiClientProvider.Get(asset.BlockchainIntegrationLayerId); } if (string.IsNullOrEmpty(cashoutModel.DestinationAddress) || !cashoutModel.DestinationAddress.IsValidPartitionOrRowKey() || asset.Id != LykkeConstants.SolarAssetId && blockchainClient != null && !await blockchainClient.IsAddressValidAsync(cashoutModel.DestinationAddress) || asset.Id == LykkeConstants.SolarAssetId && !SolarCoinValidation.ValidateAddress(cashoutModel.DestinationAddress) ) { isAddressValid = false; errors.Add(ValidationError.Create(ValidationErrorType.AddressIsNotValid, "Address is not valid")); } if (isAddressValid) { if (asset.Id != LykkeConstants.SolarAssetId) { var isBlocked = await _blackListService.IsBlockedWithoutAddressValidationAsync ( asset.BlockchainIntegrationLayerId, cashoutModel.DestinationAddress ); if (isBlocked) { errors.Add(ValidationError.Create(ValidationErrorType.BlackListedAddress, "Address is in the black list")); } } if (cashoutModel.Volume.HasValue && Math.Abs(cashoutModel.Volume.Value) < (decimal)asset.CashoutMinimalAmount) { var minimalAmount = asset.CashoutMinimalAmount.GetFixedAsString(asset.Accuracy).TrimEnd('0'); errors.Add(ValidationError.Create(ValidationErrorType.LessThanMinCashout, $"Please enter an amount greater than {minimalAmount}")); } if (asset.Id != LykkeConstants.SolarAssetId) { var blockchainSettings = _blockchainSettingsProvider.Get(asset.BlockchainIntegrationLayerId); if (cashoutModel.DestinationAddress == blockchainSettings.HotWalletAddress) { errors.Add(ValidationError.Create(ValidationErrorType.HotwalletTargetProhibited, "Hot wallet as destitnation address prohibited")); } var isPublicExtensionRequired = _blockchainWalletsCacheService.IsPublicExtensionRequired(asset.BlockchainIntegrationLayerId); if (isPublicExtensionRequired) { var hotWalletParseResult = await _blockchainWalletsClient.ParseAddressAsync( asset.BlockchainIntegrationLayerId, blockchainSettings.HotWalletAddress); var destAddressParseResult = await _blockchainWalletsClient.ParseAddressAsync( asset.BlockchainIntegrationLayerId, cashoutModel.DestinationAddress); if (hotWalletParseResult.BaseAddress == destAddressParseResult.BaseAddress) { var existedClientIdAsDestination = await _blockchainWalletsClient.TryGetClientIdAsync( asset.BlockchainIntegrationLayerId, cashoutModel.DestinationAddress); if (existedClientIdAsDestination == null) { errors.Add(ValidationError.Create(ValidationErrorType.DepositAddressNotFound, $"Deposit address {cashoutModel.DestinationAddress} not found")); } } var forbiddenCharacterErrors = await ValidateForForbiddenCharsAsync( destAddressParseResult.BaseAddress, destAddressParseResult.AddressExtension, asset.BlockchainIntegrationLayerId); if (forbiddenCharacterErrors != null) { errors.AddRange(forbiddenCharacterErrors); } if (!string.IsNullOrEmpty(destAddressParseResult.BaseAddress)) { if (!cashoutModel.DestinationAddress.Contains(destAddressParseResult.BaseAddress)) { errors.Add(ValidationError.Create(ValidationErrorType.FieldIsNotValid, "Base Address should be part of destination address")); } // full address is already checked by integration, // we don't need to validate it again, // just ensure that base address is not black-listed var isBlockedBase = await _blackListService.IsBlockedWithoutAddressValidationAsync( asset.BlockchainIntegrationLayerId, destAddressParseResult.BaseAddress); if (isBlockedBase) { errors.Add(ValidationError.Create(ValidationErrorType.BlackListedAddress, "Base Address is in the black list")); } } } } if (cashoutModel.ClientId.HasValue) { var destinationClientId = await _blockchainWalletsClient.TryGetClientIdAsync ( asset.BlockchainIntegrationLayerId, cashoutModel.DestinationAddress ); if (destinationClientId.HasValue && destinationClientId == cashoutModel.ClientId.Value) { var error = ValidationError.Create ( ValidationErrorType.CashoutToSelfAddress, "Withdrawals to the deposit wallet owned by the customer himself prohibited" ); errors.Add(error); } } } return(errors); }