public async Task <SplitTransactionResponse> GetSplitTransaction([FromQuery] string multisig, [FromQuery] string clientDestination, [FromQuery] string hubDestination)
        {
            var result = await _bccTransactionService.CreateSplitTransaction(multisig, OpenAssetsHelper.ParseAddress(clientDestination),
                                                                             OpenAssetsHelper.ParseAddress(hubDestination));

            return(new SplitTransactionResponse(result));
        }
        public async Task SpendSegwitOutput()
        {
            var pk1     = Key.Parse("cMahea7zqjxrtgAbB7LSGbcZDo359LNtib5kYpwbiSqBqvs6cqPV");
            var pk2     = Key.Parse("cQDux9gANFC1mPiwPpx7feHpiZu9xKn8RyV8yLErazuzWt146oY1");
            var pubKey1 = new PubKey("03ebcc2d675d17c5b5e250307cb0189bfc5adf6809bfd3c2823a2884dbbcaec58b").Compress();
            var pubKey2 = new PubKey("02235060021d06f6c4e766574b0374dde8d050a0a036ee52cde04608a87eebc3e1").Compress();

            var redeem = PayToMultiSigTemplate.Instance.GenerateScriptPubKey(2, pubKey1, pubKey2);

            var coin = new Coin(new OutPoint(uint256.Parse("9aff0ea55be499f0c664e447a93f7a38a87cc34f24f464642c7553b40fd18958"), 1),
                                new TxOut(Money.FromUnit(0.2M, MoneyUnit.BTC), redeem.WitHash.ScriptPubKey));

            var scriptCoin = coin.ToScriptCoin(redeem);

            var builder = new TransactionBuilder();

            builder.AddCoins(scriptCoin);
            builder.Send(OpenAssetsHelper.ParseAddress("mj5FEqrC2P4FjFNfX8q3eZ4UABWUcRNy9r"), Money.FromUnit(0.1M, MoneyUnit.BTC));
            builder.SetChange(coin.ScriptPubKey);
            builder.SendFees(Money.FromUnit(0.0001M, MoneyUnit.BTC));

            builder.AddKeys(pk1, pk2);
            var tr = builder.BuildTransaction(true);

            //await Broadcast(tr);
        }
        public async Task SpendMultisigWitOverP2ShOutput()
        {
            var pk1     = Key.Parse("cMahea7zqjxrtgAbB7LSGbcZDo359LNtib5kYpwbiSqBqvs6cqPV");
            var pk2     = Key.Parse("cQDux9gANFC1mPiwPpx7feHpiZu9xKn8RyV8yLErazuzWt146oY1");
            var pubKey1 = new PubKey("03ebcc2d675d17c5b5e250307cb0189bfc5adf6809bfd3c2823a2884dbbcaec58b").Compress();
            var pubKey2 = new PubKey("02235060021d06f6c4e766574b0374dde8d050a0a036ee52cde04608a87eebc3e1").Compress();

            var redeem = PayToMultiSigTemplate.Instance.GenerateScriptPubKey(2, pubKey1, pubKey2);

            var coin = new Coin(new OutPoint(uint256.Parse("2b2e47cd0ba3be2a013fd8658f24e66aae5d492837423ccee76e4e670e980b6f"), 0),
                                new TxOut(Money.FromUnit(1, MoneyUnit.BTC), "a914d388706006374eb728135014c9cad72e5dcd72fe87".ToScript()));

            var scriptCoin = coin.ToScriptCoin(redeem);

            var builder = new TransactionBuilder();

            builder.AddCoins(scriptCoin);
            builder.Send(OpenAssetsHelper.ParseAddress("mj5FEqrC2P4FjFNfX8q3eZ4UABWUcRNy9r"), Money.FromUnit(0.5M, MoneyUnit.BTC));
            builder.SetChange(coin.ScriptPubKey);
            builder.SendFees(Money.FromUnit(0.0001M, MoneyUnit.BTC));

            builder.AddKeys(pk1, pk2);
            var tr = builder.BuildTransaction(true);

            //await Broadcast(tr);
        }
Beispiel #4
0
        private async Task TransferOneDirection(TransactionBuilder builder, TransactionBuildContext context,
                                                BitcoinAddress @from, decimal amount, IAsset asset, BitcoinAddress to, bool addDust = true, bool sendDust = false)
        {
            var fromStr = from.ToString();

            if (OpenAssetsHelper.IsBitcoin(asset.Id))
            {
                var coins   = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(fromStr)).ToList();
                var balance = coins.Cast <Coin>().Select(o => o.Amount).DefaultIfEmpty().Sum(o => o?.ToDecimal(MoneyUnit.BTC) ?? 0);
                if (sendDust && balance > amount &&
                    balance - amount < new TxOut(Money.Zero, from).GetDustThreshold(builder.StandardTransactionPolicy.MinRelayTxFee).ToDecimal(MoneyUnit.BTC))
                {
                    amount = balance;
                }
                await _transactionBuildHelper.SendWithChange(builder, context, coins, to, new Money(amount, MoneyUnit.BTC),
                                                             from, addDust);
            }
            else
            {
                var assetIdObj  = new BitcoinAssetId(asset.BlockChainAssetId, _connectionParams.Network).AssetId;
                var assetAmount = new AssetMoney(assetIdObj, amount, asset.MultiplierPower);

                var coins = (await _bitcoinOutputsService.GetColoredUnspentOutputs(fromStr, assetIdObj)).ToList();
                _transactionBuildHelper.SendAssetWithChange(builder, context, coins, to, assetAmount, @from);
            }
        }
Beispiel #5
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);
            }
        }
        public async Task <PrivateBccTransferResponse> GetPrivateTransfer([FromQuery] string sourceAddress, [FromQuery] string destinationAddress, [FromQuery] decimal fee)
        {
            var result = await _bccTransactionService.CreatePrivateTransfer(OpenAssetsHelper.ParseAddress(sourceAddress),
                                                                            OpenAssetsHelper.ParseAddress(destinationAddress), fee);

            return(new PrivateBccTransferResponse
            {
                Transaction = result.TransactionHex,
                Outputs = result.Outputs
            });
        }
