Пример #1
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);
            }
        }
        public async Task <IEnumerable <(string address, decimal amount, string assetId)> > ReadBalance(IEnumerable <Asset> assets, string address)
        {
            var(btcAddress, isColored) = GetAddress(address);

            BalanceSummary sum;

            try
            {
                _client.Colored = isColored;
                sum             = await _client.GetBalanceSummary(btcAddress);
            }
            catch (Exception e)
            {
                throw new RetryNeededException(e);
            }

            var result = new List <(string address, decimal amount, string assetId)>();

            foreach (var asset in assets.Where(p => !string.IsNullOrEmpty(p.BlockChainAssetId)))
            {
                var btcAssetId = new BitcoinAssetId(asset.BlockChainAssetId, _client.Network);
                var amount     = sum.Spendable.Assets?.SingleOrDefault(p => p.Asset == btcAssetId)?.Quantity ?? 0;

                result.Add((address, amount * (decimal)asset.Multiplier(), asset.Id));
            }

            if (assets.Any(p => p.Id == "BTC"))
            {
                result.Add((address, (decimal)sum.Spendable.Amount.ToUnit(MoneyUnit.BTC), "BTC"));
            }

            return(result);
        }
Пример #3
0
 /// <summary>
 /// Get the quantity of asset in this balance change
 /// </summary>
 /// <param name="assetId">The asset id, if null, returns uncolored satoshi</param>
 /// <returns></returns>
 public IMoney GetAssetAmount(BitcoinAssetId assetId)
 {
     if (assetId == null)
     {
         return(Amount);
     }
     return(GetAssetAmount(assetId.AssetId));
 }
        public Task <CreateTransactionResponse> GetDestroyTransaction(BitcoinAddress bitcoinAddres, decimal modelAmount, IAsset asset, Guid transactionId)
        {
            return(Retry.Try(async() =>
            {
                var context = new TransactionBuildContext(_connectionParams.Network, _pregeneratedOutputsQueueFactory);

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

                    uint markerPosition;
                    var colorMarker = ColorMarker.Get(tx, out markerPosition);

                    for (var i = 0; i < colorMarker.Quantities.Length; i++)
                    {
                        if ((long)colorMarker.Quantities[i] == assetMoney.Quantity &&
                            tx.Outputs[i + 1].ScriptPubKey.GetDestinationAddress(_connectionParams.Network) == changeAddress)
                        {
                            colorMarker.Quantities[i] = 0;
                            break;
                        }
                    }

                    tx.Outputs[markerPosition].ScriptPubKey = colorMarker.GetScript();

                    await SaveSpentOutputs(transactionId, tx);

                    await _signRequestRepository.InsertTransactionId(transactionId);

                    await SaveNewOutputs(transactionId, tx, context);

                    return new CreateTransactionResponse(tx.ToHex(), transactionId);
                });
            }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log));
        }
Пример #5
0
        public static void Execute()
        {
            // spend the 10 assets we received on the address “nico”. (IssuingAsset.cs)
            // Here is the coin I want to spend, we need to build a ColoredCoin.

            /*
             * {
             * "transactionId": "ba6218ca0c900edd03103c68121721bc966e247626e630b33811b0d977aa9613",
             * "index": 0,
             * "value": 600,
             * "scriptPubKey": "76a914356facdac5f5bcae995d13e667bb5864fd1e7d5988ac",
             * "redeemScript": null,
             * "assetId": "AVAVfLSb1KZf9tJzrUVpktjxKUXGxUTD4e",
             * "quantity": 10
             * }
             */
            Keys keys = JsonConvert.DeserializeObject <Keys>(File.ReadAllText(@"Keys.json"));
            //  instantiate such Colored Coin in code:
            Network btcTestNet     = Network.TestNet;
            string  txnId          = "ba6218ca0c900edd03103c68121721bc966e247626e630b33811b0d977aa9613";
            string  txnFee         = "733e124863e88c6d94ae67d306cd7a0bdb2c010a4720bf290a06965c53d51a8c";
            string  scriptPubKey_0 = "OP_DUP OP_HASH160 38ef9bce9b02fb8da15926c9a3f6a1b00be949f0 OP_EQUALVERIFY OP_CHECKSIG";
            string  scriptPubKey_1 = "OP_DUP OP_HASH160 38ef9bce9b02fb8da15926c9a3f6a1b00be949f0 OP_EQUALVERIFY OP_CHECKSIG";

            BitcoinAddress bobAddress      = BitcoinAddress.Create(keys.bob.Address, btcTestNet);
            BitcoinSecret  alicePrivateKey = new BitcoinSecret(keys.alice.PrivateKey);

            Coin coin = new Coin(fromTxHash: new uint256(txnId),
                                 fromOutputIndex: 0,
                                 amount: Money.Satoshis(546),
                                 scriptPubKey: new Script(scriptPubKey_0));

            Coin forFees = new Coin(fromTxHash: new uint256(txnFee),
                                    fromOutputIndex: 0,
                                    amount: Money.Satoshis(479454),
                                    scriptPubKey: new Script(scriptPubKey_1));

            BitcoinAssetId assetId = (new AssetId(bobAddress)).GetWif(btcTestNet);
            ColoredCoin    colored = coin.ToColoredCoin(assetId, 10);

            TransactionBuilder builder = new TransactionBuilder();
            Transaction        tx      = builder.AddKeys(alicePrivateKey)
                                         .AddCoins(colored, forFees)
                                         .SendAsset(bobAddress, new AssetMoney(assetId, 10))
                                         .SendFees(Money.Coins(0.0001m))
                                         .SetChange(alicePrivateKey.GetAddress())
                                         .BuildTransaction(sign: true);

            Console.WriteLine("Transaction: " + tx);
            Console.WriteLine("Verify Txn: " + builder.Verify(tx));
        }
