private async Task ProcessBroadcastedCommitment(ICommitment commitment, ICoin spendingCoin) { var lastCommitment = await _commitmentRepository.GetLastCommitment(commitment.Multisig, commitment.AssetId, commitment.Type); if (lastCommitment.CommitmentId == commitment.CommitmentId) { await _logger.WriteInfoAsync("OffchainCommitmentMonitoringFunction", "ProcessBroadcastedCommitment", $"CommitmentId: {commitment.CommitmentId}", "Last commitment was broadcasted"); await _offchainService.CloseChannel(commitment); await _commitmentBroadcastRepository.InsertCommitmentBroadcast(commitment.CommitmentId, spendingCoin.Outpoint.Hash.ToString(), CommitmentBroadcastType.Valid, commitment.ClientAmount, commitment.HubAmount, commitment.ClientAmount, commitment.HubAmount, null); return; } await _logger.WriteWarningAsync("OffchainCommitmentMonitoringFunction", "ProcessBroadcastedCommitment", $"CommitmentId: {commitment.CommitmentId}", "Commitment is not last."); if (commitment.Type == CommitmentType.Client) { var assetSettings = await _offchainService.GetAssetSetting(commitment.AssetId); var hash = await _offchainService.SpendCommitmemtByMultisig(commitment, spendingCoin, !string.IsNullOrEmpty(assetSettings.ChangeWallet)?assetSettings.ChangeWallet : assetSettings.HotWallet); await _offchainService.CloseChannel(commitment); await _commitmentBroadcastRepository.InsertCommitmentBroadcast(commitment.CommitmentId, spendingCoin.Outpoint.Hash.ToString(), CommitmentBroadcastType.Revoked, commitment.ClientAmount, commitment.HubAmount, lastCommitment.ClientAmount, lastCommitment.HubAmount, hash); } else { await _slackNotifier.WarningAsync($"Hub commitment with id {commitment.CommitmentId} was broadcasted but it's not last"); } }
public async Task Process(SpendCommitmentMonitorindMessage message, QueueTriggeringContext context) { if (DateTime.UtcNow - message.LastTryTime.GetValueOrDefault() < MessageProcessDelay) { MoveToEnd(context, message); return; } message.LastTryTime = DateTime.UtcNow; var tr = await _qBitNinjaApiCaller.GetTransaction(message.TransactionHash); if (tr?.Block == null || tr.Block.Confirmations < OffchainService.OneDayDelay) { MoveToEnd(context, message); return; } var commitment = await _commitmentRepository.GetCommitment(message.CommitmentId); var lockedAddr = OpenAssetsHelper.ParseAddress(commitment.LockedAddress); var coin = tr.ReceivedCoins .FirstOrDefault(o => o.TxOut.ScriptPubKey.GetDestinationAddress(_connectionParams.Network) == lockedAddr); if (coin == null) { throw new Exception("Not found coin for spending for " + message.ToJson()); } if (coin is Coin) { coin = ((Coin)coin).ToScriptCoin(commitment.LockedScript.ToScript()); } else { var colored = coin as ColoredCoin; coin = colored.Bearer.ToScriptCoin(commitment.LockedScript.ToScript()).ToColoredCoin(colored.Amount); } var assetSettings = await _offchainService.GetAssetSetting(commitment.AssetId); try { var hash = await _offchainService.SpendCommitmemtByPubkey(commitment, coin, !string.IsNullOrEmpty(assetSettings.ChangeWallet)?assetSettings.ChangeWallet : assetSettings.HotWallet); await _log.WriteInfoAsync(nameof(SpendBroadcastedCommitmentFunction), nameof(Process), message.ToJson(), "Spent commitment by transaction" + hash); } catch (Exception ex) { await _log.WriteWarningAsync(nameof(SpendBroadcastedCommitmentFunction), nameof(Process), message.ToJson(), ex); MoveToEnd(context, message); } }
public Task <CreateTransactionResponse> GetTransferAllTransaction(BitcoinAddress @from, BitcoinAddress to, Guid transactionId) { return(Retry.Try(async() => { var context = _transactionBuildContextFactory.Create(_connectionParams.Network); var channels = await _offchainService.GetCurrentChannels(from.ToString()); var assets = await _assetRepository.Values(); return await context.Build(async() => { var builder = new TransactionBuilder(); var uncoloredCoins = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(from.ToString())).ToList(); var coloredCoins = (await _bitcoinOutputsService.GetColoredUnspentOutputs(from.ToString())).ToList(); if (uncoloredCoins.Count == 0 && coloredCoins.Count == 0) { throw new BackendException("Address has no unspent outputs", ErrorCode.NoCoinsFound); } async Task <IDestination> GetChangeWallet(string asset) { var assetSetting = await _offchainService.GetAssetSetting(asset); return OpenAssetsHelper.ParseAddress(!string.IsNullOrEmpty(assetSetting.ChangeWallet) ? assetSetting.ChangeWallet : assetSetting.HotWallet); }; if (uncoloredCoins.Count > 0) { var hubAmount = Money.Zero; IDestination hubAmountAddress = null; var channel = channels.FirstOrDefault(o => o.Asset == "BTC"); if (channel != null) { hubAmount = Money.FromUnit(channel.HubAmount, MoneyUnit.BTC); hubAmountAddress = await GetChangeWallet("BTC"); } builder.AddCoins(uncoloredCoins); context.AddCoins(uncoloredCoins); builder.Send(to, uncoloredCoins.Sum(o => o.TxOut.Value) - hubAmount); if (hubAmount > 0) { builder.Send(hubAmountAddress, hubAmount); } } foreach (var assetGroup in coloredCoins.GroupBy(o => o.AssetId)) { var asset = assets.First(o => o.BlockChainAssetId == assetGroup.Key.GetWif(_connectionParams.Network).ToString()); var channel = channels.FirstOrDefault(o => o.Asset == asset.Id); var sum = new AssetMoney(assetGroup.Key); foreach (var coloredCoin in assetGroup) { sum += coloredCoin.Amount; } var hubAmount = new AssetMoney(assetGroup.Key); IDestination hubAmountAddress = null; if (channel != null) { hubAmount = new AssetMoney(assetGroup.Key, channel.HubAmount, asset.MultiplierPower); hubAmountAddress = await GetChangeWallet(asset.Id); } builder.AddCoins(assetGroup.ToList()); context.AddCoins(assetGroup.ToList()); builder.SendAsset(to, sum - hubAmount); if (hubAmount.Quantity > 0) { builder.SendAsset(hubAmountAddress, hubAmount); } } await _transactionBuildHelper.AddFee(builder, context); var buildedTransaction = builder.BuildTransaction(true); await _spentOutputService.SaveSpentOutputs(transactionId, buildedTransaction); await SaveNewOutputs(transactionId, buildedTransaction, context); foreach (var offchainChannel in channels) { await _offchainService.RemoveChannel(offchainChannel); } return new CreateTransactionResponse(buildedTransaction.ToHex(), transactionId); }); }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log)); }