Beispiel #7
0
        private async Task ValidateAddress(string address, bool checkOffchain = true)
        {
            var bitcoinAddres = OpenAssetsHelper.ParseAddress(address);

            if (bitcoinAddres == null)
            {
                throw new BackendException($"Invalid Address provided: {address}", ErrorCode.InvalidAddress);
            }
            if (checkOffchain && await _offchainService.HasChannel(address))
            {
                throw new BackendException("Address was used in offchain", ErrorCode.AddressUsedInOffchain);
            }
        }
        public async Task Save(string address, IEnumerable <ICoin> coins)
        {
            try
            {
                var str = Serializer.ToString(coins, OpenAssetsHelper.ParseAddress(address).Network);

                await _storage.SaveBlobAsync(BlobContainer, $"{address}_{DateTime.UtcNow:yyyy-MM-dd_HH-mm-ss.fff}.txt", Encoding.UTF8.GetBytes(str));
            }
            // ReSharper disable once EmptyGeneralCatchClause
            catch (Exception)
            {
            }
        }
Beispiel #9
0
        private Task GenerateColorOutputs(string assetId)
        {
            return(Retry.Try(async() =>
            {
                var asset = await _assetRepostory.GetItemAsync(assetId);
                var setting = await GetAssetSetting(assetId);
                var hotWallet = OpenAssetsHelper.ParseAddress(setting.HotWallet);

                var assetIdObj = new BitcoinAssetId(asset.BlockChainAssetId).AssetId;

                var outputs = await _bitcoinOutputsService.GetColoredUnspentOutputs(setting.HotWallet, assetIdObj, 0, false);

                var balance = outputs.Aggregate(new AssetMoney(assetIdObj, 0), (accum, coin) => accum + coin.Amount);
                var outputSize = new AssetMoney(assetIdObj, setting.OutputSize, asset.MultiplierPower);


                var changeBalance = new AssetMoney(assetIdObj);
                if (setting.ChangeWallet != setting.HotWallet && !string.IsNullOrEmpty(setting.ChangeWallet))
                {
                    var changeOutputs = await _bitcoinOutputsService.GetColoredUnspentOutputs(setting.ChangeWallet, assetIdObj, 0, false);
                    changeBalance = changeOutputs.Aggregate(new AssetMoney(assetIdObj, 0), (accum, coin) => accum + coin.Amount);
                }

                if ((balance + changeBalance).ToDecimal(asset.MultiplierPower) < setting.MinBalance)
                {
                    await SendBalanceNotifications(assetId, setting.HotWallet, setting.MinBalance);
                }

                var existingCoinsCount = outputs.Count(o => o.Amount <= outputSize && o.Amount.Quantity > outputSize.Quantity / 2);

                if (existingCoinsCount > setting.MinOutputsCount)
                {
                    return;
                }

                var generateCnt = setting.MaxOutputsCount - existingCoinsCount;

                var coins = outputs.Where(o => o.Amount > outputSize * 2).ToList();

                balance = coins.Aggregate(new AssetMoney(assetIdObj, 0), (accum, coin) => accum + coin.Amount);

                generateCnt = Math.Min(generateCnt, (int)(balance.Quantity / outputSize.Quantity));
                if (generateCnt == 0)
                {
                    return;
                }

                await GenerateOutputs(generateCnt, coins, hotWallet, outputSize, asset, setting);
            }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _logger));
        }
