예제 #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));
        }
예제 #2
0
        private async Task GenerateOutputs(int generateCnt, IEnumerable <ICoin> coins, BitcoinAddress hotWallet, IMoney amount, IAsset asset, IAssetSetting setting)
        {
            var colored = amount is AssetMoney;
            await _logger.WriteInfoAsync("GenerateOffchainOutputsFunction", "GenerateOutputs", null,
                                         $"Start generate {generateCnt} outputs for {asset.Id}");

            var generated = 0;

            while (generated < generateCnt)
            {
                var outputsCount = Math.Min(setting.MaxOutputsCountInTx, generateCnt - generated);

                var context = _transactionBuildContextFactory.Create(_connectionParams.Network);

                if (colored)
                {
                    var total = coins.Cast <ColoredCoin>().DefaultIfEmpty().Sum(o => o?.Amount.Quantity ?? 0);
                    if (total < ((AssetMoney)amount).Quantity * outputsCount)
                    {
                        return;
                    }
                }
                else
                {
                    var total = coins.Cast <Coin>().DefaultIfEmpty().Sum(o => o?.Amount ?? Money.Zero);
                    if (total < (Money)amount * outputsCount)
                    {
                        return;
                    }
                }

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

                    builder.AddCoins(coins);
                    for (int i = 0; i < outputsCount; i++)
                    {
                        if (colored)
                        {
                            builder.SendAsset(hotWallet, (AssetMoney)amount);
                        }
                        else
                        {
                            builder.Send(hotWallet, amount);
                        }
                    }

                    builder.SetChange(hotWallet, colored ? ChangeType.Colored : ChangeType.Uncolored);
                    await _transactionBuildHelper.AddFee(builder, context);
                    builder.SetChange(hotWallet, colored ? ChangeType.Colored : ChangeType.Uncolored);

                    var tr = builder.BuildTransaction(true);

                    await SignAndBroadcastTransaction(tr, context);

                    var usedCoins = new HashSet <OutPoint>(tr.Inputs.Select(o => o.PrevOut));

                    coins = coins.Where(o => !usedCoins.Contains(o.Outpoint)).ToList();

                    return("");
                });

                generated += outputsCount;
            }
            await _logger.WriteInfoAsync("GenerateOffchainOutputsFunction", "GenerateOutputs", null, "End process");
        }