Example #1
0
        internal async Task <GetTransactionResponse> JsonTransaction(uint256 txId, bool colored)
        {
            var client = Configuration.Indexer.CreateIndexerClient();
            var tx     = await client.GetTransactionAsync(true, colored, txId);

            if (tx == null || (tx.ColoredTransaction == null && colored) || tx.SpentCoins == null)
            {
                throw new HttpResponseException(new HttpResponseMessage
                {
                    StatusCode   = HttpStatusCode.NotFound,
                    ReasonPhrase = "Transaction not found"
                });
            }

            var response = new GetTransactionResponse()
            {
                TransactionId = tx.TransactionId,
                Transaction   = tx.Transaction,
                IsCoinbase    = tx.Transaction.IsCoinBase,
                Fees          = tx.Fees,
                Block         = FetchBlockInformation(tx.BlockIds),
                FirstSeen     = tx.FirstSeen
            };

            for (int i = 0; i < tx.Transaction.Outputs.Count; i++)
            {
                var   txout = tx.Transaction.Outputs[i];
                ICoin coin  = new Coin(new OutPoint(txId, i), txout);
                if (colored)
                {
                    var entry = tx.ColoredTransaction.GetColoredEntry((uint)i);
                    if (entry != null)
                    {
                        coin = new ColoredCoin(entry.Asset, (Coin)coin);
                    }
                }
                response.ReceivedCoins.Add(coin);
            }
            if (!response.IsCoinbase)
            {
                for (int i = 0; i < tx.Transaction.Inputs.Count; i++)
                {
                    ICoin coin = new Coin(tx.SpentCoins[i].OutPoint, tx.SpentCoins[i].TxOut);
                    if (colored)
                    {
                        var entry = tx.ColoredTransaction.Inputs.FirstOrDefault(ii => ii.Index == i);
                        if (entry != null)
                        {
                            coin = new ColoredCoin(entry.Asset, (Coin)coin);
                        }
                    }
                    response.SpentCoins.Add(coin);
                }
            }
            return(response);
        }
Example #2
0
 protected static ColoredCoin[] GenerateWalletColoredCoins(Transaction[] transactions, UniversalUnspentOutput[] usableOutputs,
                                                           string assetId)
 {
     ColoredCoin[] coins = new ColoredCoin[transactions.Length];
     for (int i = 0; i < transactions.Length; i++)
     {
         coins[i] = new ColoredCoin(new AssetMoney(new AssetId(new BitcoinAssetId(assetId)), (int)usableOutputs[i].GetAssetAmount()),
                                    new Coin(transactions[i], (uint)usableOutputs[i].GetOutputIndex()));
     }
     return(coins);
 }
Example #3
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));
        }
Example #4
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!");
            }
        }
Example #5
0
        public async Task <Tuple <ColoredCoin[], Coin[]> > GetColoredUnColoredCoins(UniversalUnspentOutput[] walletOutputs, string assetId)
        {
            ColoredCoin[] walletColoredCoins = new ColoredCoin[0];

            if (assetId != null)
            {
                var walletAssetOutputs        = GetWalletOutputsForAsset(walletOutputs, assetId);
                var walletColoredTransactions = await GetTransactionsHex(walletAssetOutputs);

                walletColoredCoins = GenerateWalletColoredCoins(walletColoredTransactions, walletAssetOutputs, assetId);
            }

            var walletUncoloredOutputs      = GetWalletOutputsUncolored(walletOutputs);
            var walletUncoloredTransactions = await GetTransactionsHex(walletUncoloredOutputs);

            var walletUncoloredCoins = GenerateWalletUnColoredCoins(walletUncoloredTransactions, walletUncoloredOutputs);

            return(new Tuple <ColoredCoin[], Coin[]>(walletColoredCoins, walletUncoloredCoins));
        }
Example #6
0
		public ColoredTransaction(Transaction tx, ColoredCoin[] spentCoins, Script issuanceScriptPubkey)
			: this(tx.GetHash(), tx, spentCoins, issuanceScriptPubkey)
		{

		}
Example #7
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();
        }
        void Start()
        {
            var powerCoin = new Key();
            var alice     = new Key();
            var bob       = new Key();
            var satoshi   = new Key();
            var init      = new Transaction()
            {
                Outputs =
                {
                    new TxOut(Money.Coins(1.0m), powerCoin),
                    new TxOut(Money.Coins(1.0m), alice),
                    new TxOut(Money.Coins(1.0m), bob),
                    new TxOut(Money.Coins(1.0m), satoshi),
                }
            };

            var repo = new NoSqlColoredTransactionRepository();

            repo.Transactions.Put(init);

            var issuance = GetCoins(init, powerCoin)
                           .Select(c => new IssuanceCoin(c))
                           .ToArray();

            var builder = new TransactionBuilder();
            var toAlice =
                builder
                .AddCoins(issuance)
                .AddKeys(powerCoin)
                .IssueAsset(alice, new AssetMoney(powerCoin, 2))
                .SetChange(powerCoin)
                .Then()
                .AddCoins(GetCoins(init, alice).ToArray())
                .AddKeys(alice)
                .Send(alice, Money.Coins(0.2m))
                .SetChange(alice)
                .BuildTransaction(true);

            repo.Transactions.Put(toAlice);

            var votingCoin = new Key();
            var init2      = new Transaction()
            {
                Outputs =
                {
                    new TxOut(Money.Coins(1.0m), votingCoin),
                }
            };

            repo.Transactions.Put(init2);

            issuance = GetCoins(init2, votingCoin).Select(c => new IssuanceCoin(c)).ToArray();
            builder  = new TransactionBuilder();
            var toVoters =
                builder
                .AddCoins(issuance)
                .AddKeys(votingCoin)
                .IssueAsset(alice, new AssetMoney(votingCoin, 1))
                .IssueAsset(satoshi, new AssetMoney(votingCoin, 1))
                .SetChange(votingCoin)
                .BuildTransaction(true);

            repo.Transactions.Put(toVoters);

            var aliceVotingCoin = ColoredCoin.Find(toVoters, repo)
                                  .Where(c => c.ScriptPubKey == alice.ScriptPubKey)
                                  .ToArray();

            builder = new TransactionBuilder();
            var toBob =
                builder
                .AddCoins(aliceVotingCoin)
                .AddKeys(alice)
                .SendAsset(bob, new AssetMoney(votingCoin, 1))
                .BuildTransaction(true);

            repo.Transactions.Put(toBob);

            var bobVotingCoin = ColoredCoin.Find(toVoters, repo)
                                .Where(c => c.ScriptPubKey == bob.ScriptPubKey)
                                .ToArray();

            builder = new TransactionBuilder();
            var vote =
                builder
                .AddCoins(bobVotingCoin)
                .AddKeys(bob)
                .SendAsset(BitcoinAddress.Create("1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN"),
                           new AssetMoney(votingCoin, 1))
                .BuildTransaction(true);

            issuance = GetCoins(init2, votingCoin).Select(c => new IssuanceCoin(c)).ToArray();
            issuance[0].DefinitionUrl = new Uri("http://boss.com/vote01.json");
            builder  = new TransactionBuilder();
            toVoters =
                builder
                .AddCoins(issuance)
                .AddKeys(votingCoin)
                .IssueAsset(alice, new AssetMoney(votingCoin, 1))
                .IssueAsset(satoshi, new AssetMoney(votingCoin, 1))
                .SetChange(votingCoin)
                .BuildTransaction(true);
            repo.Transactions.Put(toVoters);
        }