Beispiel #10
0
        public async Task <CreateTransactionResponse> GetTransferFromSegwitWallet(BitcoinAddress source, Guid transactionId)
        {
            var assetSetting = await _assetSettingCache.GetItemAsync("BTC");

            var asset = await _assetRepository.GetItemAsync("BTC");

            var hotWallet = OpenAssetsHelper.ParseAddress(!string.IsNullOrEmpty(assetSetting.ChangeWallet) ? assetSetting.ChangeWallet : assetSetting.HotWallet);
            var context   = _transactionBuildContextFactory.Create(_connectionParams.Network);
            var lowVolume = new Money((decimal)asset.LowVolumeAmount, MoneyUnit.BTC);

            return(await context.Build(async() =>
            {
                var outputs = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(source.ToString())).OfType <Coin>()
                              .Where(o => o.Amount >= lowVolume).ToList();
                if (!outputs.Any())
                {
                    throw new BackendException($"Address {source} has not unspent outputs", ErrorCode.NoCoinsFound);
                }

                var totalAmount = new Money(outputs.Sum(o => o.Amount));

                var builder = new TransactionBuilder();
                builder.DustPrevention = false;
                builder.AddCoins(outputs);
                builder.Send(hotWallet, totalAmount);
                builder.SubtractFees();

                builder.SendEstimatedFees(await _feeProvider.GetFeeRate());

                builder.SetChange(hotWallet);

                var tx = builder.BuildTransaction(true);

                _transactionBuildHelper.AggregateOutputs(tx);

                if (tx.Outputs[0].Value <= tx.Outputs[0].GetDustThreshold(builder.StandardTransactionPolicy.MinRelayTxFee))
                {
                    throw new BackendException($"Address {source} balance is too low", ErrorCode.NoCoinsFound);
                }

                await _spentOutputService.SaveSpentOutputs(transactionId, tx);

                await SaveNewOutputs(transactionId, tx, context);

                return new CreateTransactionResponse(tx.ToHex(), transactionId);
            }));
        }
        public async Task SendToWitnessAddress()
        {
            var sourceAddr = OpenAssetsHelper.ParseAddress("mj5FEqrC2P4FjFNfX8q3eZ4UABWUcRNy9r");
            var addr       = OpenAssetsHelper.ParseAddress("tb1q2xvc2c503h95sm8nu5wyj68xee23su5wt46au5ztdsa9neqs424qh8kxal");
            var coin       = new Coin(new OutPoint(uint256.Parse("1fcedb863194c3c31f133e09c509e54b2cb40ef0a651a41a23d534301eb57af0"), 1),
                                      new TxOut(Money.FromUnit(0.5M, MoneyUnit.BTC), sourceAddr));
            var key     = Key.Parse("93586ks3uwSAgJ6q3He4CkuXeVg1N4syvszP514TitfcA9mXjVo");
            var builder = new TransactionBuilder();

            builder.AddCoins(coin);
            builder.SetChange(sourceAddr);
            builder.SendFees(Money.FromUnit(0.0001M, MoneyUnit.BTC));
            builder.Send(addr, Money.FromUnit(0.2M, MoneyUnit.BTC));
            builder.AddKeys(key);
            var tr = builder.BuildTransaction(true);
            //await Broadcast(tr);
        }
        private async Task <decimal> SendToMultisig(BitcoinAddress @from, BitcoinAddress toMultisig, IAsset assetEntity, TransactionBuilder builder, TransactionBuildContext context, decimal amount)
        {
            if (OpenAssetsHelper.IsBitcoin(assetEntity.Id))
            {
                Money sendAmount;
                var   unspentOutputs = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(from.ToString())).ToList();

                if (amount < 0)
                {
                    sendAmount = unspentOutputs.OfType <Coin>().DefaultIfEmpty().Sum(o => o.Amount);
                }
                else
                {
                    sendAmount = Money.FromUnit(amount, MoneyUnit.BTC);
                }

                if (sendAmount > 0)
                {
                    _transactionBuildHelper.SendWithChange(builder, context, unspentOutputs, toMultisig, sendAmount, from);
                }

                return(sendAmount.ToDecimal(MoneyUnit.BTC));
            }
            else
            {
                var  asset = new BitcoinAssetId(assetEntity.BlockChainAssetId, _connectionParams.Network).AssetId;
                long sendAmount;

                var unspentOutputs = (await _bitcoinOutputsService.GetColoredUnspentOutputs(from.ToString(), asset)).ToList();
                if (amount < 0)
                {
                    sendAmount = unspentOutputs.Sum(o => o.Amount.Quantity);
                }
                else
                {
                    sendAmount = new AssetMoney(asset, amount, assetEntity.MultiplierPower).Quantity;
                }
                if (sendAmount > 0)
                {
                    _transactionBuildHelper.SendAssetWithChange(builder, context, unspentOutputs,
                                                                toMultisig, new AssetMoney(asset, sendAmount), @from);
                }

                return(new AssetMoney(asset, sendAmount).ToDecimal(assetEntity.MultiplierPower));
            }
        }
Beispiel #13
0
        private Task GenerateBtcOutputs()
        {
            return(Retry.Try(async() =>
            {
                var setting = await GetAssetSetting("BTC");
                var hotWallet = OpenAssetsHelper.ParseAddress(setting.HotWallet);

                var outputs = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(setting.HotWallet, 0, false)).Cast <Coin>().ToList();

                var balance = new Money(outputs.DefaultIfEmpty().Sum(o => o?.Amount ?? Money.Zero));
                var outputSize = new Money(setting.OutputSize, MoneyUnit.BTC);

                Money changeBalance = Money.Zero;
                if (setting.ChangeWallet != setting.HotWallet && !string.IsNullOrEmpty(setting.ChangeWallet))
                {
                    var changeOutputs = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(setting.ChangeWallet, 0, false)).Cast <Coin>().ToList();
                    changeBalance = new Money(changeOutputs.DefaultIfEmpty().Sum(o => o?.Amount ?? Money.Zero));
                }

                if ((balance + changeBalance).ToDecimal(MoneyUnit.BTC) < setting.MinBalance)
                {
                    await SendBalanceNotifications("BTC", setting.HotWallet, setting.MinBalance);
                }


                var existingCoinsCount = outputs.Count(o => o.Amount <= outputSize && o.Amount > outputSize / 2);

                if (existingCoinsCount > setting.MinOutputsCount)
                {
                    return;
                }

                var generateCnt = setting.MaxOutputsCount - existingCoinsCount;

                var coins = outputs.Where(o => o.Amount > outputSize * 2).ToList();

                balance = coins.DefaultIfEmpty().Sum(o => o?.Amount ?? Money.Zero);

                generateCnt = Math.Min(generateCnt, (int)(balance / outputSize));
                if (generateCnt == 0)
                {
                    return;
                }
                await GenerateOutputs(generateCnt, coins, hotWallet, outputSize, await _assetRepostory.GetItemAsync("BTC"), setting);
            }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _logger));
        }
        private ICoin FindCoin(Transaction tr, string multisig, string walletRedeemScript, decimal amount, IAsset asset)
        {
            if (OpenAssetsHelper.IsBitcoin(asset.Id))
            {
                var money = new Money(amount, MoneyUnit.BTC);
                return(tr.Outputs.AsCoins().FirstOrDefault(o => o.Amount == money &&
                                                           o.ScriptPubKey.GetDestinationAddress(_connectionParams.Network).ToString() == multisig));
            }
            var  assetMoney = new AssetMoney(new BitcoinAssetId(asset.BlockChainAssetId), amount, asset.MultiplierPower);
            uint markerPosition;
            var  marker = ColorMarker.Get(tr, out markerPosition);
            var  found  = tr.Outputs.AsIndexedOutputs()
                          .FirstOrDefault(o => o.TxOut.ScriptPubKey.GetDestinationAddress(_connectionParams.Network)?.ToString() == multisig &&
                                          o.N > markerPosition && marker.Quantities[o.N - markerPosition - 1] == (ulong)assetMoney.Quantity);

            return(found?.ToCoin().ToScriptCoin(new Script(walletRedeemScript)).ToColoredCoin(assetMoney));
        }