Пример #6
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));
        }
Пример #7
0
        public async Task TestBroadcastCommitment()
        {
            var rpcClient = Config.Services.GetService <IRpcBitcoinClient>();
            var trService = Config.Services.GetService <IBitcoinTransactionService>();
            var helper    = Config.Services.GetService <ITransactionBuildHelper>();

            var hex =
                "01000000030fc8d9f48344cb9496af8b77c24b6d36bff11041d37b8ee0ac5c8c8aa63e0292020000004b00000047522102593e745d594696f503acab8d8a20fe6a9b97e9f63873e124ac79113dd20a03ae210379be0eea5380e3b03ae31efcfb19eba41fa6e6fdd0dc3329d4d658eca25168f452aeffffffff399b06f441db3581576da93139700d176bd726f54e05f51ace6dfedf68ada123040000004b000000475221025a4cd2d3e5e12142df245a8bc24fa9ac0a6cb412a205ca3d31b1fef891126cbf21020f0efab8a2845a8030b3a6eb535577fd38364f0897ca32ebd956223653cc6da252aeffffffff6735d37552e63c0d1386c3bd40d687546c917326502aafbb31f8018909e41a943300000000ffffffff0600000000000000000d6a0b4f41010004310538b006008c0a00000000000017a914745d46755d712e8ec662a30f70c4830261750932878c0a00000000000017a914da617d341e35dde727780f277129df8538be7f54878c0a00000000000017a914da617d341e35dde727780f277129df8538be7f54878c0a00000000000017a914745d46755d712e8ec662a30f70c483026175093287d0200000000000001976a9144104da83ef80ce0b2e5843230f489f1455e98ef688ac00000000";
            var tr = new Transaction(hex);

            var source            = BitcoinAddress.Create("mj5FEqrC2P4FjFNfX8q3eZ4UABWUcRNy9r");
            var dest              = BitcoinAddress.Create("2N3QKLu6mmH9ZrvRQdf5pNg1txeTpwLhjVK");
            var bitcoinOutService = Config.Services.GetService <IBitcoinOutputsService>();
            var assetRepo         = Config.Services.GetService <IAssetRepository>();
            var usd = await assetRepo.GetAssetById("USD");

            var lkk = await assetRepo.GetAssetById("LKK");


            var usdID = new BitcoinAssetId(usd.BlockChainAssetId).AssetId;

            var lkkID    = new BitcoinAssetId(lkk.BlockChainAssetId).AssetId;
            var usdCoins = (await bitcoinOutService.GetColoredUnspentOutputs("mj5FEqrC2P4FjFNfX8q3eZ4UABWUcRNy9r",
                                                                             usdID)).ToList();
            var lkkCoins = (await bitcoinOutService.GetColoredUnspentOutputs("mj5FEqrC2P4FjFNfX8q3eZ4UABWUcRNy9r",
                                                                             lkkID)).ToList();

            TransactionBuilder      builder = new TransactionBuilder();
            TransactionBuildContext context = new TransactionBuildContext(Network.TestNet, null, null);

            helper.SendAssetWithChange(builder, context, usdCoins, dest, new AssetMoney(usdID, 100), source);
            helper.SendAssetWithChange(builder, context, lkkCoins, dest, new AssetMoney(lkkID, 10000), source);
            await helper.AddFee(builder, context);

            var tx = builder.BuildTransaction(true).ToHex();

            //var multisigScriptOps = PayToMultiSigTemplate.Instance.GenerateScriptPubKey
            //(2,
            //    new PubKey[]
            //    {
            //        new PubKey("03ebcc2d675d17c5b5e250307cb0189bfc5adf6809bfd3c2823a2884dbbcaec58b"),
            //        new PubKey("02235060021d06f6c4e766574b0374dde8d050a0a036ee52cde04608a87eebc3e1")
            //    }).ToOps().ToList();

            //var redeem =
            //    "2 03ebcc2d675d17c5b5e250307cb0189bfc5adf6809bfd3c2823a2884dbbcaec58b 02235060021d06f6c4e766574b0374dde8d050a0a036ee52cde04608a87eebc3e1 2 OP_CHECKMULTISIG";
            //var pubkeys = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(new Script(redeem)).PubKeys;
        }
        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));
            }
        }
