예제 #1
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));
        }
예제 #2
0
        public async Task RemoveChannel([FromBody] RemoveChannelModel model)
        {
            var asset = await GetAsset(model.Asset);

            await _offchain.RemoveChannel(model.Multisig, asset);
        }