Beispiel #15
0
        public async Task <IActionResult> Cashout([FromBody] CashoutRequest model)
        {
            model.DestinationAddress = model.DestinationAddress.Trim('\n', ' ', '\t');

            if (model.Amount <= 0)
            {
                throw new BackendException("Amount can't be less or equal to zero", ErrorCode.BadInputParameter);
            }

            await ValidateAddress(model.DestinationAddress, false);

            var asset = await _assetRepository.GetItemAsync(model.Asset);

            if (asset == null)
            {
                throw new BackendException("Provided asset is missing in database", ErrorCode.AssetNotFound);
            }

            var transactionId = await _builder.AddTransactionId(model.TransactionId, $"Cashout: {model.ToJson()}");

            if (OpenAssetsHelper.IsBitcoin(model.Asset))
            {
                await _cashoutRequestRepository.CreateCashoutRequest(transactionId, model.Amount, model.DestinationAddress);
            }
            else
            {
                var assetSetting = await _assetSettingCache.GetItemAsync(asset.Id);

                var hotWallet = !string.IsNullOrEmpty(assetSetting.ChangeWallet)
                    ? assetSetting.ChangeWallet
                    : assetSetting.HotWallet;

                await _transactionQueueWriter.AddCommand(transactionId, TransactionCommandType.Transfer, new TransferCommand
                {
                    Amount             = model.Amount,
                    SourceAddress      = hotWallet,
                    Asset              = model.Asset,
                    DestinationAddress = model.DestinationAddress
                }.ToJson());
            }
            return(Ok(new TransactionIdResponse
            {
                TransactionId = transactionId
            }));
        }
Beispiel #16
0
        public async Task <IActionResult> CreateMultipleTransfer([FromBody] MultipleTransferRequest model)
        {
            foreach (var source in model.Sources)
            {
                await ValidateAddress(source.Address);
            }

            if (model.FixedFee.GetValueOrDefault() < 0)
            {
                throw new BackendException("Fixed fee must be greater than or equal to zero", ErrorCode.BadInputParameter);
            }

            var destAddress = OpenAssetsHelper.ParseAddress(model.Destination);

            if (destAddress == null)
            {
                throw new BackendException("Invalid destination address provided", ErrorCode.InvalidAddress);
            }

            var asset = await _assetRepository.GetAssetById(model.Asset);

            if (asset == null)
            {
                throw new BackendException("Provided asset is missing in database", ErrorCode.AssetNotFound);
            }

            var transactionId = await _builder.AddTransactionId(model.TransactionId, $"MultipleTransfer: {model.ToJson()}");

            var response = await _builder.GetMultipleTransferTransaction(destAddress, asset,
                                                                         model.Sources.ToDictionary(x => x.Address, x => x.Amount), model.FeeRate, model.FixedFee.GetValueOrDefault(), transactionId);

            var fullSignedHex = await _signatureApiProvider.SignTransaction(response.Transaction);

            await _transactionBlobStorage.AddOrReplaceTransaction(transactionId, TransactionBlobType.Signed, fullSignedHex);

            var fullSigned = new Transaction(fullSignedHex);

            await _broadcastService.BroadcastTransaction(transactionId, fullSigned, useHandlers : false);

            return(Ok(new TransactionIdAndHashResponse
            {
                TransactionId = transactionId,
                Hash = fullSigned.GetHash().ToString()
            }));
        }
Beispiel #17
0
        public async Task <decimal> SendWithChange(TransactionBuilder builder, TransactionBuildContext context, List <ICoin> coins, IDestination destination, Money amount, IDestination changeDestination, bool addDust = true)
        {
            if (amount.Satoshi <= 0)
            {
                throw new BackendException("Amount can't be less or equal to zero", ErrorCode.BadInputParameter);
            }

            Action throwError = () =>
            {
                throw new BackendException($"The sum of total applicable outputs is less than the required: {amount.Satoshi} satoshis.", ErrorCode.NotEnoughBitcoinAvailable);
            };

            var selectedCoins = OpenAssetsHelper.CoinSelect(coins, amount);

            if (selectedCoins == null)
            {
                throwError();
            }

            var orderedCoins = selectedCoins.OrderBy(o => o.Amount).ToList();
            var sendAmount   = Money.Zero;
            var cnt          = 0;

            while (sendAmount < amount && cnt < orderedCoins.Count)
            {
                sendAmount += orderedCoins[cnt].TxOut.Value;
                cnt++;
            }
            if (sendAmount < amount)
            {
                throwError();
            }

            context.AddCoins(orderedCoins.Take(cnt));
            builder.AddCoins(orderedCoins.Take(cnt));

            var sent = await Send(builder, context, destination, amount, addDust);

            if (sendAmount - amount > 0)
            {
                await Send(builder, context, changeDestination, sendAmount - amount, addDust);
            }
            return(sent);
        }