Example #9
0
        public static void Execute()
        {
            // NBitcoin allows you either to depend on a web service, either to provide
            // your own implementation for fetching the color of a Transaction

            // Let’s introduce two issuers: Silver and Gold. And three participants: Bob, Alice and Satoshi.
            // Let’s create a fake transaction that give some bitcoins to Silver, Gold and Satoshi.

            var gold     = new Key();
            var silver   = new Key();
            var goldId   = gold.PubKey.ScriptPubKey.Hash.ToAssetId();
            var silverId = silver.PubKey.ScriptPubKey.Hash.ToAssetId();

            var bob     = new Key();
            var alice   = new Key();
            var satoshi = new Key();

            var init = new Transaction()
            {
                Outputs = { new TxOut("1.0", gold),
                            new TxOut("1.0", silver),
                            new TxOut("1.0", satoshi) }
            };

            // In NBitcoin, the summary of color transfers and issuances is described by a class called
            // FetchColor, which will permit you to extract colored information
            // The trick when writing unit tests is to use an in memory IColoredTransactionRepository:
            var repo = new NoSqlColoredTransactionRepository();

            // we can put our init transaction inside.
            repo.Transactions.Put(init);
            // you can extract the color:
            ColoredTransaction color = ColoredTransaction.FetchColors(init, repo);

            Console.WriteLine("color: " + color);

            /*
             * {
             *  "inputs": [],
             *  "issuances": [],
             *  "transfers": [],
             *  "destructions": []
             * }
             */
            // let’s use the two coins sent to Silver and Gold as Issuance Coins.
            var issuanceCoins = init.Outputs.AsCoins()
                                .Take(2).Select((c, i) => new IssuanceCoin(c))
                                .OfType <ICoin>()
                                .ToArray();
            // Gold is the first coin, Silver the second one.
            // From that you can send Gold to Satoshi with the TransactionBuilder,

            // imagine that Satoshi wants to send 4 gold to Alice.
            // First, he will fetch the ColoredCoin out of the transaction.
            var sendGoldToSatoshi = init;
            var goldCoin          = ColoredCoin.Find(sendGoldToSatoshi, color).FirstOrDefault();
            // build a transaction like that:
            var builder           = new TransactionBuilder();
            var sendToBobAndAlice = builder.AddKeys(satoshi)
                                    .AddCoins(goldCoin)
                                    .SendAsset(alice, new AssetMoney(goldId, 4))
                                    .SetChange(satoshi)
                                    .BuildTransaction(true);
            // you are out of 600 satoshi.
            // You can fix the problem by adding the last Coin of 1 BTC
            // in the init transaction that belongs to satoshi.
            var satoshiBtc = init.Outputs.AsCoins().Last();

            builder = new TransactionBuilder();
            var sendToAlice = builder.AddKeys(satoshi)
                              .AddCoins(goldCoin, satoshiBtc)
                              .SendAsset(alice, new AssetMoney(goldId, 4))
                              .SetChange(satoshi)
                              .BuildTransaction(true);

            repo.Transactions.Put(sendToAlice);
            color = ColoredTransaction.FetchColors(sendToAlice, repo);

            // Let’s see the transaction and its colored part:
            Console.WriteLine("sendToAlice: " + sendToAlice);
            Console.WriteLine("color: " + color);
        }
Example #10
0
        private static void Main()
        {
            //========================================================================================
            //Section. Unit tests

            //You can see that previously I hard coded the properties of ColoredCoin.
            //The reason is that I wanted only to show you how to construct a Transaction out of ColoredCoin coins.
            //In real life, you would either depend on a third party API to fetch the colored coins of a transaction or a balance. Which might be not a good idea, because it adds a trust dependency to your program with the API provider.
            //NBitcoin allows you either to depend on a web service or to provide your own implementation for fetching the color of a Transaction. This allows you to have a flexible way to unit test your code, using another implementation or your own.
            //Let’s introduce two issuers: Silver and Gold. And three participants: Bob, Alice and Satoshi.
            //Let’s create a fake transaction that give some bitcoins to Silver, Gold and Satoshi.
            var gold     = new Key();
            var silver   = new Key();
            var goldId   = gold.PubKey.ScriptPubKey.Hash.ToAssetId();
            var silverId = silver.PubKey.ScriptPubKey.Hash.ToAssetId();

            var bob     = new Key();
            var alice   = new Key();
            var satoshi = new Key();

            var init = new Transaction
            {
                Outputs =
                {
                    new TxOut("1.0", gold),
                    new TxOut("1.0", silver),
                    new TxOut("1.0", satoshi)
                }
            };

            //Init does not contain any Colored Coin issuance and Transfer. But imagine that you want to be sure of it, how would you proceed?
            //In NBitcoin, the summary of color transfers and issuances is described by a class called ColoredTransaction.

            //Picture depiction:
            //IBitcoinSerializable interface.
            //3 classes(ColoredTransaction, ColoredEntry, Asset) implement IBitcoinSerializable interface.


            //You can see that the ColoredTransaction class will tell you:
            //1.Which TxIn spends which Asset
            //2.Which TxOut emits which Asset
            //3.Which TxOut transfers which Asset

            //But the method that interests us right now is FetchColor, which will permit you to extract colored information out of the transaction you gave in input.
            //You see that it depends on a IColoredTransactionRepository.
            //In other words, IColoredTransactionRepository type object should be passed into FetchColor() method as one of the arguments of it.
            //Picture depiction.


            //IColoredTransactionRepository is only a store that will give you the ColoredTransaction from the txid. However, you can see that it depends on ITransactionRepository, which maps a Transaction id to its transaction.
            //An implementation of IColoredTransactionRepository is CoinprismColoredTransactionRepository which is a public API for colored coins operations.
            //However, you can easily do your own, here is how FetchColors method works.
            //The simplest case is: The IColoredTransactionRepository knows the color, in such case FetchColors method only returns that result.
            //Picture depiction:



            //The second case is that the IColoredTransactionRepository does not know anything about the color of the transaction.
            //So FetchColors method will need to compute the color itself according to the open asset specification.
            //However, for computing the color, FetchColors method needs the color of the parent transactions.
            //So it fetches each of them on the ITransactionRepository, and calls FetchColors method on each of them.
            //Once FetchColors method has resolved the color of the parent’s recursively, it computes the transaction color, and caches the result back in the IColoredTransactionRepository.

            //Picture depiction:


            //            By doing that, future requests to fetch the color of a transaction will be resolved quickly.
            //Some IColoredTransactionRepository are read-only(like CoinprismColoredTransactionRepository), so the Put operation is ignored.
            //So, back to our example: The trick when writing unit tests is to use an in-memory IColoredTransactionRepository:
            var repo = new NoSqlColoredTransactionRepository();

            //Now, we can put our init transaction to the inside.
            repo.Transactions.Put(init);

            //Note that Put is an extension methods, so you will need to add
            //using NBitcoin.OpenAsset;
            //at the top of the file to get access to it.


            //And now, you can extract the color:

            ColoredTransaction color = ColoredTransaction.FetchColors(init, repo);

            Console.WriteLine(color);
            //Output:
            //{
            // "inputs": [],
            // "issuances": [],
            // "transfers": [],
            // "destructions": []
            //}
            //As expected, the init transaction has no inputs, issuances, transfers or destructions of Colored Coins.


            //So now, let’s use the two coins sent to Silver and Gold as Issuance Coins.
            var issuanceCoins = init
                                .Outputs
                                .AsCoins()
                                .Take(2)
                                .Select((c, i) => new IssuanceCoin(c))
                                .OfType <ICoin>()
                                .ToArray();
            //Gold is the first coin, Silver the second one.

            //From that you can send Gold to Satoshi with the TransactionBuilder, as we have done in the previous exercise, and put the resulting transaction in the repository, and print the result.

            //Output:
            //{
            // "inputs": [],
            // "issuances": [
            //    {
            //      "index": 0,
            //      "asset": "ATEwaRSNeCgBjxjcur7JtfypFjqQgAtLJs",
            //      "quantity": 10
            //    }
            //  ],
            //  "transfers": [],
            //  "destructions": []
            //}
            //This means that the first TxOut bears 10 gold.

            //Now imagine that Satoshi wants to send 4 gold to Alice.
            //First, satoshi should get the coins from the gold coin.
            //For that, build a transaction like that:
            var builder           = new TransactionBuilder();
            var sendGoldToSatoshi =
                builder
                .AddKeys(gold)
                .AddCoins(issuanceCoins[0])
                .IssueAsset(satoshi, new AssetMoney(goldId, 10))
                .SetChange(gold)
                .BuildTransaction(true);

            repo.Transactions.Put(sendGoldToSatoshi);
            color = ColoredTransaction.FetchColors(sendGoldToSatoshi, repo);
            Console.WriteLine(color);

            //Satoshi will fetch the ColoredCoin which he recieved from the gold coin out of the transaction.
            var goldCoin = ColoredCoin.Find(sendGoldToSatoshi, color).FirstOrDefault();

            //And satoshi sends the coin to Alice.
            builder = new TransactionBuilder();
            var sendToAliceWithNotEnoughFundsException =
                builder
                .AddKeys(satoshi)
                .AddCoins(goldCoin)
                .SendAsset(alice, new AssetMoney(goldId, 4))
                .SetChange(satoshi)
                .BuildTransaction(true);

            Console.WriteLine(sendToAliceWithNotEnoughFundsException);
            //Except you will get the exception NotEnoughFundsException.
            //The reason is that the transaction is composed of 600 satoshis in input(the goldCoin which satoshi owns), and 1200 satoshis in output. (One TxOut for sending assets to Alice, and the other one for sending back the change to Satoshi.)
            //In other words, in TxIn(total 600 coming) < in TxOut(total 1200 going out)
            //This means that you are out of 600 satoshis.
            //You can fix the problem by adding the last Coin of 1 BTC in the init transaction that belongs to satoshi.
            var satoshiBtc = init.Outputs.AsCoins().Last();

            builder = new TransactionBuilder();
            //Send the coin to Alice this time without a NotEnoughFundsException.
            var sendToAlice =
                builder
                .AddKeys(satoshi)
                .AddCoins(goldCoin, satoshiBtc)
                .SendAsset(alice, new AssetMoney(goldId, 4))
                .SetChange(satoshi)
                .BuildTransaction(true);

            repo.Transactions.Put(sendToAlice);
            color = ColoredTransaction.FetchColors(sendToAlice, repo);


            //Let’s see the transaction and its colored part:
            Console.WriteLine(sendToAlice);
            Console.WriteLine(color);

            //{
            //  ….
            //  "in": [
            //    {
            //      "prev_out": {
            //        "hash": "46117f3ef44f2dfd87e0bc3f461f48fe9e2a3a2281c9b3802e339c5895fc325e",
            //        "n": 0
            //      },
            //      "scriptSig": "304502210083424305549d4bb1632e2c67736383558f3e1d7fb30ce7b5a3d7b87a53cdb3940220687ea53db678b467b98a83679dec43d27e89234ce802daf14ed059e7a09557e801 03e232cda91e719075a95ede4c36ea1419efbc145afd8896f36310b76b8020d4b1"
            //    },
            //    {
            //      "prev_out": {
            //        "hash": "aefa62270999baa0d57ddc7d2e1524dd3828e81a679adda810657581d7d6d0f6",
            //        "n": 2
            //      },
            //      "scriptSig": "30440220364a30eb4c8a82cc2a79c54d0518b8ba0cf4e49c73a5bbd17fe1a5683a0dfa640220285e98f3d336f1fa26fb318be545162d6a36ce1103c8f6c547320037cb1fb8e901 03e232cda91e719075a95ede4c36ea1419efbc145afd8896f36310b76b8020d4b1"
            //    }
            //  ],
            //  "out": [
            //    {
            //      "value": "0.00000000",
            //      "scriptPubKey": "OP_RETURN 4f41010002060400"
            //    },
            //    {
            //      "value": "0.00000600",
            //      "scriptPubKey": "OP_DUP OP_HASH160 5bb41cd29f4e838b4b0fdcd0b95447dcf32c489d OP_EQUALVERIFY OP_CHECKSIG"
            //    },
            //    {
            //      "value": "0.00000600",
            //      "scriptPubKey": "OP_DUP OP_HASH160 469c5243cb08c82e78a8020360a07ddb193f2aa8 OP_EQUALVERIFY OP_CHECKSIG"
            //    },
            //    {
            //      "value": "0.99999400",
            //      "scriptPubKey": "OP_DUP OP_HASH160 5bb41cd29f4e838b4b0fdcd0b95447dcf32c489d OP_EQUALVERIFY OP_CHECKSIG"
            //    }
            //  ]
            //}
            //Colored :
            //{
            //  "inputs": [
            //    {
            //      "index": 0,
            //      "asset": " ATEwaRSNeCgBjxjcur7JtfypFjqQgAtLJs ",
            //      "quantity": 10
            //    }
            //  ],
            //  "issuances": [],
            //  "transfers": [
            //    {
            //      "index": 1,
            //      "asset": " ATEwaRSNeCgBjxjcur7JtfypFjqQgAtLJs ",
            //      "quantity": 6
            //    },
            //    {
            //      "index": 2,
            //      "asset": " ATEwaRSNeCgBjxjcur7JtfypFjqQgAtLJs ",
            //      "quantity": 4
            //    }
            //  ],
            //  "destructions": []
            //}

            //We have finally made a unit test that emits and transfers some assets without any external dependencies.
            //You can make your own IColoredTransactionRepository if you don’t want to depend on a third party service.
            //You can find more complex scenarios in NBitcoin tests, and also one of my articles “Build them all” in Codeproject. (Like multi-sig issuance and colored coin swaps.)
        }
