예제 #1
0
        public Task <CreateTransactionResponse> GetTransferTransaction(BitcoinAddress sourceAddress,
                                                                       BitcoinAddress destAddress, decimal amount, IAsset asset, Guid transactionId, bool shouldReserveFee = false, bool sentDust = false)
        {
            return(Retry.Try(async() =>
            {
                var context = _transactionBuildContextFactory.Create(_connectionParams.Network);

                return await context.Build(async() =>
                {
                    var builder = new TransactionBuilder();

                    await TransferOneDirection(builder, context, sourceAddress, amount, asset, destAddress, !shouldReserveFee, sentDust);

                    await _transactionBuildHelper.AddFee(builder, context);

                    var buildedTransaction = builder.BuildTransaction(true);

                    await _spentOutputService.SaveSpentOutputs(transactionId, buildedTransaction);

                    await SaveNewOutputs(transactionId, buildedTransaction, context);

                    if (shouldReserveFee)
                    {
                        await _feeReserveMonitoringWriter.AddTransactionFeeReserve(transactionId, context.FeeCoins);
                    }

                    return new CreateTransactionResponse(buildedTransaction.ToHex(), transactionId);
                });
            }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log));
        }
        private async Task FinishOutputs(Guid transactionId, Transaction tr, BitcoinPubKeyAddress hotWallet)
        {
            await _broadcastedOutputRepository.InsertOutputs(tr.Outputs.AsCoins()
                                                             .Where(o => o.ScriptPubKey.GetDestinationAddress(_connectionParams.Network).ToString() == hotWallet.ToString())
                                                             .Select(o => new BroadcastedOutput(o, transactionId, _connectionParams.Network)));

            await _broadcastedOutputRepository.SetTransactionHash(transactionId, tr.GetHash().ToString());

            await _spentOutputService.SaveSpentOutputs(transactionId, tr);
        }
        public async Task Send()
        {
            var feePerByte = (await _feeProvider.GetFeeRate()).FeePerK.Satoshi * _baseSettings.SpendChangeFeeRateMultiplier / 1000;

            var coins = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(_baseSettings.ChangeAddress, ConfirmationsCount)).OfType <Coin>()
                        .Where(o => o.Amount.Satoshi > feePerByte * Constants.InputSize).ToList();

            Utils.Shuffle(coins, new Random());

            while (coins.Count > _baseSettings.NumberOfChangeInputsForTransaction)
            {
                var part    = coins.Take(_baseSettings.NumberOfChangeInputsForTransaction).ToList();
                var balance = part.Sum(o => o.Amount);

                var builder = new TransactionBuilder();
                builder.AddCoins(part);
                builder.Send(new BitcoinPubKeyAddress(_baseSettings.HotWalletForPregeneratedOutputs), balance);

                var tr  = builder.BuildTransaction(false);
                var fee = new Money((await _feeProvider.CalcFeeForTransaction(builder)).Satoshi * _baseSettings.SpendChangeFeeRateMultiplier, MoneyUnit.Satoshi);
                if (fee > balance)
                {
                    await _log.WriteWarningAsync("SendFromChangeToHotWalletFunction", "Send", null,
                                                 $"Calculated fee is more than balance ({fee.Satoshi}>{balance})");

                    continue;
                }
                tr.Outputs[0].Value = tr.Outputs[0].Value - fee;

                var signed = await _signatureApiProvider.SignTransaction(tr.ToHex());

                var signedTr = new Transaction(signed);

                var transactionId = Guid.NewGuid();
                await _bitcoinBroadcastService.BroadcastTransaction(transactionId, signedTr);

                await _spentOutputService.SaveSpentOutputs(transactionId, signedTr);

                coins = coins.Skip(_baseSettings.NumberOfChangeInputsForTransaction).ToList();
            }
        }
예제 #4
0
        private async Task SignAndBroadcastTransaction(Transaction buildedTransaction, TransactionBuildContext context)
        {
            try
            {
                var id = Guid.NewGuid();

                var signed = await _signatureApi.SignTransaction(buildedTransaction.ToHex());

                var tr = new Transaction(signed);
                await _spentOutputService.SaveSpentOutputs(id, tr);
                await SaveNewOutputs(id, buildedTransaction, context);

                await _bitcoinBroadcastService.BroadcastTransaction(id, tr);
            }
            catch (Exception)
            {
                await _spentOutputService.RemoveSpentOutputs(buildedTransaction);

                throw;
            }
        }