Beispiel #18
0
        public void SendAssetWithChange(TransactionBuilder builder, TransactionBuildContext context, List <ColoredCoin> coins, IDestination destination, AssetMoney amount,
                                        IDestination changeDestination)
        {
            if (amount.Quantity <= 0)
            {
                throw new BackendException("Amount can't be less or equal to zero", ErrorCode.BadInputParameter);
            }

            Action throwError = () =>
            {
                throw new BackendException($"The sum of total applicable outputs is less than the required: {amount.Quantity} {amount.Id}.", ErrorCode.NotEnoughAssetAvailable);
            };

            var selectedCoins = OpenAssetsHelper.CoinSelect(coins, amount);

            if (selectedCoins == null)
            {
                throwError();
            }

            var orderedCounts = selectedCoins.Cast <ColoredCoin>().OrderBy(o => o.Amount).ToList();
            var sendAmount    = new AssetMoney(amount.Id);
            var cnt           = 0;

            while (sendAmount < amount && cnt < orderedCounts.Count)
            {
                sendAmount += orderedCounts[cnt].Amount;
                cnt++;
            }

            if (sendAmount < amount)
            {
                throwError();
            }

            builder.AddCoins(orderedCounts.Take(cnt));
            context.AddCoins(orderedCounts.Take(cnt));
            builder.SendAsset(destination, amount);

            if ((sendAmount - amount).Quantity > 0)
            {
                builder.SendAsset(changeDestination, sendAmount - amount);
            }
        }
        public async Task SpendCommitmemtByMultisig(ICommitment commitment, ICoin spendingCoin, string destination)
        {
            TransactionBuildContext context = new TransactionBuildContext(_connectionParams.Network, _pregeneratedOutputsQueueFactory);

            var destinationAddress = BitcoinAddress.Create(destination);

            await context.Build(async() =>
            {
                TransactionBuilder builder = new TransactionBuilder();
                builder.AddCoins(spendingCoin);
                if (OpenAssetsHelper.IsBitcoin(commitment.AssetId))
                {
                    builder.Send(destinationAddress, spendingCoin.Amount);
                }
                else
                {
                    builder.SendAsset(destinationAddress, ((ColoredCoin)spendingCoin).Amount);
                }
                await _transactionBuildHelper.AddFee(builder, context);

                var tr = builder.BuildTransaction(false);

                var scriptParams = new OffchainScriptParams
                {
                    IsMultisig   = true,
                    RedeemScript = commitment.LockedScript.ToScript().ToBytes(),
                    Pushes       = new[] { new byte[0], new byte[0], new byte[0] }
                };

                tr.Inputs[0].ScriptSig = OffchainScriptCommitmentTemplate.GenerateScriptSig(scriptParams);

                var signed = await _signatureApiProvider.SignTransaction(tr.ToHex());

                var signedTr = new Transaction(signed);
                var id       = Guid.NewGuid();
                await _rpcBitcoinClient.BroadcastTransaction(signedTr, id);

                await _lykkeTransactionBuilderService.SaveSpentOutputs(id, signedTr);

                return(Task.CompletedTask);
            });
        }
        private async Task TransferOneDirection(TransactionBuilder builder, TransactionBuildContext context,
                                                BitcoinAddress @from, decimal amount, IAsset asset, BitcoinAddress to)
        {
            var fromStr = from.ToString();

            if (OpenAssetsHelper.IsBitcoin(asset.Id))
            {
                var coins = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(fromStr)).ToList();
                _transactionBuildHelper.SendWithChange(builder, context, coins, to, new Money(amount, MoneyUnit.BTC),
                                                       from);
            }
            else
            {
                var assetIdObj  = new BitcoinAssetId(asset.BlockChainAssetId, _connectionParams.Network).AssetId;
                var assetAmount = new AssetMoney(assetIdObj, amount, asset.MultiplierPower);

                var coins = (await _bitcoinOutputsService.GetColoredUnspentOutputs(fromStr, assetIdObj)).ToList();
                _transactionBuildHelper.SendAssetWithChange(builder, context, coins, to, assetAmount, @from);
            }
        }
        public async Task <CommandHandlingResult> Handle(StartCashoutCommand command,
                                                         IEventPublisher eventPublisher)
        {
            var address = command.Address.Trim('\n', ' ', '\t');

            try
            {
                var transactionId = await _builder.AddTransactionId(command.Id, $"Cashout: {command.ToJson()}");

                if (OpenAssetsHelper.IsBitcoin(command.AssetId))
                {
                    await _cashoutRequestRepository.CreateCashoutRequest(transactionId, command.Amount, address);
                }
                else
                {
                    var assetSetting = await _assetSettingCache.GetItemAsync(command.AssetId);

                    var hotWallet = !string.IsNullOrEmpty(assetSetting.ChangeWallet)
                        ? assetSetting.ChangeWallet
                        : assetSetting.HotWallet;

                    await _transactionQueueWriter.AddCommand(transactionId, TransactionCommandType.Transfer, new TransferCommand
                    {
                        Amount             = command.Amount,
                        SourceAddress      = hotWallet,
                        Asset              = command.AssetId,
                        DestinationAddress = command.Address
                    }.ToJson());
                }
            }
            catch (BackendException ex) when(ex.Code == ErrorCode.DuplicateTransactionId)
            {
                _logger.WriteWarning(nameof(CashinCommandHandler), nameof(Handle), $"Duplicated id: {command.Id}");
            }

            return(CommandHandlingResult.Ok());
        }
Beispiel #22
0
        public Task <CreateTransactionResponse> GetDestroyTransaction(BitcoinAddress bitcoinAddres, decimal modelAmount, IAsset asset, Guid transactionId)
        {
            return(Retry.Try(async() =>
            {
                var context = _transactionBuildContextFactory.Create(_connectionParams.Network);

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

                    var assetId = new BitcoinAssetId(asset.BlockChainAssetId, _connectionParams.Network).AssetId;
                    var coins =
                        (await _bitcoinOutputsService.GetColoredUnspentOutputs(bitcoinAddres.ToString(), assetId)).ToList();

                    builder.SetChange(bitcoinAddres, ChangeType.Colored);
                    builder.AddCoins(coins);

                    var assetMoney = new AssetMoney(assetId, modelAmount, asset.MultiplierPower);

                    var changeAddress = BitcoinAddress.Create(_baseSettings.ChangeAddress, _connectionParams.Network);

                    _transactionBuildHelper.SendAssetWithChange(builder, context, coins, changeAddress, assetMoney, bitcoinAddres);

                    await _transactionBuildHelper.AddFee(builder, context);

                    var tx = builder.BuildTransaction(true);

                    OpenAssetsHelper.DestroyColorCoin(tx, assetMoney, changeAddress, _connectionParams.Network);

                    await _spentOutputService.SaveSpentOutputs(transactionId, tx);

                    await SaveNewOutputs(transactionId, tx, context);

                    return new CreateTransactionResponse(tx.ToHex(), transactionId);
                });
            }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log));
        }