Example #11
0
        static void Main(string[] args)
        {
            var goldGuy   = new BitcoinSecret("KyuzoVnpsqW529yzozkzP629wUDBsPmm4QEkh9iKnvw3Dy5JJiNg");
            var silverGuy = new BitcoinSecret("L4KvjpqDtdGEn7Lw6HdDQjbg74MwWRrFZMQTgJozeHAKJw5rQ2Kn");

            var firstPerson    = new BitcoinSecret("5Jnw9Td7PaG6PWBrU7ZCfxyVXsHSsNxdZ9sg5dnZstcr12DLVbJ");
            var secondPerson   = new BitcoinSecret("5Jn4zJkzS2BWNu7AMRTdSJ6mS7JYfJg27oXKAichaRBbp97ZKks");
            var exchangeEntity = new BitcoinSecret("5KA7FeABKmMKerWmkJzYM9FdoqScZEMVcS9u6wvT3EhgF5ZUWv5");

            var bitcoinProviderEntity = new BitcoinSecret("5Jcz2A17aAt4bcQP5GEn6itt72JsLwrksNRVKqazy7n284b1bKj");

            var issuanceCoinsTransaction = new Transaction()
            {
                Outputs =
                {
                    new TxOut("1.0", goldGuy.PubKey),
                    new TxOut("1.0", silverGuy.PubKey),
                    new TxOut("1.0", firstPerson.PubKey),
                    new TxOut("1.0", secondPerson.PubKey),
                }
            };

            IssuanceCoin[] issuanceCoins = issuanceCoinsTransaction
                                           .Outputs
                                           .Take(2)
                                           .Select((o, i) => new Coin(new OutPoint(issuanceCoinsTransaction.GetHash(), i), o))
                                           .Select(c => new IssuanceCoin(c))
                                           .ToArray();

            var goldIssuanceCoin        = issuanceCoins[0];
            var silverIssuanceCoin      = issuanceCoins[1];
            var firstPersonInitialCoin  = new Coin(new OutPoint(issuanceCoinsTransaction, 2), issuanceCoinsTransaction.Outputs[2]);
            var secondPersonInitialCoin = new Coin(new OutPoint(issuanceCoinsTransaction, 3), issuanceCoinsTransaction.Outputs[3]);

            var goldId   = goldIssuanceCoin.AssetId;
            var silverId = silverIssuanceCoin.AssetId;

            var txRepo = new NoSqlTransactionRepository();

            txRepo.Put(issuanceCoinsTransaction.GetHash(), issuanceCoinsTransaction);

            var ctxRepo = new NoSqlColoredTransactionRepository(txRepo);

            TransactionBuilder txBuilder = new TransactionBuilder();

            // Issuing gold to first person
            // This happens in gold issuer client
            Transaction tx = txBuilder
                             .AddKeys(goldGuy.PrivateKey)
                             .AddCoins(goldIssuanceCoin)
                             .IssueAsset(firstPerson.GetAddress(), new AssetMoney(goldId, 20))
                             .SetChange(goldGuy.GetAddress())
                             .BuildTransaction(true);

            txRepo.Put(tx.GetHash(), tx);
            var         ctx                 = tx.GetColoredTransaction(ctxRepo);
            var         coloredCoins        = ColoredCoin.Find(tx, ctx).ToArray();
            ColoredCoin firstPersonGoldCoin = coloredCoins[0];

            // Issuing silver to second person
            // This happens in silver issuer client
            txBuilder = new TransactionBuilder();
            tx        = txBuilder
                        .AddKeys(silverGuy.PrivateKey)
                        .AddCoins(silverIssuanceCoin)
                        .IssueAsset(secondPerson.GetAddress(), new AssetMoney(silverId, 30))
                        .SetChange(silverGuy.GetAddress())
                        .BuildTransaction(true);

            txRepo.Put(tx.GetHash(), tx);
            ctx          = tx.GetColoredTransaction(ctxRepo);
            coloredCoins = ColoredCoin.Find(tx, ctx).ToArray();
            ColoredCoin secondPersonSilverCoin = coloredCoins[0];

            // Sending first person gold to exchange
            // This happens in first user client
            var bitcoinProviderCoin = CreateTransactionFeeCoin(bitcoinProviderEntity.PubKey, txRepo);

            txBuilder = new TransactionBuilder();
            tx        = txBuilder
                        .AddCoins(bitcoinProviderCoin)
                        .AddKeys(bitcoinProviderEntity.PrivateKey)
                        .AddCoins(firstPersonGoldCoin)
                        .AddKeys(firstPerson.PrivateKey)
                        .SendAssetToExchange(exchangeEntity.GetAddress(), new AssetMoney(goldId, 5))
                        .SetChange(firstPerson.PubKey)
                        .BuildTransaction(true);
            txRepo.Put(tx.GetHash(), tx);
            ctx          = tx.GetColoredTransaction(ctxRepo);
            coloredCoins = ColoredCoin.Find(tx, ctx).ToArray();
            ColoredCoin firstPersonColoredCoinInExchange = coloredCoins[1];

            // Creating the time-locked transaction which the first user can post to the
            // network to claim his/her coin from exchange (it works if the exchange does not touch the coins
            // This happens in exchange and the transaction is delivered to first user client
            bitcoinProviderCoin = CreateTransactionFeeCoin(bitcoinProviderEntity.PubKey, txRepo);
            txBuilder           = new TransactionBuilder();
            tx = txBuilder
                 .AddCoins(bitcoinProviderCoin)
                 .AddKeys(bitcoinProviderEntity.PrivateKey)
                 .AddCoins(firstPersonColoredCoinInExchange)
                 .AddKeys(firstPerson.PrivateKey)
                 .SendAsset(firstPerson.PubKey, new AssetMoney(firstPersonColoredCoinInExchange.Amount.Id,
                                                               firstPersonColoredCoinInExchange.Amount.Quantity))
                 .SetChange(exchangeEntity.PubKey)
                 .SetLockTime(new LockTime(1000000))
                 .BuildTransaction(true);
            string reclaimTransactionForFirstUser = tx.ToHex();

            // Create first person exchange request
            // This happens in first person client
            JObject firstPersonRequestToExchange = CreateExchangeRequest("ExactMatch", goldId.ToString(),
                                                                         silverId.ToString(), 5, 2);
            var firstRequestSignature = firstPerson.PrivateKey.SignMessage(firstPersonRequestToExchange.ToString(Formatting.None));

            // Sending second person silver to exchange
            // This happens in second person client
            bitcoinProviderCoin = CreateTransactionFeeCoin(bitcoinProviderEntity.PubKey, txRepo);
            txBuilder           = new TransactionBuilder();
            tx = txBuilder
                 .AddCoins(bitcoinProviderCoin)
                 .AddKeys(bitcoinProviderEntity.PrivateKey)
                 .AddCoins(secondPersonSilverCoin)
                 .AddKeys(secondPerson.PrivateKey)
                 .SendAssetToExchange(exchangeEntity.GetAddress(), new AssetMoney(silverId, 12))
                 .SetChange(secondPerson.PubKey)
                 .BuildTransaction(true);
            txRepo.Put(tx.GetHash(), tx);
            ctx          = tx.GetColoredTransaction(ctxRepo);
            coloredCoins = ColoredCoin.Find(tx, ctx).ToArray();
            ColoredCoin secondPersonColoredCoinInExchange = coloredCoins[1];

            // Create second person exchange request
            // This happens in second person client
            JObject secondPersonRequestToExchange = CreateExchangeRequest("ExactMatch", silverId.ToString(),
                                                                          goldId.ToString(), 30, 0.5f);
            var secondRequestSignature = secondPerson.PrivateKey.SignMessage(secondPersonRequestToExchange.ToString(Formatting.None));

            // Creating exchange reason
            // This happens in exchange
            var exchangeReason = CreateExchangeMatch(firstPersonRequestToExchange, firstRequestSignature,
                                                     secondPersonRequestToExchange, secondRequestSignature, exchangeEntity.PrivateKey);

            // Performing the exchange operation
            // This happens in exchange
            bitcoinProviderCoin = CreateTransactionFeeCoin(bitcoinProviderEntity.PubKey, txRepo);
            txBuilder           = new TransactionBuilder();
            tx = txBuilder
                 .AddCoins(bitcoinProviderCoin)
                 .AddKeys(bitcoinProviderEntity.PrivateKey)
                 .AddCoins(firstPersonColoredCoinInExchange)
                 .AddKeys(exchangeEntity.PrivateKey)
                 .AddCoins(secondPersonColoredCoinInExchange)
                 .AddKeys(exchangeEntity.PrivateKey)
                 .PerformExchangeOperation(firstPerson.GetAddress(), new AssetMoney(silverId, 10),
                                           secondPerson.GetAddress(), new AssetMoney(goldId, 5), exchangeReason.ToString(Formatting.None))
                 .SetChange(exchangeEntity.GetAddress())
                 .BuildTransaction(true);
            txRepo.Put(tx.GetHash(), tx);
            ctx          = tx.GetColoredTransaction(ctxRepo);
            coloredCoins = ColoredCoin.Find(tx, ctx).ToArray();

            txRepo.Put(tx.GetHash(), tx);
        }
