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 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"); }