public async Task <string> GetOrBuildTransferTransaction(Guid operationId, BitcoinAddress fromAddress, PubKey fromAddressPubkey, BitcoinAddress toAddress, string assetId, Money amountToSend, bool includeFee) { if (await _operationMetaRepository.Exist(operationId)) { return(await _transactionBlobStorage.GetTransaction(operationId, TransactionBlobType.Initial)); } var buildedTransaction = await _transactionBuilder.GetTransferTransaction(fromAddress, fromAddressPubkey, toAddress, amountToSend, includeFee); var transactionContext = Serializer.ToString((tx: buildedTransaction.TransactionData, spentCoins: buildedTransaction.SpentCoins)); await _transactionBlobStorage.AddOrReplaceTransaction(operationId, TransactionBlobType.Initial, transactionContext); var operation = OperationMeta.Create(operationId, fromAddress.ToString(), toAddress.ToString(), assetId, buildedTransaction.Amount.Satoshi, buildedTransaction.Fee.Satoshi, includeFee); await _operationMetaRepository.Insert(operation); return(transactionContext); }
public async Task <Transaction> GetOrBuildTransferTransaction(Guid operationId, BitcoinAddress fromAddress, PubKey fromAddressPubkey, BitcoinAddress toAddress, string assetId, Money amountToSend, bool includeFee) { if (await _operationMetaRepository.Exist(operationId)) { var alreadyBuildedTransaction = await _transactionBlobStorage.GetTransaction(operationId, TransactionBlobType.Initial); return(Transaction.Parse(alreadyBuildedTransaction)); } var buildedTransaction = await _transactionBuilder.GetTransferTransaction(fromAddress, fromAddressPubkey, toAddress, amountToSend, includeFee); await _transactionBlobStorage.AddOrReplaceTransaction(operationId, TransactionBlobType.Initial, buildedTransaction.TransactionData.ToHex()); var operation = OperationMeta.Create(operationId, fromAddress.ToString(), toAddress.ToString(), assetId, buildedTransaction.Amount.Satoshi, buildedTransaction.Fee.Satoshi, includeFee); await _operationMetaRepository.Insert(operation); return(buildedTransaction.TransactionData); }
public async Task BroadcastTransaction(BroadcastingTransaction transaction, QueueTriggeringContext context) { try { var signedByClientTr = await _transactionBlobStorage.GetTransaction(transaction.TransactionId, TransactionBlobType.Initial); var signedByExchangeTr = await _exchangeSignatureApi.SignTransaction(signedByClientTr); if (!await _settingsRepository.Get(Constants.CanBeBroadcastedSetting, true)) { await _transactionBlobStorage.AddOrReplaceTransaction(transaction.TransactionId, TransactionBlobType.Signed, signedByExchangeTr); context.MoveMessageToPoison(transaction.ToJson()); return; } var tr = new Transaction(signedByExchangeTr); await _broadcastService.BroadcastTransaction(transaction.TransactionId, tr); if (transaction.TransactionCommandType == TransactionCommandType.SegwitTransferToHotwallet) { _cqrsEngine.PublishEvent(new CashinCompletedEvent { OperationId = transaction.TransactionId, TxHash = tr.GetHash().ToString() }, BitcoinBoundedContext.Name); } if (transaction.TransactionCommandType == TransactionCommandType.Transfer) { _cqrsEngine.PublishEvent(new CashoutCompletedEvent { OperationId = transaction.TransactionId, TxHash = tr.GetHash().ToString() }, BitcoinBoundedContext.Name); } } catch (RPCException e) { if (e.Message != transaction.LastError) { await _logger.WriteWarningAsync("BroadcastingTransactionFunction", "BroadcastTransaction", $"Id: [{transaction.TransactionId}]", $"Message: {e.Message} Code:{e.RPCCode} CodeMessage:{e.RPCCodeMessage}"); } transaction.LastError = e.Message; var unacceptableTx = _unacceptableTxErrors.Any(o => e.Message.Contains(o)); if (transaction.DequeueCount >= _settings.MaxDequeueCount || unacceptableTx) { context.MoveMessageToPoison(); } else { transaction.DequeueCount++; context.MoveMessageToEnd(transaction.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); } } }
public async Task Monitor(FeeReserveMonitoringMessage message, QueueTriggeringContext context) { if (await _broadcastedTransactionBlob.IsBroadcasted(message.TransactionId)) { return; } if (DateTime.UtcNow - message.PutDateTime > TimeSpan.FromSeconds(_settings.FeeReservePeriodSeconds)) { await _logger.WriteInfoAsync("FeeReserveMonitoringFunction", "Monitor", message.ToJson(), "Free reserved fee"); await _transactionSignRequestRepository.InvalidateTransactionId(message.TransactionId); await Task.Delay(3000); if (await _broadcastedTransactionBlob.IsBroadcasted(message.TransactionId)) { return; } var transaction = await _transactionBlobStorage.GetTransaction(message.TransactionId, TransactionBlobType.Initial); var tr = new Transaction(transaction); await _spentOutputService.RemoveSpentOutputs(tr); var queue = _pregeneratedOutputsQueueFactory.CreateFeeQueue(); await queue.EnqueueOutputs(message.FeeCoins.Select(x => x.ToCoin()).ToArray()); } else { context.MoveMessageToEnd(); context.SetCountQueueBasedDelay(5000, 100); } }
public async Task Broadcast([FromBody] BroadcastTransactionRequest model) { var signRequest = await _transactionSignRequestRepository.GetSignRequest(model.TransactionId); if (signRequest == null) { throw new BackendException("Transaction is not found", ErrorCode.BadTransaction); } if (signRequest.Invalidated == true) { throw new BackendException("Transaction was invalidated", ErrorCode.BadTransaction); } var initialTransaction = await _transactionBlobStorage.GetTransaction(model.TransactionId, TransactionBlobType.Initial); if (!TransactionComparer.CompareTransactions(initialTransaction, model.Transaction)) { throw new BackendException("Signed transaction is not equals to initial transaction", ErrorCode.BadTransaction); } var transaction = new Transaction(model.Transaction); if (transaction.Inputs.All(o => o.ScriptSig == null || o.ScriptSig.Length == 0)) { throw new BackendException("Transaction is not signed by client", ErrorCode.BadTransaction); } var fullSignedHex = signRequest.DoNotSign ? model.Transaction : await _signatureApiProvider.SignTransaction(model.Transaction); await _transactionBlobStorage.AddOrReplaceTransaction(model.TransactionId, TransactionBlobType.Signed, fullSignedHex); var fullSigned = new Transaction(fullSignedHex); await _broadcastService.BroadcastTransaction(model.TransactionId, fullSigned, useHandlers : false, savePaidFees : !signRequest.DoNotSign); }
private async Task <BuiltTransactionInfo> GetExistingTransaction(Guid operationId, string hash) { var alreadyBuildedTransaction = await _transactionBlobStorage.GetTransaction(operationId, hash, TransactionBlobType.Initial); return(Serializer.ToObject <BuiltTransactionInfo>(alreadyBuildedTransaction)); }