Example #12
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:
        }
Example #13
0
        private static void Main()
        {
            //===========================================================================================
            //Section. Liquid Democracy

            //===========================================================================================
            //Section1. Overview
            //This part is a purely conceptual exercise of one application of colored coins.

            //Let’s imagine a company where some decisions are taken by a board of investors after a vote.
            //1.Some investors do not know enough about a topic, so they would like to delegate decisions about some subjects to someone else.
            //2.There is potentially a huge number of investors.
            //3.As the CEO, you want the ability to sell voting power for financing the company.
            //4.As the CEO, you want the ability to cast a vote when you decide.

            //How Colored Coins can help to organize such a vote transparently ?

            //But before beginning, let’s talk about some downside of voting on the Blockchain:
            //1.Nobody knows the real identity of a voter.
            //2.Miners could censor(even if it would be provable, and not in their interest.)
            //3.Even if nobody knows the real identity of the voter, behavioral analysis of a voter across several vote might reveal his identity.

            //Whether these points are relevant or not is up to the vote organizer to decide.

            //Let’s take an overview of how we would implement that.



            //===========================================================================================
            //Section2. Issuing voting power

            //Everything starts with the founder of the company(let’s call him Boss) wanting to sell “decision power” in his company to some investors. The decision power can take the shape of a colored coin that we will call for the sake of this exercise a “Power Coin”.

            //Let’s represent it in purple:



            //Let’s say that three persons are interested, Satoshi, Alice and Bob. (Yes, them again)
            //So Boss decides to sell each Power Coin at 0.1 BTC each.
            //Let’s start funding some money to the powerCoin address, satoshi, alice and bob.

            var powerCoin = new Key();
            var alice     = new Key();
            var bob       = new Key();
            var satoshi   = new Key();
            var init      = new Transaction()
            {
                Outputs =
                {
                    new TxOut(Money.Coins(1.0m), powerCoin),
                    new TxOut(Money.Coins(1.0m), alice),
                    new TxOut(Money.Coins(1.0m), bob),
                    new TxOut(Money.Coins(1.0m), satoshi),
                }
            };

            var repo = new NoSqlColoredTransactionRepository();

            repo.Transactions.Put(init);


            //Imagine that Alice buys 2 Power coins, here is how to create such transaction.
            var issuance = GetCoins(init, powerCoin)
                           .Select(c => new IssuanceCoin(c))
                           .ToArray();
            var builder = new TransactionBuilder();
            var toAlice =
                builder
                .AddCoins(issuance)
                .AddKeys(powerCoin)
                .IssueAsset(alice, new AssetMoney(powerCoin, 2))
                .SetChange(powerCoin)
                .Then()
                .AddCoins(GetCoins(init, alice))
                .AddKeys(alice)
                .Send(alice, Money.Coins(0.2m))
                .SetChange(alice)
                .BuildTransaction(true);

            repo.Transactions.Put(toAlice);
            //In summary, powerCoin issues 2 Power Coins to Alice and sends the change to himself(powerCoin). Likewise, Alice sends 0.2 BTC to powerCoin and sends the change to herself(Alice).


            //Where GetCoins method is
            //private IEnumerable<Coin> GetCoins(Transaction tx, Key owner)
            //{
            //    return tx.Outputs.AsCoins().Where(c => c.ScriptPubKey == owner.ScriptPubKey);
            //}


            //For some reason, Alice, might want to sell some of her voting power to Satoshi.

            //You can note that I am double spending the coin of Alice from the init transaction.
            //**Such thing would not be accepted on the Blockchain. However, we have not seen yet how to retrieve unspent coins from the Blockchain easily, so let’s just imagine for the sake of the exercise that the coin was not double spent.
            // Now that Alice and Satoshi have some voting power, let’s see how Boss can run a vote.

            //===========================================================================================
            //Section3. Running a vote

            //By consulting the Blockchain, Boss can at any time know ScriptPubKeys which own Power Coins.
            //So he will send Voting Coins to these owners, proportionally to their voting power, in our case, 1 voting coin to Alice and 1 voting coin to Satoshi.


            //First, I need to create some funds for votingCoin.
            var votingCoin = new Key();
            var init2      = new Transaction()
            {
                Outputs =
                {
                    new TxOut(Money.Coins(1.0m), votingCoin),
                }
            };

            repo.Transactions.Put(init2);

            //Then, issue the voting coins.
            issuance = GetCoins(init2, votingCoin).Select(c => new IssuanceCoin(c)).ToArray();
            builder  = new TransactionBuilder();
            var toVoters =
                builder
                .AddCoins(issuance)
                .AddKeys(votingCoin)
                .IssueAsset(alice, new AssetMoney(votingCoin, 1))
                .IssueAsset(satoshi, new AssetMoney(votingCoin, 1))
                .SetChange(votingCoin)
                .BuildTransaction(true);

            repo.Transactions.Put(toVoters);


            //===========================================================================================
            //Section4. Vote delegation

            //The problem is that the vote concerns some financial aspect of the business, and Alice is mostly concerned by the marketing aspect.
            //Her decision is to handout her voting coin to someone she trusts having a better judgment on financial matter. She chooses to delegate her vote to Bob.

            var aliceVotingCoin = ColoredCoin.Find(toVoters, repo)
                                  .Where(c => c.ScriptPubKey == alice.ScriptPubKey)
                                  .ToArray();

            builder = new TransactionBuilder();
            var toBob =
                builder
                .AddCoins(aliceVotingCoin)
                .AddKeys(alice)
                .SendAsset(bob, new AssetMoney(votingCoin, 1))
                .BuildTransaction(true);

            repo.Transactions.Put(toBob);

            //You can notice that there is no SetChange() extension method. The reason for that is that the input colored coin is spent entirely, so that nothing is left to be returned.


            //===========================================================================================
            //Section5. Voting

            //Imagine that Satoshi is too busy and decides not to vote.Now Bob must express his decision.
            //The vote concerns whether the company should ask for a loan to the bank for investing into new production machines.
            //Boss says on the company’s website:
            //Send your coins to 1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN for "Yes" or to 1F3sAm6ZtwLAUnj7d38pGFxtP3RVEvtsbV for "No".
            //Bob decides that the company should take the loan:

            var bobVotingCoin = ColoredCoin.Find(toVoters, repo)
                                .Where(c => c.ScriptPubKey == bob.ScriptPubKey)
                                .ToArray();

            builder = new TransactionBuilder();
            var vote = builder
                       .AddCoins(bobVotingCoin)
                       .AddKeys(bob)
                       .SendAsset(BitcoinAddress.Create("1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN"),
                                  new AssetMoney(votingCoin, 1))
                       .BuildTransaction(true);

            //Now Boss can compute the result of the vote and see 1-Yes 0-No.
            //Yes and he wins, so he takes the loan.
            //Every participants can also count the result by themselves.



            //===========================================================================================
            //Section6. Alternative: Use of Ricardian Contract

            //In the previous exercise, we have supposed that Boss announced the modalities of the vote, out of the Blockchain, on the company’s website.
            //This works great, but Bob need to know that the website exists.
            //Another solution for this existing website problem is to publish the modalities of the vote directly on the Blockchain within an Asset Definition File, so some software can automatically get it and present it to Bob.
            //The only piece of code that would have changed is during the issuance of the Voting Coins to voters.


            issuance = GetCoins(init2, votingCoin).Select(c => new IssuanceCoin(c)).ToArray();
            issuance[0].DefinitionUrl = new Uri("http://boss.com/vote01.json");
            builder  = new TransactionBuilder();
            toVoters = builder
                       .AddCoins(issuance)
                       .AddKeys(votingCoin)
                       .IssueAsset(alice, new AssetMoney(votingCoin, 1))
                       .IssueAsset(satoshi, new AssetMoney(votingCoin, 1))
                       .SetChange(votingCoin)
                       .BuildTransaction(true);
            repo.Transactions.Put(toVoters);



            //In such case, Bob can see that during the issuance of his voting coin, an Asset Definition File was published, which is nothing more than a JSON document whose schema is partially specified in Open Asset.The schema can be extended to have information about things like:
            //1.Expiration of the vote
            //2.Destination of the votes for each candidates
            //3.Human friendly description of it
            //However, imagine that a hacker wants to cheat the vote. He can always modify the JSON document(either man in the middle of attack, physical access to boss.com, or access to Bob’s machine) so Bob is tricked and sends his vote to the wrong candidate.
            //Transforming the Asset Definition File into a Ricardian Contract by signing it would make any modification immediately detectable by Bob’s software. (See Proof Of Authenticity in the Asset Definition Protocol)
        }
