예제 #1
0
        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);
     }
 }
예제 #3
0
        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());
 }