Beispiel #23
0
        public async Task Test()
        {
            var hotWallet    = OpenAssetsHelper.ParseAddress("mj5FEqrC2P4FjFNfX8q3eZ4UABWUcRNy9r");
            var changeWallet = OpenAssetsHelper.ParseAddress("minog49vnNVuWK5kSs5Ut1iPyNZcR1i7he");

            var hotWalletOutputs = GenerateOutputs(5);

            var hotWalletBalance = new Money(hotWalletOutputs.Select(o => o.Amount).DefaultIfEmpty().Sum(o => o?.Satoshi ?? 0));

            var maxFeeForTransaction = Money.FromUnit(0.099M, MoneyUnit.BTC);

            var selectedCoins = new List <Coin>();

            var _feeProvider            = Config.Services.GetService <IFeeProvider>();
            var _transactionBuildHelper = Config.Services.GetService <ITransactionBuildHelper>();
            var cashoutRequests         = (GenerateCashoutRequest(200)).ToList();

            var maxInputsCount = maxFeeForTransaction.Satoshi / (await _feeProvider.GetFeeRate()).GetFee(Constants.InputSize).Satoshi;

            do
            {
                if (selectedCoins.Count > maxInputsCount && cashoutRequests.Count > 1)
                {
                    cashoutRequests = cashoutRequests.Take(cashoutRequests.Count - 1).ToList();
                    selectedCoins.Clear();
                }
                else
                if (selectedCoins.Count > 0)
                {
                    break;
                }

                var totalAmount = Money.FromUnit(cashoutRequests.Select(o => o.Amount).Sum(), MoneyUnit.BTC);

                if (hotWalletBalance < totalAmount + maxFeeForTransaction)
                {
                    var         changeBalance       = Money.Zero;
                    List <Coin> changeWalletOutputs = new List <Coin>();
                    if (hotWallet != changeWallet)
                    {
                        changeWalletOutputs = GenerateOutputs(1).ToList();
                        changeBalance       = new Money(changeWalletOutputs.Select(o => o.Amount).DefaultIfEmpty().Sum(o => o?.Satoshi ?? 0));
                    }
                    if (changeBalance + hotWalletBalance >= totalAmount + maxFeeForTransaction)
                    {
                        selectedCoins.AddRange(hotWalletOutputs);
                        selectedCoins.AddRange(OpenAssetsHelper
                                               .CoinSelect(changeWalletOutputs, totalAmount + maxFeeForTransaction - hotWalletBalance).OfType <Coin>());
                    }
                    else
                    {
                        selectedCoins.AddRange(hotWalletOutputs);
                        selectedCoins.AddRange(changeWalletOutputs);

                        int cashoutsUsedCount = 0;
                        var cashoutsAmount    = await _transactionBuildHelper.CalcFee(selectedCoins.Count, cashoutRequests.Count + 1);

                        foreach (var cashoutRequest in cashoutRequests)
                        {
                            cashoutsAmount += Money.FromUnit(cashoutRequest.Amount, MoneyUnit.BTC);
                            if (cashoutsAmount > hotWalletBalance + changeBalance)
                            {
                                break;
                            }
                            cashoutsUsedCount++;
                        }
                        if (cashoutsUsedCount == 0)
                        {
                            throw new BackendException("Not enough bitcoin available", ErrorCode.NotEnoughBitcoinAvailable);
                        }
                        cashoutRequests = cashoutRequests.Take(cashoutsUsedCount).ToList();
                    }
                }
                else
                {
                    selectedCoins.AddRange(OpenAssetsHelper.CoinSelect(hotWalletOutputs, totalAmount + maxFeeForTransaction).OfType <Coin>());
                }
            } while (true);

            var selectedCoinsAmount = new Money(selectedCoins.Sum(o => o.Amount));
            var sendAmount          = new Money(cashoutRequests.Sum(o => o.Amount), MoneyUnit.BTC);
            var builder             = new TransactionBuilder();

            builder.AddCoins(selectedCoins);
            foreach (var cashout in cashoutRequests)
            {
                var amount = Money.FromUnit(cashout.Amount, MoneyUnit.BTC);
                builder.Send(OpenAssetsHelper.ParseAddress(cashout.DestinationAddress), amount);
            }

            builder.Send(changeWallet, selectedCoinsAmount - sendAmount);

            builder.SubtractFees();
            builder.SendEstimatedFees(await _feeProvider.GetFeeRate());
            builder.SetChange(changeWallet);

            var tx = builder.BuildTransaction(true);

            _transactionBuildHelper.AggregateOutputs(tx);
        }
Beispiel #24
0
 private async Task SaveNewOutputs(Guid transactionId, Transaction tr, TransactionBuildContext context)
 {
     var coloredOutputs = OpenAssetsHelper.OrderBasedColoringOutputs(tr, context);
     await _broadcastedOutputRepository.InsertOutputs(
         coloredOutputs.Select(o => new BroadcastedOutput(o, transactionId, _connectionParams.Network)).ToList());
 }