Example #14
0
        void Start()
        {
            var gold     = new Key();
            var silver   = new Key();
            var goldId   = gold.PubKey.ScriptPubKey.Hash.ToAssetId();
            var silverId = silver.PubKey.ScriptPubKey.Hash.ToAssetId();

            var bob     = new Key();
            var alice   = new Key();
            var satoshi = new Key();

            var init = new Transaction
            {
                Outputs =
                {
                    new TxOut("1.0", gold),
                    new TxOut("1.0", silver),
                    new TxOut("1.0", satoshi)
                }
            };

            var repo = new NoSqlColoredTransactionRepository();

            repo.Transactions.Put(init);

            ColoredTransaction color = ColoredTransaction.FetchColors(init, repo);

            UnityEngine.Debug.Log(color);

            var issuanceCoins =
                init
                .Outputs
                .AsCoins()
                .Take(2)
                .Select((c, i) => new IssuanceCoin(c))
                .OfType <ICoin>()
                .ToArray();

            var builder           = new TransactionBuilder();
            var sendGoldToSatoshi =
                builder
                .AddKeys(gold)
                .AddCoins(issuanceCoins[0])
                .IssueAsset(satoshi, new AssetMoney(goldId, 10))
                .SetChange(gold)
                .BuildTransaction(true);

            repo.Transactions.Put(sendGoldToSatoshi);
            color = ColoredTransaction.FetchColors(sendGoldToSatoshi, repo);
            UnityEngine.Debug.Log(color);

            var goldCoin = ColoredCoin.Find(sendGoldToSatoshi, color).FirstOrDefault();

            builder = new TransactionBuilder();
            var sendToBobAndAlice =
                builder
                .AddKeys(satoshi)
                .AddCoins(goldCoin)
                .SendAsset(alice, new AssetMoney(goldId, 4))
                .SetChange(satoshi)
                .BuildTransaction(true);


            var satoshiBtc = init.Outputs.AsCoins().Last();

            builder = new TransactionBuilder();
            var sendToAlice =
                builder
                .AddKeys(satoshi)
                .AddCoins(goldCoin, satoshiBtc)
                .SendAsset(alice, new AssetMoney(goldId, 4))
                .SetChange(satoshi)
                .BuildTransaction(true);

            repo.Transactions.Put(sendToAlice);
            color = ColoredTransaction.FetchColors(sendToAlice, repo);

            UnityEngine.Debug.Log(sendToAlice);
            UnityEngine.Debug.Log(color);
        }