Пример #9
0
        static void Main(string[] args)
        {
            var coin = new Coin(
                fromTxHash: new uint256("668c63369dfb6f6ebcd07aa36a4f1e9f252f8b3f976fcc84d540e03e54cdcc0a"),
                fromOutputIndex: 0,
                amount: Money.Satoshis(2730),
                scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914aef515f8874638687187da27bd008c3e7f5c68c188ac")));
            BitcoinAssetId assetId = new BitcoinAssetId("oPvD7Nn3eKHkWkwwG4i2HRjVJEhv4d6SEW");
            ColoredCoin    colored = coin.ToColoredCoin(assetId, 21000000);

            var book       = BitcoinAddress.Create("mi7TqrUCAKZ3pFuRaLZvFWhjrktbcyZf54");
            var nicoSecret = new BitcoinSecret("cUQo9VhkwZ8zMUJA8cFEY5MLHiQJMhcGKk9SUbRVDCB3yveUq66z");
            var nico       = nicoSecret.GetAddress();       //mwU3UJ1VXX3GxKKQHdscw1TvWSrMKdtymR

            var forFees = new Coin(
                fromTxHash: new uint256("a0c35a09e52af1a116d1e1233b952511ca7cae3aef5e0ea888b77167cb22e0fc"),
                fromOutputIndex: 0,
                amount: Money.Satoshis(300000000),
                scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914aef515f8874638687187da27bd008c3e7f5c68c188ac")));

            TransactionBuilder builder = new TransactionBuilder();
            var tx = builder
                     .AddKeys(nicoSecret)
                     .AddCoins(colored, forFees)
                     .SendAsset(book, new AssetMoney(assetId, 100000))
                     .SetChange(nico)
                     .SendFees(Money.Coins(0.001m))
                     .BuildTransaction(true);

            Console.WriteLine(tx);
            Console.WriteLine(builder.Verify(tx));

            var client = new QBitNinjaClient(Network.TestNet);
            BroadcastResponse broadcastResponse = client.Broadcast(tx).Result;

            if (!broadcastResponse.Success)
            {
                Console.WriteLine("ErrorCode: " + broadcastResponse.Error.ErrorCode);
                Console.WriteLine("Error message: " + broadcastResponse.Error.Reason);
            }
            else
            {
                Console.WriteLine("Success!");
            }
        }
Пример #10
0
        public Task <CreateTransactionResponse> GetIssueTransaction(BitcoinAddress bitcoinAddres, decimal amount, IAsset asset, Guid transactionId)
        {
            return(Retry.Try(async() =>
            {
                var context = _transactionBuildContextFactory.Create(_connectionParams.Network);

                return await context.Build(async() =>
                {
                    var builder = new TransactionBuilder();
                    var queue = _pregeneratedOutputsQueueFactory.Create(asset.BlockChainAssetId);

                    var coin = await queue.DequeueCoin();

                    try
                    {
                        var issueCoin = new IssuanceCoin(coin)
                        {
                            DefinitionUrl = new Uri(asset.DefinitionUrl)
                        };

                        var assetId = new BitcoinAssetId(asset.BlockChainAssetId, _connectionParams.Network).AssetId;

                        builder.AddCoins(issueCoin)
                        .IssueAsset(bitcoinAddres, new AssetMoney(assetId, amount, asset.MultiplierPower));
                        context.IssueAsset(assetId);

                        await _transactionBuildHelper.AddFee(builder, context);

                        var buildedTransaction = builder.BuildTransaction(true);

                        await _spentOutputService.SaveSpentOutputs(transactionId, buildedTransaction);

                        await SaveNewOutputs(transactionId, buildedTransaction, context);

                        return new CreateTransactionResponse(buildedTransaction.ToHex(), transactionId);
                    }
                    catch (Exception)
                    {
                        await queue.EnqueueOutputs(coin);
                        throw;
                    }
                });
            }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log));
        }
        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);
            }
        }