Beispiel #25
0
        public Task <CreateMultiCashoutTransactionResult> GetMultipleCashoutTransaction(List <ICashoutRequest> cashoutRequests, Guid transactionId)
        {
            return(Retry.Try(async() =>
            {
                var context = _transactionBuildContextFactory.Create(_connectionParams.Network);
                var assetSetting = await _assetSettingCache.GetItemAsync("BTC");

                var hotWallet = OpenAssetsHelper.ParseAddress(assetSetting.HotWallet);
                var changeWallet = OpenAssetsHelper.ParseAddress(string.IsNullOrWhiteSpace(assetSetting.ChangeWallet)
                    ? assetSetting.HotWallet
                    : assetSetting.ChangeWallet);

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

                    var hotWalletOutputs = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(hotWallet.ToString())).OfType <Coin>().ToList();

                    var hotWalletBalance = new Money(hotWalletOutputs.Select(o => o.Amount).DefaultIfEmpty().Sum(o => o?.Satoshi ?? 0));

                    var maxFeeForTransaction = Money.FromUnit(0.099M, MoneyUnit.BTC);

                    var selectedCoins = new List <Coin>();

                    var maxInputsCount = maxFeeForTransaction.Satoshi / (await _feeProvider.GetFeeRate()).GetFee(Constants.InputSize).Satoshi;
                    var tryCount = 100;
                    do
                    {
                        if (selectedCoins.Count > maxInputsCount && cashoutRequests.Count > 1)
                        {
                            cashoutRequests = cashoutRequests.Take(cashoutRequests.Count - 1).ToList();
                            selectedCoins.Clear();
                        }
                        else
                        if (selectedCoins.Count > 0)
                        {
                            break;
                        }

                        var totalAmount = Money.FromUnit(cashoutRequests.Select(o => o.Amount).Sum(), MoneyUnit.BTC);

                        if (hotWalletBalance < totalAmount + maxFeeForTransaction)
                        {
                            var changeBalance = Money.Zero;
                            List <Coin> changeWalletOutputs = new List <Coin>();
                            if (hotWallet != changeWallet)
                            {
                                changeWalletOutputs = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(changeWallet.ToString()))
                                                      .OfType <Coin>().ToList();
                                changeBalance = new Money(changeWalletOutputs.Select(o => o.Amount).DefaultIfEmpty().Sum(o => o?.Satoshi ?? 0));
                            }
                            if (changeBalance + hotWalletBalance >= totalAmount + maxFeeForTransaction)
                            {
                                selectedCoins.AddRange(hotWalletOutputs);
                                selectedCoins.AddRange(OpenAssetsHelper
                                                       .CoinSelect(changeWalletOutputs, totalAmount + maxFeeForTransaction - hotWalletBalance).OfType <Coin>());
                            }
                            else
                            {
                                selectedCoins.AddRange(hotWalletOutputs);
                                selectedCoins.AddRange(changeWalletOutputs);

                                int cashoutsUsedCount = 0;
                                var cashoutsAmount = await _transactionBuildHelper.CalcFee(selectedCoins.Count, cashoutRequests.Count + 1);
                                foreach (var cashoutRequest in cashoutRequests)
                                {
                                    cashoutsAmount += Money.FromUnit(cashoutRequest.Amount, MoneyUnit.BTC);
                                    if (cashoutsAmount > hotWalletBalance + changeBalance)
                                    {
                                        break;
                                    }
                                    cashoutsUsedCount++;
                                }
                                if (cashoutsUsedCount == 0)
                                {
                                    throw new BackendException("Not enough bitcoin available", ErrorCode.NotEnoughBitcoinAvailable);
                                }
                                cashoutRequests = cashoutRequests.Take(cashoutsUsedCount).ToList();
                            }

                            if (changeWallet != hotWallet)
                            {
                                if (assetSetting.Asset == Constants.DefaultAssetSetting)
                                {
                                    assetSetting = await CreateAssetSetting("BTC", assetSetting);
                                }

                                if (assetSetting.Asset != Constants.DefaultAssetSetting)
                                {
                                    await _assetSettingRepository.UpdateHotWallet(assetSetting.Asset, assetSetting.ChangeWallet);
                                }
                            }
                        }
                        else
                        {
                            selectedCoins.AddRange(OpenAssetsHelper.CoinSelect(hotWalletOutputs, totalAmount + maxFeeForTransaction).OfType <Coin>());
                        }
                    } while (tryCount-- > 0);

                    var selectedCoinsAmount = new Money(selectedCoins.Sum(o => o.Amount));
                    var sendAmount = new Money(cashoutRequests.Sum(o => o.Amount), MoneyUnit.BTC);

                    builder.AddCoins(selectedCoins);
                    foreach (var cashout in cashoutRequests)
                    {
                        var amount = Money.FromUnit(cashout.Amount, MoneyUnit.BTC);
                        builder.Send(OpenAssetsHelper.ParseAddress(cashout.DestinationAddress), amount);
                    }

                    builder.Send(changeWallet, selectedCoinsAmount - sendAmount);
                    builder.SubtractFees();
                    builder.SendEstimatedFees(await _feeProvider.GetFeeRate());
                    builder.SetChange(changeWallet);

                    var tx = builder.BuildTransaction(true);
                    _transactionBuildHelper.AggregateOutputs(tx);

                    await _broadcastedOutputRepository.InsertOutputs(
                        tx.Outputs.AsCoins().Where(o => o.ScriptPubKey == changeWallet.ScriptPubKey).Select(o =>
                                                                                                            new BroadcastedOutput(o, transactionId, _connectionParams.Network)).ToList());

                    await _spentOutputService.SaveSpentOutputs(transactionId, tx);

                    return new CreateMultiCashoutTransactionResult
                    {
                        Transaction = tx,
                        UsedRequests = cashoutRequests
                    };
                });
            }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log));
        }
Beispiel #26
0
        public Task <CreateTransactionResponse> GetMultipleTransferTransaction(BitcoinAddress destination, IAsset asset, Dictionary <string, decimal> transferAddresses, int feeRate, decimal fixedFee, Guid transactionId)
        {
            return(Retry.Try(async() =>
            {
                var context = _transactionBuildContextFactory.Create(_connectionParams.Network);

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

                    builder.SetChange(destination, ChangeType.Uncolored);

                    foreach (var transferAddress in transferAddresses)
                    {
                        var source = OpenAssetsHelper.ParseAddress(transferAddress.Key);
                        await TransferOneDirection(builder, context, source, transferAddress.Value, asset, destination);
                    }

                    Transaction buildedTransaction;
                    try
                    {
                        buildedTransaction = builder.BuildTransaction(true);
                    }
                    catch (NotEnoughFundsException ex)
                    {
                        if (ex.Missing is Money)
                        {
                            var missingAmount = ((Money)ex.Missing).Satoshi;
                            _transactionBuildHelper.AddFakeInput(builder, new Money(missingAmount, MoneyUnit.Satoshi));
                            buildedTransaction = builder.BuildTransaction(true);
                        }
                        else
                        {
                            throw;
                        }
                    }

                    _transactionBuildHelper.RemoveFakeInput(buildedTransaction);

                    _transactionBuildHelper.AggregateOutputs(buildedTransaction);

                    var fee = fixedFee > 0 ? Money.FromUnit(fixedFee, MoneyUnit.BTC) : await _transactionBuildHelper.CalcFee(buildedTransaction, feeRate);

                    foreach (var output in buildedTransaction.Outputs)
                    {
                        if (output.ScriptPubKey.GetDestinationAddress(_connectionParams.Network) == destination)
                        {
                            if (output.Value <= fee)
                            {
                                throw new BackendException("Amount is lower than fee", ErrorCode.NotEnoughBitcoinAvailable);
                            }
                            output.Value -= fee;
                            break;
                        }
                    }

                    await _spentOutputService.SaveSpentOutputs(transactionId, buildedTransaction);

                    await SaveNewOutputs(transactionId, buildedTransaction, context);

                    return new CreateTransactionResponse(buildedTransaction.ToHex(), transactionId);
                });
            }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log));
        }