Example #15
0
		public ColoredTransaction(uint256 txId, Transaction tx, ColoredCoin[] spentCoins, Script issuanceScriptPubkey)
			: this()
		{
			if(tx == null)
				throw new ArgumentNullException("tx");
			if(spentCoins == null)
				throw new ArgumentNullException("spentCoins");
			if(tx.IsCoinBase || tx.Inputs.Count == 0)
				return;
			txId = txId ?? tx.GetHash();

			Queue<ColoredEntry> previousAssetQueue = new Queue<ColoredEntry>();
			for(uint i = 0 ; i < tx.Inputs.Count ; i++)
			{
				var txin = tx.Inputs[i];
				var prevAsset = spentCoins.FirstOrDefault(s => s.Outpoint == txin.PrevOut);
				if(prevAsset != null)
				{
					var input = new ColoredEntry()
					{
						Index = i,
						Asset = prevAsset.Amount
					};
					previousAssetQueue.Enqueue(input);
					Inputs.Add(input);
				}
			}

			uint markerPos = 0;
			var marker = ColorMarker.Get(tx, out markerPos);
			if(marker == null)
			{
				return;
			}
			Marker = marker;
			if(!marker.HasValidQuantitiesCount(tx))
			{
				return;
			}

			AssetId issuedAsset = null;
			for(uint i = 0 ; i < markerPos ; i++)
			{
				var entry = new ColoredEntry();
				entry.Index = i;
				entry.Asset = new AssetMoney(entry.Asset.Id, i >= marker.Quantities.Length ? 0 : marker.Quantities[i]);
				if(entry.Asset.Quantity == 0)
					continue;

				if(issuedAsset == null)
				{
					var txIn = tx.Inputs.FirstOrDefault();
					if(txIn == null)
						continue;
					if(issuanceScriptPubkey == null)
						throw new ArgumentException("The transaction has an issuance detected, but issuanceScriptPubkey is null.", "issuanceScriptPubkey");
					issuedAsset = issuanceScriptPubkey.Hash.ToAssetId();
				}
				entry.Asset = new AssetMoney(issuedAsset, entry.Asset.Quantity);
				Issuances.Add(entry);
			}

			long used = 0;
			for(uint i = markerPos + 1 ; i < tx.Outputs.Count ; i++)
			{
				var entry = new ColoredEntry();
				entry.Index = i;
				//If there are less items in the  asset quantity list  than the number of colorable outputs (all the outputs except the marker output), the outputs in excess receive an asset quantity of zero.
				entry.Asset = new AssetMoney(entry.Asset.Id, (i - 1) >= marker.Quantities.Length ? 0 : marker.Quantities[i - 1]);
				if(entry.Asset.Quantity == 0)
					continue;

				//If there are less asset units in the input sequence than in the output sequence, the transaction is considered invalid and all outputs are uncolored. 
				if(previousAssetQueue.Count == 0)
				{
					Transfers.Clear();
					Issuances.Clear();
					return;
				}
				entry.Asset = new AssetMoney(previousAssetQueue.Peek().Asset.Id, entry.Asset.Quantity);
				var remaining = entry.Asset.Quantity;
				while(remaining != 0)
				{
					if(previousAssetQueue.Count == 0 || previousAssetQueue.Peek().Asset.Id != entry.Asset.Id)
					{
						Transfers.Clear();
						Issuances.Clear();
						return;
					}
					var assertPart = Math.Min(previousAssetQueue.Peek().Asset.Quantity - used, remaining);
					remaining = remaining - assertPart;
					used += assertPart;
					if(used == previousAssetQueue.Peek().Asset.Quantity)
					{
						previousAssetQueue.Dequeue();
						used = 0;
					}
				}
				Transfers.Add(entry);
			}
		}
Example #16
0
        static void Main(string[] args)
        {
            // 実際はAPIでJSONを受け取る
            string jsonString = @"{""commandType"":""issuance"",""fromTxHash"":""ce56e1d60efe0f5a3d93b837ce208f559214a5ec10cb9715ac0357475ae72576"",""fromOutputIndex"":""1"",""amount"":""100000000"",""scriptPubkey"":""76a9146255517104577282389fdce86d4e9e67f796759e88ac"",""bitcoinAddress"":""mpUtirtqBzQXuH9MRw3u1YgMFhBqRhknqu"",""bitcoinSecret"":""cTxQtwjYch3uscAPDUyUd2ZkcuMDTY3dp7X2HEvXoVzsFZiLFKYX"",""quantity"":""100000000""}";

            // string jsonString = @"{""commandType"":""send"",""fromTxHash"":""5dd0250910238a134c19a6ae5867cb239754b4d69d1a0f5589b29afba55b8315"",""fromOutputIndex"":""0"",""amount"":""2730"",""scriptPubkey"":""76a9146255517104577282389fdce86d4e9e67f796759e88ac"",""issuranceAddress"":""mpUtirtqBzQXuH9MRw3u1YgMFhBqRhknqu"",""balanceQuantity"":""100000000"",""bitcoinAddress"":""myMmSWRcRvrKPiQioF6QLfhkNkn1Krsz4J"",""bitcoinSecret"":""cTxQtwjYch3uscAPDUyUd2ZkcuMDTY3dp7X2HEvXoVzsFZiLFKYX"",""feeFromTxHash"":""5dd0250910238a134c19a6ae5867cb239754b4d69d1a0f5589b29afba55b8315"",""feeFromOutputIndex"":""1"",""feeAmount"":""99987270"",""feeScriptPubkey"":""76a9146255517104577282389fdce86d4e9e67f796759e88ac"",""quantity"":""1""}";
            // string jsonString = @"{""commandType"":""other""}";

            JsonHandler.PersonData pd = (JsonHandler.PersonData)JsonHandler.getObjectFromJson(
                jsonString,
                typeof(JsonHandler.PersonData)
                );

            Console.WriteLine(jsonString);

            if (pd.commandType.Equals("issuance"))
            {
                var coin = new Coin(
                    fromTxHash: new uint256(pd.fromTxHash),
                    fromOutputIndex: pd.fromOutputIndex,
                    amount: Money.Satoshis(pd.amount),
                    scriptPubKey: new Script(Encoders.Hex.DecodeData(pd.scriptPubkey)));

                var issuance = new IssuanceCoin(coin);

                var receiveAddress         = BitcoinAddress.Create(pd.bitcoinAddress);
                var bookKey                = new BitcoinSecret(pd.bitcoinSecret);
                TransactionBuilder builder = new TransactionBuilder();

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

                System.Diagnostics.Debug.WriteLine(tx);
                Console.WriteLine(tx);

                System.Diagnostics.Debug.WriteLine(builder.Verify(tx));
                Console.WriteLine(builder.Verify(tx));

                System.Diagnostics.Debug.WriteLine(issuance.AssetId);
                Console.WriteLine(issuance.AssetId);

                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!");
                }

                /* 連結ではbitcoindでのブロードキャストを行う
                 * using (var node = Node.ConnectToLocal(Network.TestNet)) //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
                 * }
                 */
            }
            else if (pd.commandType.Equals("send"))
            {
                var booka = BitcoinAddress.Create(pd.issuranceAddress);
                // System.Diagnostics.Debug.WriteLine(booka.ToColoredAddress());
                // Console.WriteLine(booka.ToColoredAddress());
                var assetId = new AssetId(booka).GetWif(Network.TestNet);
                System.Diagnostics.Debug.WriteLine(assetId);
                Console.WriteLine(assetId);

                var coin = new Coin(
                    fromTxHash: new uint256(pd.fromTxHash),
                    fromOutputIndex: pd.fromOutputIndex,
                    amount: Money.Satoshis(2730),
                    scriptPubKey: new Script(Encoders.Hex.DecodeData(pd.scriptPubkey)));
                // BitcoinAssetId assetId = new BitcoinAssetId(assetId);
                ColoredCoin colored = coin.ToColoredCoin(assetId, pd.balanceQuantity);

                var book        = BitcoinAddress.Create(pd.bitcoinAddress);
                var sendSecret  = new BitcoinSecret(pd.bitcoinSecret);
                var sendAddress = sendSecret.GetAddress();

                var forFees = new Coin(
                    fromTxHash: new uint256(pd.feeFromTxHash),
                    fromOutputIndex: pd.feeFromOutputIndex,
                    amount: Money.Satoshis(pd.feeAmount),
                    scriptPubKey: new Script(Encoders.Hex.DecodeData(pd.feeScriptPubkey)));

                TransactionBuilder builder = new TransactionBuilder();
                var tx = builder
                         .AddKeys(sendSecret)
                         .AddCoins(colored, forFees)
                         .SendAsset(book, new AssetMoney(assetId, pd.quantity))
                         .SetChange(sendAddress)
                         .SendFees(Money.Coins(0.0001m))
                         .BuildTransaction(true);
                System.Diagnostics.Debug.WriteLine(tx);
                Console.WriteLine(tx);
                System.Diagnostics.Debug.WriteLine(builder.Verify(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!");
                }

                /* 連結ではbitcoindでのブロードキャストを行う
                 * using (var node = Node.ConnectToLocal(Network.TestNet)) //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
                 * }
                 */
            }
            else
            {
                Console.WriteLine("CommandTypeError");
            }

            Console.ReadKey();
        }
