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");
            }
        }
Beispiel #2
0
        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);
            }
        }
Beispiel #3
0
        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));
        }