public async Task <IActionResult> CreateMultipleTransfer([FromBody] MultipleTransferRequest model) { foreach (var source in model.Sources) { await ValidateAddress(source.Address); } if (model.FixedFee.GetValueOrDefault() < 0) { throw new BackendException("Fixed fee must be greater than or equal to zero", ErrorCode.BadInputParameter); } var destAddress = OpenAssetsHelper.ParseAddress(model.Destination); if (destAddress == null) { throw new BackendException("Invalid destination address provided", ErrorCode.InvalidAddress); } var asset = await _assetRepository.GetAssetById(model.Asset); if (asset == null) { throw new BackendException("Provided asset is missing in database", ErrorCode.AssetNotFound); } var transactionId = await _builder.AddTransactionId(model.TransactionId, $"MultipleTransfer: {model.ToJson()}"); var response = await _builder.GetMultipleTransferTransaction(destAddress, asset, model.Sources.ToDictionary(x => x.Address, x => x.Amount), model.FeeRate, model.FixedFee.GetValueOrDefault(), transactionId); var fullSignedHex = await _signatureApiProvider.SignTransaction(response.Transaction); await _transactionBlobStorage.AddOrReplaceTransaction(transactionId, TransactionBlobType.Signed, fullSignedHex); var fullSigned = new Transaction(fullSignedHex); await _broadcastService.BroadcastTransaction(transactionId, fullSigned, useHandlers : false); return(Ok(new TransactionIdAndHashResponse { TransactionId = transactionId, Hash = fullSigned.GetHash().ToString() })); }
/// <summary> /// Broadcast multiple transfer transaction /// </summary> /// <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> ApiTransactionMultipletransferPostAsync(this IBitcoinApi operations, MultipleTransferRequest model = default(MultipleTransferRequest), CancellationToken cancellationToken = default(CancellationToken)) { using (var _result = await operations.ApiTransactionMultipletransferPostWithHttpMessagesAsync(model, null, cancellationToken).ConfigureAwait(false)) { return(_result.Body); } }
protected async Task <dynamic> PostTransferRaw(string assertId, PayRequest payRequest, int feeRate = 0) { var store = payRequest; var result = new TransferInProgressReturn { TransferResponse = new TransferInProgressResponse { Settlement = Settlement.TRANSACTION_DETECTED, TimeStamp = DateTime.UtcNow.Ticks, Currency = assertId }, TransferRequestId = payRequest.RequestId }; try { store.MerchantId = MerchantId; store.MerchantPayRequestStatus = MerchantPayRequestStatus.InProgress.ToString(); var list = await GetListOfSources(assertId) ?? new List <ToOneAddress>(); if (store.SourceAddress == PayApiSettings.HotWalletAddress) { list.Add(new ToOneAddress(PayApiSettings.HotWalletAddress, (decimal)store.Amount * 2)); } var isDestinationAddressValid = await _payWalletservice.ApiWalletsByWalletAddressGetWithHttpMessagesAsync(store.DestinationAddress); if (!(bool)isDestinationAddressValid.Body || (!string.IsNullOrEmpty(store.SourceAddress) && list.FirstOrDefault(l => store.SourceAddress .Equals(l.Address)) == null)) { await Log.WriteWarningAsync(nameof(PurchaseController), nameof(PostTransferRaw), LogContextPayRequest(store), $"Invalid adresses"); return(await JsonAndStoreError(store, new TransferErrorReturn { TransferResponse = new TransferErrorResponse { TransferError = TransferError.INVALID_ADDRESS, TimeStamp = DateTime.UtcNow.Ticks }, TransferRequestId = payRequest.RequestId })); } var sourceList = new List <ToOneAddress>(); if (!string.IsNullOrEmpty(store.SourceAddress)) { sourceList.Add(list.First(l => store.SourceAddress .Equals(l.Address))); } else { sourceList.AddRange(list); } if (!store.Amount.HasValue || store.Amount.Value <= 0) { await Log.WriteWarningAsync(nameof(PurchaseController), nameof(PostTransferRaw), LogContextPayRequest(store), $"Invalid amount"); return(await JsonAndStoreError(store, new TransferErrorReturn { TransferResponse = new TransferErrorResponse { TransferError = TransferError.INVALID_AMOUNT, TimeStamp = DateTime.UtcNow.Ticks }, TransferRequestId = "1" //payRequest.RequestId })); } decimal amountToPay = (decimal)store.Amount.Value; foreach (var src in sourceList) { if (!src.Amount.HasValue || src.Amount.Value == 0 || amountToPay == 0) { src.Amount = 0; continue; } var amout = Math.Max(src.Amount.Value, amountToPay); if (amout > amountToPay) { src.Amount = amountToPay; amountToPay = 0; } else { amountToPay -= src.Amount.Value; } } if (amountToPay > 0) { await Log.WriteWarningAsync(nameof(PurchaseController), nameof(PostTransferRaw), LogContextPayRequest(store), $"Invalid amount, there is not enough money in the wallet for translation: {amountToPay}"); return(await JsonAndStoreError(store, new TransferErrorReturn { TransferResponse = new TransferErrorResponse { TransferError = TransferError.INVALID_AMOUNT, TimeStamp = DateTime.UtcNow.Ticks }, TransferRequestId = "2" //payRequest.RequestId })); } var mtRequest = new MultipleTransferRequest { Asset = assertId, Destination = store.DestinationAddress, FeeRate = feeRate, Sources = new List <ToOneAddress>(from sl in sourceList where sl.Amount.HasValue && sl.Amount > 0 select sl) }; var r = await BitcointApiClient.ApiTransactionMultipletransferPostWithHttpMessagesAsync(mtRequest); var resData = r?.Body as TransactionIdAndHashResponse; if (resData?.Hash == null) { var errorCode = (r?.Body as ApiException)?.Error.Code; var errorMessage = (r?.Body as ApiException)?.Error.Message; if (resData == null && errorCode == "3") { await Log.WriteWarningAsync(nameof(PurchaseController), nameof(PostTransferRaw), LogContextPayRequest(store), $"Invalid amount. Error on TransactionMultipletransfer: {errorMessage} ({errorCode})"); return(await JsonAndStoreError(store, new TransferErrorReturn { TransferResponse = new TransferErrorResponse { TransferError = TransferError.INVALID_AMOUNT, TimeStamp = DateTime.UtcNow.Ticks }, TransferRequestId = "3" //payRequest.RequestId })); } await Log.WriteWarningAsync(nameof(PurchaseController), nameof(PostTransferRaw), LogContextPayRequest(store), "Transaction not confirmed."); return(await JsonAndStoreError(store, new TransferErrorReturn { TransferResponse = new TransferErrorResponse { TransferError = TransferError.TRANSACTION_NOT_CONFIRMED, TimeStamp = DateTime.UtcNow.Ticks }, TransferRequestId = payRequest.RequestId })); } store.TransactionId = resData.Hash; store.MerchantPayRequestNotification = MerchantPayRequestNotification.InProgress.ToString(); await StoreRequestClient.ApiStorePostWithHttpMessagesAsync(store); result.TransferResponse.TransactionId = store.TransactionId; } catch (Exception exception) { await Log.WriteWarningAsync(nameof(PurchaseController), nameof(PostTransferRaw), LogContextPayRequest(store), "Internal error. Exception on transfer.", exception); return(await JsonAndStoreError(store, new TransferErrorReturn { TransferResponse = new TransferErrorResponse { TransferError = TransferError.INTERNAL_ERROR, TimeStamp = DateTime.UtcNow.Ticks }, TransferRequestId = payRequest.RequestId })); } return(result); }
/// <summary> /// Broadcast multiple transfer transaction /// </summary> /// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='model'> /// </param> public static object ApiTransactionMultipletransferPost(this IBitcoinApi operations, MultipleTransferRequest model = default(MultipleTransferRequest)) { return(operations.ApiTransactionMultipletransferPostAsync(model).GetAwaiter().GetResult()); }