Example #17
0
        public ColoredTransaction(uint256 txId, Transaction tx, ColoredCoin[] spentCoins, Script issuanceScriptPubkey)
            : this()
        {
            if (tx == null)
            {
                throw new ArgumentNullException("tx");
            }
            if (spentCoins == null)
            {
                throw new ArgumentNullException("spentCoins");
            }
            if (tx.IsCoinBase || tx.Inputs.Count == 0)
            {
                return;
            }
            txId = txId ?? tx.GetHash();

            var previousAssetQueue = new Queue <ColoredEntry>();

            for (uint i = 0; i < tx.Inputs.Count; i++)
            {
                TxIn        txin      = tx.Inputs[i];
                ColoredCoin prevAsset = spentCoins.FirstOrDefault(s => s.Outpoint == txin.PrevOut);
                if (prevAsset != null)
                {
                    var input = new ColoredEntry()
                    {
                        Index = i,
                        Asset = prevAsset.Amount
                    };
                    previousAssetQueue.Enqueue(input);
                    this.Inputs.Add(input);
                }
            }

            uint        markerPos = 0;
            ColorMarker marker    = ColorMarker.Get(tx, out markerPos);

            if (marker == null)
            {
                return;
            }

            this.Marker = marker;
            if (!marker.HasValidQuantitiesCount(tx))
            {
                return;
            }

            AssetId issuedAsset = null;

            for (uint i = 0; i < markerPos; i++)
            {
                var entry = new ColoredEntry();
                entry.Index = i;
                entry.Asset = new AssetMoney(entry.Asset.Id, i >= marker.Quantities.Length ? 0 : marker.Quantities[i]);
                if (entry.Asset.Quantity == 0)
                {
                    continue;
                }

                if (issuedAsset == null)
                {
                    TxIn txIn = tx.Inputs.FirstOrDefault();
                    if (txIn == null)
                    {
                        continue;
                    }
                    if (issuanceScriptPubkey == null)
                    {
                        throw new ArgumentException("The transaction has an issuance detected, but issuanceScriptPubkey is null.", "issuanceScriptPubkey");
                    }
                    issuedAsset = issuanceScriptPubkey.Hash.ToAssetId();
                }
                entry.Asset = new AssetMoney(issuedAsset, entry.Asset.Quantity);
                this.Issuances.Add(entry);
            }

            long used = 0;

            for (uint i = markerPos + 1; i < tx.Outputs.Count; i++)
            {
                var entry = new ColoredEntry();
                entry.Index = i;
                //If there are less items in the  asset quantity list  than the number of colorable outputs (all the outputs except the marker output), the outputs in excess receive an asset quantity of zero.
                entry.Asset = new AssetMoney(entry.Asset.Id, (i - 1) >= marker.Quantities.Length ? 0 : marker.Quantities[i - 1]);
                if (entry.Asset.Quantity == 0)
                {
                    continue;
                }

                //If there are less asset units in the input sequence than in the output sequence, the transaction is considered invalid and all outputs are uncolored.
                if (previousAssetQueue.Count == 0)
                {
                    this.Transfers.Clear();
                    this.Issuances.Clear();
                    return;
                }
                entry.Asset = new AssetMoney(previousAssetQueue.Peek().Asset.Id, entry.Asset.Quantity);
                long remaining = entry.Asset.Quantity;
                while (remaining != 0)
                {
                    if (previousAssetQueue.Count == 0 || previousAssetQueue.Peek().Asset.Id != entry.Asset.Id)
                    {
                        this.Transfers.Clear();
                        this.Issuances.Clear();
                        return;
                    }
                    long assertPart = Math.Min(previousAssetQueue.Peek().Asset.Quantity - used, remaining);
                    remaining = remaining - assertPart;
                    used     += assertPart;
                    if (used == previousAssetQueue.Peek().Asset.Quantity)
                    {
                        previousAssetQueue.Dequeue();
                        used = 0;
                    }
                }

                this.Transfers.Add(entry);
            }
        }
