Example #1
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);
        }
        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);
        }
        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 #4
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);
        }
        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 #6
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 #7
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);
        }
        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
        }