Пример #12
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));
        }
Пример #13
0
 public ColoredCoin ToColoredCoin(BitcoinAssetId asset, ulong quantity)
 {
     return(ToColoredCoin(new AssetMoney(asset, quantity)));
 }
Пример #14
0
        static void Main()
        {
            var coin = new Coin(
                fromTxHash: new uint256("eb49a599c749c82d824caf9dd69c4e359261d49bbb0b9d6dc18c59bc9214e43b"),
                fromOutputIndex: 0,
                amount: Money.Satoshis(2000000),
                scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914c81e8e7b7ffca043b088a992795b15887c96159288ac")));

            var issuance = new IssuanceCoin(coin);


            var nico = BitcoinAddress.Create("15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe");
            //var bookKey = new BitcoinSecret("???????");
            var bookKey = new Key().GetBitcoinSecret(Network.Main); // Just a fake key in order to not get an exception

            var builder = new TransactionBuilder();

            Transaction tx = builder
                             .AddKeys(bookKey)
                             .AddCoins(issuance)
                             .IssueAsset(nico, new AssetMoney(issuance.AssetId, quantity: 10))
                             .SendFees(Money.Coins(0.0001m))
                             .SetChange(bookKey.GetAddress())
                             .BuildTransaction(true);

            Console.WriteLine(tx);

            Console.WriteLine(builder.Verify(tx));

            nico = BitcoinAddress.Create("15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe");
            Console.WriteLine(nico.ToColoredAddress());


            /* QBITNINJA */

            //var client = new QBitNinjaClient(Network.Main);
            //BroadcastResponse broadcastResponse = client.Broadcast(tx).Result;

            //if (!broadcastResponse.Success)
            //{
            //    Console.WriteLine("ErrorCode: " + broadcastResponse.Error.ErrorCode);
            //    Console.WriteLine("Error message: " + broadcastResponse.Error.Reason);
            //}
            //else
            //{
            //    Console.WriteLine("Success!");
            //}

            /* OR BITCOIN CORE */

            //using (var node = Node.ConnectToLocal(Network.Main)) //Connect to the node
            //{
            //    node.VersionHandshake(); //Say hello
            //                             //Advertize your transaction (send just the hash)
            //    node.SendMessage(new InvPayload(InventoryType.MSG_TX, tx.GetHash()));
            //    //Send it
            //    node.SendMessage(new TxPayload(tx));
            //    Thread.Sleep(500); //Wait a bit
            //}


            coin = new Coin(
                fromTxHash: new uint256("fa6db7a2e478f3a8a0d1a77456ca5c9fa593e49fd0cf65c7e349e5a4cbe58842"),
                fromOutputIndex: 0,
                amount: Money.Satoshis(2000000),
                scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914356facdac5f5bcae995d13e667bb5864fd1e7d5988ac")));
            BitcoinAssetId assetId = new BitcoinAssetId("AVAVfLSb1KZf9tJzrUVpktjxKUXGxUTD4e");
            ColoredCoin    colored = coin.ToColoredCoin(assetId, 10);

            var book       = BitcoinAddress.Create("1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB");
            var nicoSecret = new BitcoinSecret("??????????");

            nico = nicoSecret.GetAddress(); //15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe

            var forFees = new Coin(
                fromTxHash: new uint256("7f296e96ec3525511b836ace0377a9fbb723a47bdfb07c6bc3a6f2a0c23eba26"),
                fromOutputIndex: 0,
                amount: Money.Satoshis(4425000),
                scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914356facdac5f5bcae995d13e667bb5864fd1e7d5988ac")));

            builder = new TransactionBuilder();
            tx      = builder
                      .AddKeys(nicoSecret)
                      .AddCoins(colored, forFees)
                      .SendAsset(book, new AssetMoney(assetId, 10))
                      .SetChange(nico)
                      .SendFees(Money.Coins(0.0001m))
                      .BuildTransaction(true);
            Console.WriteLine(tx);



            Console.ReadLine();
        }
Пример #15
0
 public AssetBalanceChange GetAsset(BitcoinAssetId asset)
 {
     return(GetAsset(asset.AssetId));
 }
Пример #16
0
 public IEnumerable <ColoredCoin> WhereColored(BitcoinAssetId assetId)
 {
     return(WhereColored(assetId.AssetId));
 }
Пример #17
0
        private async Task GenerateIssueAllowedCoins()
        {
            foreach (var asset in await _assetRepostory.Values())
            {
                if (OpenAssetsHelper.IsBitcoin(asset.Id) || OpenAssetsHelper.IsLkk(asset.Id) || !asset.IssueAllowed)
                {
                    continue;
                }

                try
                {
                    var setting = await GetAssetSetting(asset.Id);

                    if (setting.HotWallet != setting.ChangeWallet)
                    {
                        continue;
                    }

                    var hotWallet = OpenAssetsHelper.ParseAddress(setting.HotWallet);
                    var assetId   = new BitcoinAssetId(asset.BlockChainAssetId).AssetId;

                    var coins = await _bitcoinOutputsService.GetColoredUnspentOutputs(setting.HotWallet, assetId);

                    var outputSize = new AssetMoney(assetId, setting.OutputSize, asset.MultiplierPower);

                    await _logger.WriteInfoAsync("GenerateOffchainOutputsFunction", "GenerateIssueAllowedCoins", "AssetId " + asset.Id, "Start process");

                    var existingCoinsCount = coins.Count(o => o.Amount <= outputSize && o.Amount * 2 > outputSize);

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

                    var generateCnt = setting.MaxOutputsCount - existingCoinsCount;
                    var generated   = 0;
                    while (generated < generateCnt)
                    {
                        var outputsCount = Math.Min(setting.MaxOutputsCountInTx, generateCnt - generated);

                        var context = _transactionBuildContextFactory.Create(_connectionParams.Network);

                        await context.Build(async() =>
                        {
                            var builder = new TransactionBuilder();
                            var queue   = _pregeneratedOutputsQueueFactory.Create(asset.BlockChainAssetId);
                            var coin    = await queue.DequeueCoin();

                            try
                            {
                                var issueCoin = new IssuanceCoin(coin)
                                {
                                    DefinitionUrl = new Uri(asset.DefinitionUrl)
                                };

                                builder.AddCoins(issueCoin);

                                for (var i = 0; i < outputsCount; i++)
                                {
                                    builder.IssueAsset(hotWallet, outputSize);
                                }
                                context.IssueAsset(assetId);
                                await _transactionBuildHelper.AddFee(builder, context);

                                var tr = builder.BuildTransaction(true);

                                await SignAndBroadcastTransaction(tr, context);

                                return("");
                            }
                            catch (Exception)
                            {
                                await queue.EnqueueOutputs(coin);

                                throw;
                            }
                        });

                        generated += outputsCount;
                    }
                }
                catch (Exception ex)
                {
                    await _logger.WriteWarningAsync("GenerateOffchainOutputsFunction", "GenerateIssueAllowedCoins", "AssetId " + asset.Id, ex);
                }
                finally
                {
                    await _logger.WriteInfoAsync("GenerateOffchainOutputsFunction", "GenerateIssueAllowedCoins", "AssetId " + asset.Id, "End process");
                }
            }
        }
        private CreationCommitmentResult CreateCommitmentTransaction(IWalletAddress wallet, PubKey lockedPubKey, PubKey unlockedPubKey, PubKey revokePubKey, PubKey multisigPairPubKey,
                                                                     IAsset asset, decimal lockedAmount, decimal unlockedAmount, string channelTr)
        {
            var multisig  = new BitcoinScriptAddress(wallet.MultisigAddress, _connectionParams.Network);
            var channel   = new Transaction(channelTr);
            var spendCoin = FindCoin(channel, multisig.ToString(), wallet.RedeemScript, lockedAmount + unlockedAmount, asset);

            if (spendCoin == null)
            {
                throw new BackendException($"Not found output in setup channel with amount {lockedAmount + unlockedAmount}", ErrorCode.NoCoinsFound);
            }

            TransactionBuilder builder = new TransactionBuilder();

            builder.AddCoins(spendCoin);
            long additionalBtc = 0;
            var  script        = CreateOffchainScript(multisigPairPubKey, revokePubKey, lockedPubKey);

            var unlockedAddress = unlockedPubKey.GetAddress(_connectionParams.Network);
            var lockedAddress   = script.GetScriptAddress(_connectionParams.Network);

            if (OpenAssetsHelper.IsBitcoin(asset.Id))
            {
                if (unlockedAmount > 0)
                {
                    builder.Send(unlockedAddress, new Money(unlockedAmount, MoneyUnit.BTC));
                }
                if (lockedAmount > 0)
                {
                    builder.Send(lockedAddress, new Money(lockedAmount, MoneyUnit.BTC));
                }
            }
            else
            {
                var sendAmount = ((ColoredCoin)spendCoin).Bearer.Amount;
                var dustAmount = 0L;
                var assetId    = new BitcoinAssetId(asset.BlockChainAssetId).AssetId;
                if (unlockedAmount > 0)
                {
                    builder.SendAsset(unlockedAddress, new AssetMoney(assetId, unlockedAmount, asset.MultiplierPower));
                    dustAmount += new TxOut(Money.Zero, unlockedAddress.ScriptPubKey).GetDustThreshold(builder.StandardTransactionPolicy.MinRelayTxFee);
                }
                if (lockedAmount > 0)
                {
                    builder.Send(lockedAddress, new AssetMoney(assetId, lockedAmount, asset.MultiplierPower));
                    dustAmount += new TxOut(Money.Zero, lockedAddress.ScriptPubKey).GetDustThreshold(builder.StandardTransactionPolicy.MinRelayTxFee);
                }
                additionalBtc = dustAmount - sendAmount;
            }

            var fakeFee = new Money(1, MoneyUnit.BTC);

            var fakeAmount = additionalBtc + fakeFee;

            builder.SendFees(fakeFee);

            _transactionBuildHelper.AddFakeInput(builder, fakeAmount);
            var tr = builder.BuildTransaction(true);

            _transactionBuildHelper.RemoveFakeInput(tr);
            return(new CreationCommitmentResult(tr, lockedAddress.ToString(), script.ToHex()));
        }
Пример #19
0
        static void Main()
        {
            //==========================================================================================
            //Other types of asset

            //In the previous chapters, we have seen several types of ownership. You have seen all the different kind of ownership and proof of ownership, and understand how Bitcoin can be coded to invent new kinds of ownership.



            //==========================================================================================
            //Colored Coins

            //So until now, you have seen how to exchange Bitcoins on the network. However you can use the Bitcoin network for transferring and exchanging any type of assets.
            //We call such assets “colored coins”.
            //As far as the Blockchain is concerned, there is no difference between a Coin and a Colored Coin.
            //A colored coin is represented by a standard TxOut.Most of the time, such TxOut have a residual Bitcoin value called “Dust”. (600 satoshi)
            //The real value of a colored coin reside in what the issuer of the coin will exchange against it.


            //Since a colored coin is nothing but a standard coin with special meaning, it follows that all what you saw about proof of ownership and the TransactionBuilder stays true.You can transfer a colored coin with exactly the same rules as before.
            //As far as the blockchain is concerned, a Colored Coin is a Coin like all others.
            //You can represent several type of asset with a colored coin: company shares, bonds, stocks, votes.
            //But no matter what type of asset you will represent, there will always have a trust relationship between the issuer of the asset and the owner.
            //If you own some company share, then the company might decide to not send you dividends.
            //If you own a bond, then the bank might not exchange it at maturity.
            //However, a violation of contract might be automatically detected with the help of Ricardian Contracts.
            //A Ricardian Contract is a contract signed by the issuer with the rights attached to the asset. Such contract can be not only human-readable (PDF) but also structured (JSON), so tools can automatically prove any violation.
            //The issuer can’t change the ricardian contract attached to an asset.
            //The Blockchain is only the transport medium of a financial instrument.
            //The innovation is that everyone can create and transfer its own asset without intermediary, whereas traditional asset transport mediums (clearing houses), are either heavily regulated or purposefully kept secret, and closed to the general public.
            //Open Asset is the name of the protocol created by Flavien Charlon that describes how to transfer and emit colored coins on the Blockchain.
            //Other protocols exist, but Open Asset is the most easy and flexible and the only one supported by NBitcoin.
            //In the rest of the book, I will not go in the details of the Open Asset protocol, the GitHub page of the specification is better suited to this need.



            //===========================================================================================
            //Section. Issuing an Asset

            //===========================================================================================
            //Section1. Objective

            //For the purpose of this exercise, I will emit BlockchainProgramming coins.
            //You get one of these BlockchainProgramming coins for every 0.004 bitcoin you send me.
            //One more if you add some kind words.
            //Furthermore, this is a great opportunity to make it to the Hall of The Makers.
            //Let’s see how I would code such feature.



            //==========================================================================================
            //Section2. Issuance Coin
            //In Open Asset, the Asset ID is derived from the issuer's ScriptPubKey.
            //If you want to issue a Colored Coin, you need to prove ownership of such ScriptPubKey.And the only way to do that on the Blockchain is by spending a coin belonging to such ScriptPubKey.
            //The coin that you will choose to spend for issuing colored coins is called “Issuance Coin” in NBitcoin.
            //I want to emit an Asset from this book's bitcoin address: 1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB.
            //Take a look at my balance by some blockchain explorers, I decided to use the following coin(2,000,000 satoshis) for issuing assets.

            //{
            //       "transactionId": "eb49a599c749c82d824caf9dd69c4e359261d49bbb0b9d6dc18c59bc9214e43b",
            //       "index": 0,
            //       "value": 2000000,
            //       "scriptPubKey": "76a914c81e8e7b7ffca043b088a992795b15887c96159288ac",
            //       "redeemScript": null
            //}


            //Here is how to create my issuance coin:
            var coin = new Coin(
                fromTxHash: new uint256("eb49a599c749c82d824caf9dd69c4e359261d49bbb0b9d6dc18c59bc9214e43b"),
                fromOutputIndex: 0,
                amount: Money.Satoshis(2000000),
                scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914c81e8e7b7ffca043b088a992795b15887c96159288ac")));

            var issuance = new IssuanceCoin(coin);

            //Now I need to build transaction and sign the transaction with the help of the TransactionBuilder.
            var nico = BitcoinAddress.Create("15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe");
            //var bookKey = new BitcoinSecret("???????");
            var bookKey = new Key().GetBitcoinSecret(Network.Main); // Just a fake key in order to not get an exception

            TransactionBuilder builder = new TransactionBuilder();

            Transaction tx = builder
                             .AddKeys(bookKey)
                             .AddCoins(issuance)
                             .IssueAsset(nico, new AssetMoney(issuance.AssetId, quantity: 10))
                             .SendFees(Money.Coins(0.0001m))
                             .SetChange(bookKey.GetAddress())
                             .BuildTransaction(true);

            Console.WriteLine(tx);
            //Output:
            //{
            //  …
            //  "out": [
            //    {
            //      "value": "0.00000600",
            //      "scriptPubKey": "OP_DUP OP_HASH160 356facdac5f5bcae995d13e667bb5864fd1e7d59 OP_EQUALVERIFY OP_CHECKSIG"
            //    },
            //    {
            //      "value": "0.01989400",
            //      "scriptPubKey": "OP_DUP OP_HASH160 c81e8e7b7ffca043b088a992795b15887c961592 OP_EQUALVERIFY OP_CHECKSIG"
            //    },
            //    {
            //      "value": "0.00000000",
            //      "scriptPubKey": "OP_RETURN 4f410100010a00"
            //    }
            //  ]
            //}

            //You can see it includes an OP_RETURN output. In fact, this is the location where information about colored coins are stuffed.
            //Here is the format of the data in the OP_RETURN.
            //Picture depiction:
            //IBitcoinSerializable. ColorMarker class. Of the class, properties and methods.



            //In our case, Quantities have only 10, which is the number of Asset I issued to nico. Metadata is arbitrary data. We will see that we can put an url that points to an “Asset Definition”.
            //An Asset Definition is a document that describes what the Asset is.It is optional, so we are not using it in our case. (We’ll come back later on it in the Ricardian Contract part.)
            //For more information check out the Open Asset Specification link.
            //After transaction verifications it is ready to be sent to the network.

            //Trasaction verification.
            Console.WriteLine(builder.Verify(tx));



            //=============================================================================================
            //Section3. With QBitNinja

            //We can do the same thing by a QBitNinja.
            //var client = new QBitNinjaClient(Network.Main);
            //BroadcastResponse broadcastResponse = client.Broadcast(tx).Result;

            //if (!broadcastResponse.Success)
            //{
            //    Console.WriteLine("ErrorCode: " + broadcastResponse.Error.ErrorCode);
            //    Console.WriteLine("Error message: " + broadcastResponse.Error.Reason);
            //}
            //else
            //{
            //    Console.WriteLine("Success!");
            //}


            //=============================================================================================
            //Section4. Or With local Bitcoin Core

            //We can do the same thing by a local Bitcoin Core.
            ////Connect to the node
            //using (var node = Node.ConnectToLocal(Network.Main))
            //{
            //    //Say hello
            //    node.VersionHandshake();
            //    //Advertize your transaction (send just the hash)
            //    node.SendMessage(new InvPayload(InventoryType.MSG_TX, tx.GetHash()));
            //    //Send it
            //    node.SendMessage(new TxPayload(tx));
            //    //Wait a bit
            //    Thread.Sleep(500);
            //}

            //My Bitcoin Wallet has both, the book address and the “Nico”'s address.
            //Picture depiction:



            //As you can see, Bitcoin Core only shows the 0.0001 BTC of fees I paid, and ignores the 2,000,000 satoshis coin because of a spam prevention feature.
            //This classical bitcoin wallet knows nothing about Colored Coins.
            //Worse: If a classical bitcoin wallet spends a colored coin, it will destroy the underlying asset and transfer only the bitcoin value of the TxOut. (200,000 satoshis)
            //For preventing a user from sending Colored Coin to a wallet that does not support it, Open Asset has its own address format, that only colored coin wallets understand.

            nico = BitcoinAddress.Create("15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe");
            Console.WriteLine(nico.ToColoredAddress());
            //Output:
            //akFqRqfdmAaXfPDmvQZVpcAQnQZmqrx4gcZ


            //Now, you can take a look on an Open Asset compatible wallet like Coinprism, and see my asset correctly detected:
            //Picture depiction:



            //As I have told you before, the Asset ID is derived from the issuer’s ScriptPubKey, here is how to get it in code:
            var book     = BitcoinAddress.Create("1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB");
            var assetId1 = new AssetId(book).GetWif(Network.Main);

            Console.WriteLine(assetId1); // AVAVfLSb1KZf9tJzrUVpktjxKUXGxUTD4e



            //=============================================================================================
            //Section. Transfer an Asset

            //So now, let’s imagine I sent you some BlockchainProgramming Coins.
            //How can you send me back the coins?
            //You need to build a ColoredCoin.
            //In the sample above, let’s say I want to spend the 10 assets I received on the address “nico”.
            //Here is the coin I want to spend:
            //{
            //  "transactionId": "fa6db7a2e478f3a8a0d1a77456ca5c9fa593e49fd0cf65c7e349e5a4cbe58842",
            //  "index": 0,
            //  "value": 600,
            //  "scriptPubKey": "76a914356facdac5f5bcae995d13e667bb5864fd1e7d5988ac",
            //  "redeemScript": null,
            //  "assetId": "AVAVfLSb1KZf9tJzrUVpktjxKUXGxUTD4e",
            //  "quantity": 10
            //}

            //Here is how to instantiate such Colored Coin in code:
            coin = new Coin(
                fromTxHash: new uint256("fa6db7a2e478f3a8a0d1a77456ca5c9fa593e49fd0cf65c7e349e5a4cbe58842"),
                fromOutputIndex: 0,
                amount: Money.Satoshis(600),
                scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914356facdac5f5bcae995d13e667bb5864fd1e7d5988ac")));
            BitcoinAssetId assetId = new BitcoinAssetId("AVAVfLSb1KZf9tJzrUVpktjxKUXGxUTD4e");
            ColoredCoin    colored = coin.ToColoredCoin(assetId, 10);


            //We will show you later how you can use some web services or custom code to get the coins more easily.
            //I also needed another coin(forFees), to pay the fees.
            //The asset transfer is actually very easy with the TransactionBuilder.
            var book1      = BitcoinAddress.Create("1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB");
            var nicoSecret = new BitcoinSecret("??????????");
            var nico1      = nicoSecret.GetAddress(); //15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe

            var forFees = new Coin(
                fromTxHash: new uint256("7f296e96ec3525511b836ace0377a9fbb723a47bdfb07c6bc3a6f2a0c23eba26"),
                fromOutputIndex: 0,
                amount: Money.Satoshis(4425000),
                scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914356facdac5f5bcae995d13e667bb5864fd1e7d5988ac")));

            builder = new TransactionBuilder();
            tx      = builder
                      .AddKeys(nicoSecret)
                      .AddCoins(colored, forFees)
                      .SendAsset(book1, new AssetMoney(assetId, 10))
                      .SetChange(nico1)
                      .SendFees(Money.Coins(0.0001m))
                      .BuildTransaction(true);
            Console.WriteLine(tx);
            //Output:
            //{
            //  ….
            //  "out": [
            //    {
            //      "value": "0.00000000",
            //      "scriptPubKey": "OP_RETURN 4f410100010a00"
            //    },
            //    {
            //      "value": "0.00000600",
            //      "scriptPubKey": "OP_DUP OP_HASH160 c81e8e7b7ffca043b088a992795b15887c961592 OP_EQUALVERIFY OP_CHECKSIG"
            //    },
            //    {
            //      "value": "0.04415000",
            //      "scriptPubKey": "OP_DUP OP_HASH160 356facdac5f5bcae995d13e667bb5864fd1e7d59 OP_EQUALVERIFY OP_CHECKSIG"
            //    }
            //  ]
            //}


            //Which basically succeed:
            //Picture depiction:
        }