Example #18
0
        public static void Execute()
        {
            // Issuing voting power
            // Let’s say that three persons are interested, Satoshi, Alice and Bob. (Yes, them again)
            // So Boss decides to sell each Power Coin at 0.1 BTC each.
            // Let’s start funding some money to the powerCoin address, satoshi, alice and bob.
            Keys keys      = JsonConvert.DeserializeObject <Keys>(File.ReadAllText(@"Keys.json"));
            var  powerCoin = new Key();
            var  alice     = new Key();
            var  bob       = new Key();
            var  satoshi   = new Key();
            var  init      = new Transaction()
            {
                Outputs =
                {
                    new TxOut(Money.Coins(1.0m), powerCoin),
                    new TxOut(Money.Coins(1.0m), alice),
                    new TxOut(Money.Coins(1.0m), bob),
                    new TxOut(Money.Coins(1.0m), satoshi),
                }
            };

            var repo = new NoSqlColoredTransactionRepository();

            repo.Transactions.Put(init);

            // Alice buy 2 Power coins
            var issuance = GetCoins(init, powerCoin)
                           .Select(c => new IssuanceCoin(c))
                           .ToArray();

            var builder = new TransactionBuilder();

            // You can note that I am double spending the coin of Alice from the init transaction.
            // **Such thing would not be accepted on the Blockchain
            var toAlice = builder.AddCoins(issuance)
                          .AddKeys(powerCoin)
                          .IssueAsset(alice, new AssetMoney(powerCoin, 2))
                          .SetChange(powerCoin)
                          .Then()
                          .AddCoins(GetCoins(init, alice))
                          .AddKeys(alice)
                          .Send(powerCoin, Money.Coins(0.2m))
                          .SetChange(alice)
                          .BuildTransaction(true);

            repo.Transactions.Put(toAlice);

            // Running a vote, create some funds for votingCoin.
            var votingCoin = new Key();
            var init2      = new Transaction()
            {
                Outputs =
                {
                    new TxOut(Money.Coins(1.0m), votingCoin),
                }
            };

            repo.Transactions.Put(init2);

            // issue the voting coins.
            issuance = GetCoins(init2, votingCoin).Select(c => new IssuanceCoin(c)).ToArray();
            builder  = new TransactionBuilder();
            var toVoters = builder.AddCoins(issuance)
                           .AddKeys(votingCoin)
                           .IssueAsset(alice, new AssetMoney(votingCoin, 1))
                           .IssueAsset(satoshi, new AssetMoney(votingCoin, 1))
                           .SetChange(votingCoin)
                           .BuildTransaction(true);

            repo.Transactions.Put(toVoters);

            // Vote delegation
            // alice chooses to delegate her vote to Bob
            // notice that there is no SetChange the reason is that the input colored coin is spent entirely
            var aliceVotingCoin = ColoredCoin.Find(toVoters, repo)
                                  .Where(c => c.ScriptPubKey == alice.ScriptPubKey)
                                  .ToArray();

            builder = new TransactionBuilder();
            var toBob = builder.AddCoins(aliceVotingCoin)
                        .AddKeys(alice)
                        .SendAsset(bob, new AssetMoney(votingCoin, 1))
                        .BuildTransaction(true);

            repo.Transactions.Put(toBob);

            // Voting
            // Send your coins to 1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN for yes
            // and to 1F3sAm6ZtwLAUnj7d38pGFxtP3RVEvtsbV for no
            var bobVotingCoin = ColoredCoin.Find(toVoters, repo)
                                .Where(c => c.ScriptPubKey == bob.ScriptPubKey)
                                .ToArray();

            builder = new TransactionBuilder();
            var satoshiAdress = BitcoinAddress.Create(keys.satoshi.Address, Network.TestNet);
            var vote          = builder.AddCoins(bobVotingCoin)
                                .AddKeys(bob)
                                .SendAsset(satoshiAdress, new AssetMoney(votingCoin, 1))
                                .BuildTransaction(true);

            // The only piece of code that would have changed is during the issuance of the Voting Coins to voters
            issuance = GetCoins(init2, votingCoin).Select(c => new IssuanceCoin(c)).ToArray();
            issuance[0].DefinitionUrl = new Uri("http://boss.com/vote01.json");
            builder  = new TransactionBuilder();
            toVoters = builder.AddCoins(issuance)
                       .AddKeys(votingCoin)
                       .IssueAsset(alice, new AssetMoney(votingCoin, 1))
                       .IssueAsset(satoshi, new AssetMoney(votingCoin, 1))
                       .SetChange(votingCoin)
                       .BuildTransaction(true);
            repo.Transactions.Put(toVoters);
        }
        public static void ColoredCoins()
        {
            // ISSUING AN ASSET
            // In Open Asset, the Asset ID is derived from the issuers ScriptPubKey. To issue a Colored Coin, you must prove ownership of the ScriptPubKey by spending from it.
            // The coin you spend for issuing colored coins is called the "Issuance Coin" in NBitcoin. Create an issuance coin:
            // coin being used for issuing the asset:
            //{
            //    "transactionId": "eb49a599c749c82d824caf9dd69c4e359261d49bbb0b9d6dc18c59bc9214e43b",
            //    "index": 0,
            //    "value": 2000000,
            //    "scriptPubKey": "76a914c81e8e7b7ffca043b088a992795b15887c96159288ac",
            //    "redeemScript": null
            //}
            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);
            // build and sign transaction using TransactionBuilder
            var nico    = BitcoinAddress.Create("15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe");
            var bookKey = new BitcoinSecret("???"); // program errors bc we don't have nico's private key/secret
            TransactionBuilder builder = new TransactionBuilder();

            var tx = builder
                     .AddCoins(coin)
                     .AddKeys(bookKey)
                     .IssueAsset(nico, new NBitcoin.OpenAsset.AssetMoney(issuance.AssetId, quantity: 10)) // this is new part relevant to issuing colored coins
                     .SendFees(Money.Coins(0.0001m))
                     .SetChange(bookKey.GetAddress())
                     .BuildTransaction(sign: true);

            Console.WriteLine(tx);
            // after tx verification, it's ready to be sent to the network
            Console.WriteLine(builder.Verify(tx));
            // review: broadcasting with 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 broadcast with your own Bitcoin Core node:
            using (var node = Node.ConnectToLocal(Network.Main))
            {
                node.VersionHandshake();
                node.SendMessage(new InvPayload(InventoryType.MSG_TX, tx.GetHash())); // first send just the hash of your transaction
                node.SendMessage(new TxPayload(tx));                                  // then send signed transaction
                Thread.Sleep(500);
            }

            // Colored Coins have their own address format that only colored coin wallets understand, to prevent sending colored coins to wallets that don't support it
            nico = BitcoinAddress.Create("15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe");
            Console.WriteLine(nico.ToColoredAddress());

            // colored coin Asset ID is derived from issuer's ScriptPubKey. here is how to get the ID:
            var book    = BitcoinAddress.Create("1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB");
            var assetId = new AssetId(book).GetWif(Network.Main);

            Console.WriteLine(assetId);

            // TRANSFER AN ASSET
            // to send received colored coins, you need to build a ColredCoin
            // received transaction to spent:
            //{
            //    "transactionId": "fa6db7a2e478f3a8a0d1a77456ca5c9fa593e49fd0cf65c7e349e5a4cbe58842",
            //    "index": 0,
            //    "value": 600,
            //    "scriptPubKey": "76a914356facdac5f5bcae995d13e667bb5864fd1e7d5988ac",
            //    "redeemScript": null,
            //    "assetId": "AVAVfLSb1KZf9tJzrUVpktjxKUXGxUTD4e",
            //    "quantity": 10
            //}
            //var coin2 = new Coin(
            //    fromTxHash: new uint256("fa6db7a2e478f3a8a0d1a77456ca5c9fa593e49fd0cf65c7e349e5a4cbe58842"),
            //    fromOutputIndex: 0,
            //    amount: Money.Satoshis(600),
            //    scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914356facdac5f5bcae995d13e667bb5864fd1e7d5988ac")));
            //BitcoinAssetId assetId2 = new BitcoinAssetId("AVAVfLSb1KZf9tJzrUVpktjxKUXGxUTD4e");
            //ColoredCoin colored = coin2.ToColoredCoin(assetId2, 10);

            //// also, in this exampled, we needed another coin forFees to pay the tx fee
            //var forFees = new Coin(
            //    fromTxHash: new uint256("7f296e96ec3525511b836ace0377a9fbb723a47bdfb07c6bc3a6f2a0c23eba26"),
            //    fromOutputIndex: 0,
            //    amount: Money.Satoshis(4425000),
            //    scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914356facdac5f5bcae995d13e667bb5864fd1e7d5988ac")));

            //TransactionBuilder builder2 = new TransactionBuilder();
            //var tx2 = builder2
            //    .AddCoins(colored, forFees) // note: added newly created colored coin, and coin to pay fees in this example
            //    .AddKeys(bookKey)
            //    .SendAsset(book, new AssetMoney(assetId2, 10))
            //    .SetChange(nico)
            //    .SendFees(Money.Coins(0.0001m))
            //    .BuildTransaction(true);

            //Console.WriteLine(tx2); // again, errors b/c we don't have Nico's secret and I don't feel like creating another real tx and dealing with privacy when I push this to github

            // UNIT TESTS
            // create 2 issuers silver and gold, and fake tx to give bitcoin to silver, gold, satoshi
            var gold     = new Key();
            var silver   = new Key();
            var goldId   = gold.PubKey.ScriptPubKey.Hash.ToAssetId();
            var silverId = silver.PubKey.ScriptPubKey.Hash.ToAssetId();

            var alice   = new Key();
            var bob     = new Key();
            var satoshi = new Key();

            var init = new Transaction()
            {
                Outputs =
                {
                    new TxOut("1.0", gold),
                    new TxOut("1.0", silver),
                    new TxOut("1.0", satoshi)
                }
            };
            // in NBitcoin the sammary of color coin issuance and transfer is described by class ColoredTransaction
            // the trick to writing unit tests is to use an in memory IColoredTransactionRepository
            var repo = new NoSqlColoredTransactionRepository();

            // now we can put the init tx inside
            repo.Transactions.Put(init);
            // now we can get the color
            ColoredTransaction color = ColoredTransaction.FetchColors(init, repo);

            Console.WriteLine(color);
            // now we will use the coins sent to silver and gold as Issuance coins
            var issuanceCoins = init
                                .Outputs
                                .AsCoins()
                                .Take(2)
                                .Select((c, i) => new IssuanceCoin(c))
                                .OfType <ICoin>()
                                .ToArray();
            var sendGoldToSatoshi = new Transaction(); // use TransactionBuilder to send Gold to Satoshi, then put resulting tx in repo and print result

            var goldCoin = ColoredCoin.Find(sendGoldToSatoshi, color).FirstOrDefault();

            builder = new TransactionBuilder();
            var sendToBobAndAlice = builder
                                    .AddKeys(satoshi)
                                    .AddCoins(goldCoin)
                                    .SendAsset(alice, new AssetMoney(goldId, 4))
                                    .SetChange(satoshi)
                                    .BuildTransaction(true);
            // not enough funds; goldCoin input only has 600sats and need 1200 for output to transfer assets to Alice and change to satoshi; add coin
            var satoshiBtc = init.Outputs.AsCoins().Last();

            builder = new TransactionBuilder();
            var sendToAlice = builder
                              .AddKeys(satoshi)
                              .AddCoins(goldCoin, satoshiBtc)
                              .SendAsset(alice, new AssetMoney(goldId, 4))
                              .SetChange(satoshi)
                              .BuildTransaction(true);

            repo.Transactions.Put(sendToAlice);
            color = ColoredTransaction.FetchColors(sendToAlice, repo);
            // see transaction and its color
            Console.WriteLine(sendToAlice);
            Console.WriteLine(color);
            // have made a unit test that emits and transfers some assets w/o any external dependencies
        }