Beispiel #27
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));
        }
 public Task OnMessage(BccTransferCommand command)
 {
     return(_bccTransactionService.Transfer(OpenAssetsHelper.ParseAddress(command.SourceAddress),
                                            OpenAssetsHelper.ParseAddress(command.DestinationAddress), command.Amount));
 }
        public async Task ProcessMessage(TransactionQueueMessage message, QueueTriggeringContext context)
        {
            CreateTransactionResponse transactionResponse;

            try
            {
                var request = await _signRequestRepository.GetSignRequest(message.TransactionId);

                if (request?.Invalidated == true)
                {
                    context.MoveMessageToPoison(message.ToJson());
                    return;
                }

                switch (message.Type)
                {
                case TransactionCommandType.Issue:
                    var issue = message.Command.DeserializeJson <IssueCommand>();
                    transactionResponse = await _lykkeTransactionBuilderService.GetIssueTransaction(
                        OpenAssetsHelper.ParseAddress(issue.Address),
                        issue.Amount, await _assetRepository.GetAssetById(issue.Asset), message.TransactionId);

                    break;

                case TransactionCommandType.Transfer:
                    var transfer = message.Command.DeserializeJson <TransferCommand>();
                    transactionResponse = await _lykkeTransactionBuilderService.GetTransferTransaction(
                        OpenAssetsHelper.ParseAddress(transfer.SourceAddress),
                        OpenAssetsHelper.ParseAddress(transfer.DestinationAddress), transfer.Amount,
                        await _assetRepository.GetAssetById(transfer.Asset), message.TransactionId);

                    break;

                case TransactionCommandType.TransferAll:
                    var transferAll = message.Command.DeserializeJson <TransferAllCommand>();
                    transactionResponse = await _lykkeTransactionBuilderService.GetTransferAllTransaction(
                        OpenAssetsHelper.ParseAddress(transferAll.SourceAddress),
                        OpenAssetsHelper.ParseAddress(transferAll.DestinationAddress),
                        message.TransactionId);

                    break;

                case TransactionCommandType.Swap:
                    var swap = message.Command.DeserializeJson <SwapCommand>();
                    transactionResponse = await _lykkeTransactionBuilderService.GetSwapTransaction(
                        OpenAssetsHelper.ParseAddress(swap.MultisigCustomer1),
                        swap.Amount1,
                        await _assetRepository.GetAssetById(swap.Asset1),
                        OpenAssetsHelper.ParseAddress(swap.MultisigCustomer2),
                        swap.Amount2,
                        await _assetRepository.GetAssetById(swap.Asset2),
                        message.TransactionId);

                    break;

                case TransactionCommandType.Destroy:
                    var destroy = message.Command.DeserializeJson <DestroyCommand>();
                    transactionResponse = await _lykkeTransactionBuilderService.GetDestroyTransaction(
                        OpenAssetsHelper.ParseAddress(destroy.Address),
                        destroy.Amount,
                        await _assetRepository.GetAssetById(destroy.Asset),
                        message.TransactionId);

                    break;

                case TransactionCommandType.SegwitTransferToHotwallet:
                    var segwitTransfer = message.Command.DeserializeJson <SegwitTransferCommand>();
                    transactionResponse = await _lykkeTransactionBuilderService.GetTransferFromSegwitWallet(
                        OpenAssetsHelper.ParseAddress(segwitTransfer.SourceAddress), message.TransactionId);

                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            catch (BackendException e) when(e.Code == ErrorCode.NoCoinsFound)
            {
                if (message.Type == TransactionCommandType.SegwitTransferToHotwallet)
                {
                    _cqrsEngine.PublishEvent(new CashinCompletedEvent {
                        OperationId = message.TransactionId
                    }, BitcoinBoundedContext.Name);
                }
                return;
            }
            catch (BackendException e)
            {
                if (e.Text != message.LastError)
                {
                    await _logger.WriteWarningAsync("TransactionBuildFunction", "ProcessMessage", $"Id: [{message.TransactionId}], cmd: [{message.Command}]", e.Text);
                }

                message.LastError = e.Text;
                if (message.DequeueCount >= _settings.MaxDequeueCount)
                {
                    context.MoveMessageToPoison(message.ToJson());
                }
                else
                {
                    message.DequeueCount++;
                    context.MoveMessageToEnd(message.ToJson());
                    context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200);
                }
                return;
            }

            await _transactionBlobStorage.AddOrReplaceTransaction(message.TransactionId, TransactionBlobType.Initial, transactionResponse.Transaction);


            await _queueFactory(Constants.BroadcastingQueue).PutRawMessageAsync(new BroadcastingTransaction
            {
                TransactionCommandType = message.Type,
                TransactionId          = message.TransactionId
            }.ToJson());
        }
Beispiel #30
0
        private IEnumerable <Coin> GenerateOutputs(int cnt)
        {
            var rand = new Random(rndINit);

            for (int i = 0; i < cnt; i++)
            {
                yield return(new Coin(new OutPoint(uint256.One, _N++), new TxOut(rand.Next(2700, 500000000), OpenAssetsHelper.ParseAddress("mj5FEqrC2P4FjFNfX8q3eZ4UABWUcRNy9r"))));
            }
        }