Beispiel #1
0
		public WalletCreation()
		{
			SignatureRequired = 1;
			RootKeys = new ExtPubKey[0];
			Network = Network.Main;
			DerivationPath = new KeyPath();
		}
Beispiel #2
0
		public WalletCreation()
		{
			SignatureRequired = 1;
			RootKeys = new ExtPubKey[0];
			Network = Network.Main;
			DerivationPath = new KeyPath();
			Name = Guid.NewGuid().ToString();
		}
Beispiel #3
0
		public WalletCreation()
		{
			SignatureRequired = 1;
			RootKeys = new ExtPubKey[0];
			Network = Network.Main;
			DerivationPath = new KeyPath();
			Name = Guid.NewGuid().ToString();
			PurgeConnectionOnFilterChange = true;
		}
Beispiel #4
0
        public async Task TrezorTKataAsync()
        {
            // --- USER INTERACTIONS ---
            //
            // Connect and initialize your Trezor T with the following seed phrase:
            // more maid moon upgrade layer alter marine screen benefit way cover alcohol
            // Run this test.
            // displayaddress request: refuse 1 time
            // displayaddress request: confirm 2 times
            // displayaddress request: confirm 1 time
            // signtx request: refuse 1 time
            // signtx request: Hold to confirm
            //
            // --- USER INTERACTIONS ---

            var network = Network.Main;
            var client  = new HwiClient(network);

            using var cts = new CancellationTokenSource(ReasonableRequestTimeout);
            var enumerate = await client.EnumerateAsync(cts.Token);

            Assert.Single(enumerate);
            HwiEnumerateEntry entry = enumerate.Single();

            Assert.NotNull(entry.Path);
            Assert.Equal(HardwareWalletModels.Trezor_T, entry.Model);
            Assert.NotNull(entry.Fingerprint);

            string devicePath = entry.Path;
            HardwareWalletModels deviceType  = entry.Model;
            HDFingerprint        fingerprint = entry.Fingerprint.Value;

            await Assert.ThrowsAsync <HwiException>(async() => await client.SetupAsync(deviceType, devicePath, false, cts.Token));

            await Assert.ThrowsAsync <HwiException>(async() => await client.RestoreAsync(deviceType, devicePath, false, cts.Token));

            // Trezor T doesn't support it.
            await Assert.ThrowsAsync <HwiException>(async() => await client.PromptPinAsync(deviceType, devicePath, cts.Token));

            // Trezor T doesn't support it.
            await Assert.ThrowsAsync <HwiException>(async() => await client.SendPinAsync(deviceType, devicePath, 1111, cts.Token));

            KeyPath   keyPath1 = KeyManager.DefaultAccountKeyPath;
            KeyPath   keyPath2 = KeyManager.DefaultAccountKeyPath.Derive(1);
            ExtPubKey xpub1    = await client.GetXpubAsync(deviceType, devicePath, keyPath1, cts.Token);

            ExtPubKey xpub2 = await client.GetXpubAsync(deviceType, devicePath, keyPath2, cts.Token);

            Assert.NotNull(xpub1);
            Assert.NotNull(xpub2);
            Assert.NotEqual(xpub1, xpub2);

            // USER SHOULD REFUSE ACTION
            await Assert.ThrowsAsync <HwiException>(async() => await client.DisplayAddressAsync(deviceType, devicePath, keyPath1, cts.Token));

            // USER: CONFIRM
            BitcoinWitPubKeyAddress address1 = await client.DisplayAddressAsync(deviceType, devicePath, keyPath1, cts.Token);

            // USER: CONFIRM
            BitcoinWitPubKeyAddress address2 = await client.DisplayAddressAsync(fingerprint, keyPath2, cts.Token);

            Assert.NotNull(address1);
            Assert.NotNull(address2);
            Assert.NotEqual(address1, address2);
            var expectedAddress1 = xpub1.PubKey.GetAddress(ScriptPubKeyType.Segwit, network);
            var expectedAddress2 = xpub2.PubKey.GetAddress(ScriptPubKeyType.Segwit, network);

            Assert.Equal(expectedAddress1, address1);
            Assert.Equal(expectedAddress2, address2);

            // USER SHOULD REFUSE ACTION
            var result = await Assert.ThrowsAsync <HwiException>(async() => await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token));

            Assert.Equal(HwiErrorCode.ActionCanceled, result.ErrorCode);

            // USER: Hold to confirm
            PSBT signedPsbt = await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token);

            Transaction signedTx = signedPsbt.GetOriginalTransaction();

            Assert.Equal(Psbt.GetOriginalTransaction().GetHash(), signedTx.GetHash());

            var checkResult = signedTx.Check();

            Assert.Equal(TransactionCheckResult.Success, checkResult);
        }
Beispiel #5
0
        /// <summary>
        /// Adds an account to the current wallet.
        /// </summary>
        /// <remarks>
        /// The name given to the account is of the form "account (i)" by default, where (i) is an incremental index starting at 0.
        /// According to BIP44, an account at index (i) can only be created when the account at index (i - 1) contains at least one transaction.
        /// </remarks>
        /// <seealso cref="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki"/>
        /// <param name="coinType">The type of coin this account is for.</param>
        /// <param name="extPubKey">The extended public key for the wallet<see cref="EncryptedSeed"/>.</param>
        /// <param name="accountIndex">Zero-based index of the account to add.</param>
        /// <param name="accountCreationTime">Creation time of the account to be created.</param>
        /// <returns>A new HD account.</returns>
        public HdAccount AddNewAccount(CoinType coinType, ExtPubKey extPubKey, int accountIndex, DateTimeOffset accountCreationTime)
        {
            AccountRoot accountRoot = this.AccountsRoot.Single(a => a.CoinType == coinType);

            return(accountRoot.AddNewAccount(extPubKey, accountIndex, this.Network, accountCreationTime));
        }
Beispiel #6
0
        public LoadWalletViewModel(WalletManagerViewModel owner, LoadWalletType loadWalletType)
            : base(loadWalletType == LoadWalletType.Password ? "Test Password" : (loadWalletType == LoadWalletType.Desktop ? "Load Wallet" : "Hardware Wallet"))
        {
            Owner          = owner;
            Password       = "";
            LoadWalletType = loadWalletType;
            Wallets        = new ObservableCollection <LoadWalletEntry>();
            WalletLock     = new object();

            this.WhenAnyValue(x => x.SelectedWallet)
            .Subscribe(_ => TrySetWalletStates());

            this.WhenAnyValue(x => x.IsWalletOpened)
            .Subscribe(_ => TrySetWalletStates());

            this.WhenAnyValue(x => x.IsBusy)
            .Subscribe(_ => TrySetWalletStates());

            LoadCommand           = ReactiveCommand.CreateFromTask(async() => await LoadWalletAsync(), this.WhenAnyValue(x => x.CanLoadWallet));
            TestPasswordCommand   = ReactiveCommand.CreateFromTask(async() => await LoadKeyManagerAsync(requirePassword: true, isHardwareWallet: false), this.WhenAnyValue(x => x.CanTestPassword));
            OpenFolderCommand     = ReactiveCommand.Create(OpenWalletsFolder);
            ImportColdcardCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                try
                {
                    var ofd = new OpenFileDialog
                    {
                        AllowMultiple = false,
                        Title         = "Import Coldcard"
                    };

                    if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
                    }

                    var selected = await ofd.ShowAsync(Application.Current.MainWindow, fallBack: true);
                    if (selected != null && selected.Any())
                    {
                        var path       = selected.First();
                        var jsonString = await File.ReadAllTextAsync(path);
                        var json       = JObject.Parse(jsonString);
                        var xpubString = json["ExtPubKey"].ToString();
                        var mfpString  = json["MasterFingerprint"].ToString();

                        // https://github.com/zkSNACKs/WalletWasabi/pull/1663#issuecomment-508073066
                        // Coldcard 2.1.0 improperly implemented Wasabi skeleton fingerpring at first, so we must reverse byte order.
                        // The solution was to add a ColdCardFirmwareVersion json field from 2.1.1 and correct the one generated by 2.1.0.
                        var coldCardVersionString = json["ColdCardFirmwareVersion"]?.ToString();
                        var reverseByteOrder      = false;
                        if (coldCardVersionString is null)
                        {
                            reverseByteOrder = true;
                        }
                        else
                        {
                            Version coldCardVersion = new Version(coldCardVersionString);

                            if (coldCardVersion == new Version("2.1.0"))                             // Should never happen though.
                            {
                                reverseByteOrder = true;
                            }
                        }
                        HDFingerprint mfp   = NBitcoinHelpers.BetterParseHDFingerprint(mfpString, reverseByteOrder: reverseByteOrder);
                        ExtPubKey extPubKey = NBitcoinHelpers.BetterParseExtPubKey(xpubString);
                        Logger.LogInfo("Creating new wallet file.");
                        var walletName     = Global.GetNextHardwareWalletName(customPrefix: "Coldcard");
                        var walletFullPath = Global.GetWalletFullPath(walletName);
                        KeyManager.CreateNewHardwareWalletWatchOnly(mfp, extPubKey, walletFullPath);
                        owner.SelectLoadWallet();
                    }
                }
                catch (Exception ex)
                {
                    SetWarningMessage(ex.ToTypeMessageString());
                    Logger.LogError(ex);
                }
            }, outputScheduler: RxApp.MainThreadScheduler);

            OpenBrowserCommand = ReactiveCommand.Create <string>(x =>
            {
                IoHelpers.OpenBrowser(x);
            });

            OpenBrowserCommand.ThrownExceptions.Subscribe(ex => Logger.LogWarning(ex));
            LoadCommand.ThrownExceptions.Subscribe(ex => Logger.LogWarning(ex));
            TestPasswordCommand.ThrownExceptions.Subscribe(ex => Logger.LogWarning(ex));
            OpenFolderCommand.ThrownExceptions.Subscribe(ex => Logger.LogWarning(ex));
            ImportColdcardCommand.ThrownExceptions.Subscribe(ex => Logger.LogWarning(ex));

            SetLoadButtonText();

            IsHwWalletSearchTextVisible = LoadWalletType == LoadWalletType.Hardware;
        }
Beispiel #7
0
 public static KeyManager CreateNewWatchOnly(ExtPubKey extPubKey, string filePath = null)
 {
     return(new KeyManager(null, null, null, extPubKey, null, AbsoluteMinGapLimit, new BlockchainState(), filePath));
 }
Beispiel #8
0
        public KeyManager(BitcoinEncryptedSecretNoEC encryptedSecret, byte[] chainCode, HDFingerprint?masterFingerprint, ExtPubKey extPubKey, bool?passwordVerified, int?minGapLimit, BlockchainState blockchainState, string filePath = null, KeyPath accountKeyPath = null)
        {
            HdPubKeys               = new List <HdPubKey>();
            HdPubKeyScriptBytes     = new List <byte[]>();
            ScriptHdPubKeyMap       = new Dictionary <Script, HdPubKey>();
            HdPubKeysLock           = new object();
            HdPubKeyScriptBytesLock = new object();
            ScriptHdPubKeyMapLock   = new object();
            BlockchainStateLock     = new object();

            EncryptedSecret   = encryptedSecret;
            ChainCode         = chainCode;
            MasterFingerprint = masterFingerprint;
            ExtPubKey         = Guard.NotNull(nameof(extPubKey), extPubKey);

            PasswordVerified = passwordVerified;
            SetMinGapLimit(minGapLimit);

            BlockchainState = blockchainState ?? new BlockchainState();
            AccountKeyPath  = accountKeyPath ?? DefaultAccountKeyPath;

            SetFilePath(filePath);
            ToFileLock = new object();
            ToFile();
        }
Beispiel #9
0
        public KeyManager(BitcoinEncryptedSecretNoEC encryptedSecret, byte[] chainCode, ExtPubKey extPubKey, bool?passwordVerified, BlockchainState blockchainState, string filePath = null)
        {
            HdPubKeys               = new List <HdPubKey>();
            HdPubKeyScriptBytes     = new List <byte[]>();
            ScriptHdPubkeyMap       = new Dictionary <Script, HdPubKey>();
            HdPubKeysLock           = new object();
            HdPubKeyScriptBytesLock = new object();
            ScriptHdPubkeyMapLock   = new object();
            BlockchainStateLock     = new object();

            EncryptedSecret = Guard.NotNull(nameof(encryptedSecret), encryptedSecret);
            ChainCode       = Guard.NotNull(nameof(chainCode), chainCode);
            ExtPubKey       = Guard.NotNull(nameof(extPubKey), extPubKey);

            PasswordVerified = passwordVerified;

            BlockchainState = blockchainState ?? new BlockchainState();

            SetFilePath(filePath);
            ToFileLock = new object();
            ToFile();
        }
 /// <summary>
 /// Create a single signature derivation strategy from public key
 /// </summary>
 /// <param name="publicKey">The public key of the wallet</param>
 /// <param name="options">Derivation options</param>
 /// <returns></returns>
 public DerivationStrategyBase CreateDirectDerivationStrategy(ExtPubKey publicKey, DerivationStrategyOptions options = null)
 {
     return(CreateDirectDerivationStrategy(publicKey.GetWif(Network), options));
 }
        private static void Main()
        {
            RandomUtils.Random = new UnsecureRandom();


            //==========================================================================================
            //Chapter. HD Wallet(BIP 32)

            //Let’s keep in mind the problems that we want to resolve:
            //1.Prevent outdated backups
            //2.Delegating key / address generation to an untrusted peer
            //A “Deterministic” wallet would fix our backup problem. With such a wallet, you would have to save only the seed.From this seed, you can generate the same series of private keys over and over.
            //This is what the “Deterministic” stands for.
            //As you can see, from the master key, I can generate new keys:

            //Create a masterKey.
            ExtKey masterKey = new ExtKey();

            Console.WriteLine("Master key : " + masterKey.ToString(Network.Main));
            //Output:
            //xprv9s21ZrQH143K46gx2C5V4o9iEn52h9y2Y7LykXSTVPFLM28kyMuj8BkicTd3uAiqrVPxb3BZ4fVkzKDwzxVpkEhsqS5HD6vrGDf5D613Lwt

            //Create 5 derived keys based on the masterKey.
            for (int i = 0; i < 5; i++)
            {
                ExtKey key = masterKey.Derive((uint)i);
                Console.WriteLine("Key " + i + " : " + key.ToString(Network.Main));
            }
            //Output:
            //Key 0 : xprv9uvuViKQnT4vo8rSWEtXYXxDLMvt4SrSToHVs3ZpzKXpHd5deZNDKj57XnrQ8rRZSANm3oZBjXN245oy161otLGddxch46UrtTH3tB5fMKQ
            //Key 1 : xprv9uvuViKQnT4vqG7czoZ1VYGPmK9yhXBLGYKgZpiB271L6ekwbzyPo9fHE3F4cAay6qbwczt1K35cEF3HrykPGR9agzmHNhBPDSZtyoxhMbh
            //Key 2 : xprv9uvuViKQnT4vs7GpRKcouP8TP8ERksBG5GdNmocVDp6R8nHGTYH4qwG8PY75hHGKsTKQdQmRAiQnZim6UuYguiaUx1dpqGXafM1Lr1WEkzy
            //Key 3 : xprv9uvuViKQnT4vwDWmEvSEae5nLGbKLMmeMLLCc5MDD9iVSDhDqNpzSErHBYm1TRZGfDM2YbHZyCtmas1d2JRSWMYLKbJMGhyB9ynSbyLTh14
            //Key 4 : xprv9uvuViKQnT4vxgXFvxk6FhKYgzU8NgW3xMfqciveTWKpJDkdCmQiJjAdGUij7QckJ1ZBqKuY1RSyw9JeGM7P6cTMPZqVZBu9SCAfHEpp8SS



            //You only need to save the masterKey, since you can generate the same suite of private keys over and over.
            //As you can see, these keys are ExtKey and not Key as you are used to. However, this should not stop you since you have the real private key inside of these keys:


            //You can go back from a Key to an ExtKey by supplying the Key and the ChainCode to the ExtKey constructor. This works as follows:

            //Create extKey.
            ExtKey extKey = new ExtKey();

            //Get ChainCode from extKey.
            byte[] chainCode = extKey.ChainCode;
            //Get a PrivateKey from extKey.
            Key privateKeyFromExtKey = extKey.PrivateKey;
            //Supply a private key and ChainCode to the ExtKey constructor to go back from a Key to an ExtKey.
            ExtKey newExtKey = new ExtKey(privateKeyFromExtKey, chainCode);


            //The Base58 type equivalent of ExtKey is called BitcoinExtKey.
            //But how can we solve our second problem: Delegating address creation to a peer that can potentially be hacked like a payment server?
            //The trick is that you can “neuter” your master key, then you have a public (without private key) version of the master key.From this neutered version, a third party can generate public keys without knowing the private key.

            //Neuter the master key, then you get a master public key.
            ExtPubKey masterPubKey = masterKey.Neuter();

            //Genarate 5 derived public keys from the master public key.
            for (int i = 0; i < 5; i++)
            {
                ExtPubKey pubkey = masterPubKey.Derive((uint)i);
                Console.WriteLine("PubKey " + i + " : " + pubkey.ToString(Network.Main));
            }

            //So imagine that your payment server generates pubkey1, and then you can get the corresponding private key with your private master key.
            masterKey    = new ExtKey();
            masterPubKey = masterKey.Neuter();

            //The payment server generates pubkey1.
            ExtPubKey pubkey1 = masterPubKey.Derive((uint)1);

            //You get the private key of pubkey1
            ExtKey key1 = masterKey.Derive((uint)1);

            //Check if it is legit
            Console.WriteLine("Generated address : " + pubkey1.PubKey.GetAddress(Network.Main));
            Console.WriteLine("Expected address : " + key1.PrivateKey.PubKey.GetAddress(Network.Main));
            //Generated address: 1Jy8nALZNqpf4rFN9TWG2qXapZUBvquFfX
            //Expected address:	 1Jy8nALZNqpf4rFN9TWG2qXapZUBvquFfX

            //ExtPubKey is similar to ExtKey except that it holds a public key and not a private key.



            //Now we have seen how Deterministic keys solve our problems, let’s speak about what the “hierarchical” is for.

            //In the previous exercise, we have seen that by combining master key + index we could generate another key.We call this process Derivation, the master key is the parent key, and any generated keys are called child keys.

            //However, you can also derivate children from the child key.This is what the “hierarchical” stands for.

            //This is why conceptually more generally you can say: Parent Key + KeyPath => Child Key



            //Now that we have seen how Deterministic keys solve our problems, let’s speak about what the “hierarchical” is for.
            //In the previous exercise, we have seen that we could generate another derived keys based on a master key by invoking Derive() method on the master key passing integer numbers into an argument.
            //We call this process a Derivation. And in this scheme, a master key is a parent key, and any generated keys based on the master key are called child keys.
            //However, I can also derivate children from the "child key". This is what the “Hierarchical” stands for.
            //This is why conceptually more generally you can say: Parent Key + KeyPath => Child Key

            //Just suppose the scenario that there is a parent key, "Parent".
            //And there can be child keys derived from "Parent". => Child(1),Child(2),Child(3),Child(4).
            //And there can be child keys derived from Child(1). => Child(1, 1), Child(1, 2).

            //In this diagram, you can derivate Child(1,1) from a parent in two different way:
            //First generate a parent key.
            ExtKey parent = new ExtKey();

            ExtKey child11ByFirstWay = parent.Derive(1).Derive(1);

            Console.WriteLine(child11ByFirstWay);

            //Or above code can be expressed in this way, resulting in an identical output.
            ExtKey child11BySecondWay = parent.Derive(new KeyPath("1/1"));

            Console.WriteLine(child11BySecondWay);

            //Remember that Ancestor ExtKey + KeyPath = Child ExtKey.

            //This process works indenticaly for ExtPubKey.

            //Why do you need hierarchical keys? It's because it might be a nice way to classify the type of my keys for multiple accounts. This point is more neat than on BIP44. It also permits segmenting account rights across an organization.

            //Imagine you are the CEO of a company. You want control over all wallets, but you don’t want the Accounting department to spend the money from the Marketing department.

            //So, for implementing this constraint, your first idea would be to generate one hierarchy for each department.

            //CEO Key(the master key)-> derived child Keys from a master key(the CEO key) : Marketing(0), Accounting(0).
            //Marketing(0)->Child Keys:Marketing(0, 1), Marketing(0, 2).
            //Accounting(0)->Child Keys:Accounting(0, 2), Accounting(0, 2).

            //However, in such a case, Accounting and Marketing would be able to recover the CEO’s private key, because we defined such child keys as non-hardened.

            //Parent ExtPubKey + Child ExtKey(non hardened) => Parent ExtKey.


            ExtKey ceoKey = new ExtKey();

            Console.WriteLine("CEO: " + ceoKey.ToString(Network.Main));
            //Note the hardened is false.
            ExtKey accountingKey = ceoKey.Derive(0, hardened: false);

            ExtPubKey ceoPubkey = ceoKey.Neuter();

            //Recover the CEO key by the accounting private key and the CEO public key.
            ExtKey ceoKeyRecovered = accountingKey.GetParentExtKey(ceoPubkey);

            Console.WriteLine("CEO recovered: " + ceoKeyRecovered.ToString(Network.Main));
            //CEO: xprv9s21ZrQH143K2XcJU89thgkBehaMqvcj4A6JFxwPs6ZzGYHYT8dTchd87TC4NHSwvDuexuFVFpYaAt3gztYtZyXmy2hCVyVyxumdxfDBpoC
            //CEO recovered: xprv9s21ZrQH143K2XcJU89thgkBehaMqvcj4A6JFxwPs6ZzGYHYT8dTchd87TC4NHSwvDuexuFVFpYaAt3gztYtZyXmy2hCVyVyxumdxfDBpoC

            //In other words, a non-hardened key can “climb” the hierarchy. Non-hardened keys should only be used for categorizing accounts that belong to a point of single control.

            //So in our case, the CEO should create child keys as hardened ones, so the accounting department will not be able to climb the hierarchy.



            //Identical process to above code except for hardened is true.
            Console.WriteLine("CEO: " + ceoKey.ToString(Network.Main));
            ExtKey accountingKeyHardened = ceoKey.Derive(0, hardened: true);

            Console.WriteLine(accountingKeyHardened);
            //Generate derived child accountKeys from ceoKey
            //However, since accountKeys are hardened, they can't climb hierarchy towards ceoKey.
            ExtPubKey ceoPubkeyToTestForHardened = ceoKey.Neuter();

            Console.WriteLine(ceoPubkeyToTestForHardened);
            ////At this point, it'll be crashed by this climbing attempt.
            //ExtKey ceoKeyRecovered = accountingKeyHardened.GetParentExtKey(ceoPubkeyToTestForHardened);



            //You can also create hardened keys via the ExtKey.Derivate(KeyPath), by using an apostrophe(') after a child’s index such as "1/2/3'"
            var nonHardenedChildKey = new KeyPath("1/2/3");
            var hardenedChildKey    = new KeyPath("1/2/3'");

            Console.WriteLine(nonHardenedChildKey);
            Console.WriteLine(hardenedChildKey);


            //So let’s imagine that the Accounting Department generates 1 parent key for each customer, and a child for each of the customer’s payments.

            //As the CEO, you want to spend the money on one of these addresses.Here is how you would proceed.
            ceoKey = new ExtKey();
            //Child key is generated as hardened, so it can't climb hierarchy upwards to a parent key.
            string  accounting = "1'";
            int     customerId = 5;
            int     paymentId  = 50;
            KeyPath path       = new KeyPath(accounting + "/" + customerId + "/" + paymentId);
            //Path will be "1'/5/50"
            ExtKey paymentKey = ceoKey.Derive(path);

            Console.WriteLine(paymentKey);


            //===========================================================================================
            //Chapter. Mnemonic Code for HD Keys (BIP39)


            //As you have seen, generating HD keys is easy.However, what if we want an easy way to transmit such a key by telephone or hand writing?

            //Cold wallets like Trezor, generate the HD Keys from a sentence that can easily be written down. They call such a sentence “the seed” or “mnemonic”. And it can eventually be protected by a password or a PIN.



            //The language that you use to generate your 'easy to write' sentence is called a Wordlist.


            //Wordlist + mnemonic + password => HD Root key.


            Mnemonic mnemo  = new Mnemonic(Wordlist.English, WordCount.Twelve);
            ExtKey   hdRoot = mnemo.DeriveExtKey("my password");

            Console.WriteLine(mnemo);
            Console.WriteLine(hdRoot);

            //Now, if you have the mnemonic and the password, you can recover the hdRoot key.
            mnemo = new Mnemonic("minute put grant neglect anxiety case globe win famous correct turn link", Wordlist.English);
            ExtKey hdRoot1 = mnemo.DeriveExtKey("my password");

            Console.WriteLine(hdRoot1);

            //Currently supported languages for wordlist are, English, Japanese, Spanish, Chinese (simplified and traditional).
        }
Beispiel #12
0
        public async Task LedgerNanoSKataAsync()
        {
            // --- USER INTERACTIONS ---
            //
            // Connect and initialize your Nano S with the following seed phrase:
            // more maid moon upgrade layer alter marine screen benefit way cover alcohol
            // Run this test.
            // displayaddress request(derivation path): approve
            // displayaddress request: reject
            // displayaddress request(derivation path): approve
            // displayaddress request: approve
            // displayaddress request(derivation path): approve
            // displayaddress request: approve
            // signtx request: reject
            // signtx request: accept
            // confirm transaction: accept and send
            // unverified inputs: continue
            // signtx request: accept
            // confirm transaction: accept and send
            //
            // --- USER INTERACTIONS ---

            var network = Network.Main;
            var client  = new HwiClient(network);

            using var cts = new CancellationTokenSource(ReasonableRequestTimeout);
            var enumerate = await client.EnumerateAsync(cts.Token);

            HwiEnumerateEntry entry = Assert.Single(enumerate);

            Assert.NotNull(entry.Path);
            Assert.Equal(HardwareWalletModels.Ledger_Nano_S, entry.Model);
            Assert.True(entry.Fingerprint.HasValue);
            Assert.Null(entry.Code);
            Assert.Null(entry.Error);
            Assert.Null(entry.SerialNumber);
            Assert.False(entry.NeedsPassphraseSent);
            Assert.False(entry.NeedsPinSent);

            string devicePath = entry.Path;
            HardwareWalletModels deviceType  = entry.Model;
            HDFingerprint        fingerprint = entry.Fingerprint.Value;

            await Assert.ThrowsAsync <HwiException>(async() => await client.SetupAsync(deviceType, devicePath, false, cts.Token));

            await Assert.ThrowsAsync <HwiException>(async() => await client.RestoreAsync(deviceType, devicePath, false, cts.Token));

            await Assert.ThrowsAsync <HwiException>(async() => await client.PromptPinAsync(deviceType, devicePath, cts.Token));

            await Assert.ThrowsAsync <HwiException>(async() => await client.SendPinAsync(deviceType, devicePath, 1111, cts.Token));

            KeyPath   keyPath1 = KeyManager.DefaultAccountKeyPath;
            KeyPath   keyPath2 = KeyManager.DefaultAccountKeyPath.Derive(1);
            ExtPubKey xpub1    = await client.GetXpubAsync(deviceType, devicePath, keyPath1, cts.Token);

            ExtPubKey xpub2 = await client.GetXpubAsync(deviceType, devicePath, keyPath2, cts.Token);

            Assert.NotNull(xpub1);
            Assert.NotNull(xpub2);
            Assert.NotEqual(xpub1, xpub2);

            // USER SHOULD REFUSE ACTION
            await Assert.ThrowsAsync <HwiException>(async() => await client.DisplayAddressAsync(deviceType, devicePath, keyPath1, cts.Token));

            // USER: CONFIRM
            BitcoinWitPubKeyAddress address1 = await client.DisplayAddressAsync(deviceType, devicePath, keyPath1, cts.Token);

            // USER: CONFIRM
            BitcoinWitPubKeyAddress address2 = await client.DisplayAddressAsync(fingerprint, keyPath2, cts.Token);

            Assert.NotNull(address1);
            Assert.NotNull(address2);
            Assert.NotEqual(address1, address2);
            var expectedAddress1 = xpub1.PubKey.GetAddress(ScriptPubKeyType.Segwit, network);
            var expectedAddress2 = xpub2.PubKey.GetAddress(ScriptPubKeyType.Segwit, network);

            Assert.Equal(expectedAddress1, address1);
            Assert.Equal(expectedAddress2, address2);

            // USER: REFUSE
            var ex = await Assert.ThrowsAsync <HwiException>(async() => await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token));

            Assert.Equal(HwiErrorCode.BadArgument, ex.ErrorCode);

            // USER: CONFIRM
            var nullFailEx = await Assert.ThrowsAsync <PSBTException>(async() => await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token));

            Assert.Equal(nullFailEx.Message.Contains("NullFail"), true);

            // USER: CONFIRM
            PSBT signedPsbt = await Gui.Controls.WalletExplorer.SendTabViewModel.SignPsbtWithoutInputTxsAsync(client, fingerprint, Psbt, cts.Token);

            Transaction signedTx = signedPsbt.GetOriginalTransaction();

            Assert.Equal(Psbt.GetOriginalTransaction().GetHash(), signedTx.GetHash());

            var checkResult = signedTx.Check();

            Assert.Equal(TransactionCheckResult.Success, checkResult);
        }
Beispiel #13
0
        public static void CreateWallet()
        {
            var         secret    = new BitcoinSecret("L3E7oUgKrmF4ED4xTSKem3NjduRcCVNmfG59wTG3p28YGkY9a5og");
            ExtKey      masterKey = new ExtKey();
            Transaction tx;
            var         input = new TxIn();
            //input.PrevOut = new OutPoint(new uint256("1CxZnG2Mb31YHcsoKx18yshWdbcM9Y1mb5"),0);
            Coin y = new Coin();

            y.Amount = 5;

            //ColoredTransaction coloredTransaction = new ColoredTransaction();
            Console.WriteLine("Address: " + secret.PubKey.GetAddress(Network.Main));
            Console.WriteLine("Key: " + masterKey.GetWif(Network.Main));
            Console.WriteLine("Master key : " + masterKey.ToString(Network.Main));
            for (int i = 0; i < 5; i++)
            {
                ExtKey key2 = masterKey.Derive((uint)i);
                Console.WriteLine("Key " + i + " : " + key2.ToString(Network.Main));
            }

            ExtKey extKey = new ExtKey();

            byte[] chainCode = extKey.ChainCode;
            Key    key       = extKey.PrivateKey;

            ExtKey newExtKey = new ExtKey(key, chainCode);


            ExtPubKey masterPubKey = masterKey.Neuter();

            for (int i = 0; i < 5; i++)
            {
                ExtPubKey pubkey = masterPubKey.Derive((uint)i);
                Console.WriteLine("PubKey " + i + " : " + pubkey.ToString(Network.Main));
            }

            masterKey    = new ExtKey();
            masterPubKey = masterKey.Neuter();


            ExtPubKey pubkey1 = masterPubKey.Derive((uint)1);


            ExtKey key1 = masterKey.Derive((uint)1);


            Console.WriteLine("Generated address : " + pubkey1.PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.Main));
            Console.WriteLine("Expected address : " + key1.PrivateKey.PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.Main));

            ExtKey parent  = new ExtKey();
            ExtKey child11 = parent.Derive(new KeyPath("1/1"));

            ExtKey Key = new ExtKey();

            Console.WriteLine("Key: " + Key.ToString(Network.Main));
            ExtKey accountingKey = Key.Derive(0, hardened: false);

            ExtPubKey ceoPubkey = Key.Neuter();

            ExtKey ceoKeyRecovered = accountingKey.GetParentExtKey(ceoPubkey);

            Console.WriteLine("Key recovered: " + ceoKeyRecovered.ToString(Network.Main));
            var nonHardened = new KeyPath("1/2/3");
            var hardened    = new KeyPath("1/2/3'");

            Key = new ExtKey();
            string  accounting = "1'";
            int     customerId = 5;
            int     paymentId  = 50;
            KeyPath path       = new KeyPath(accounting + "/" + customerId + "/" + paymentId);
            ExtKey  paymentKey = Key.Derive(path);
        }
Beispiel #14
0
        public LoadWalletViewModel(WalletManagerViewModel owner, LoadWalletType loadWalletType)
            : base(loadWalletType == LoadWalletType.Password ? "Test Password" : (loadWalletType == LoadWalletType.Desktop ? "Load Wallet" : "Hardware Wallet"))
        {
            Global = Locator.Current.GetService <Global>();

            Owner          = owner;
            Password       = "";
            LoadWalletType = loadWalletType;
            Wallets        = new ObservableCollection <LoadWalletEntry>();
            IsHwWalletSearchTextVisible = false;

            this.WhenAnyValue(x => x.SelectedWallet)
            .Subscribe(_ => TrySetWalletStates());

            this.WhenAnyValue(x => x.IsWalletOpened)
            .Subscribe(_ => TrySetWalletStates());

            this.WhenAnyValue(x => x.IsBusy)
            .Subscribe(_ => TrySetWalletStates());

            LoadCommand           = ReactiveCommand.CreateFromTask(async() => await LoadWalletAsync(), this.WhenAnyValue(x => x.CanLoadWallet));
            TestPasswordCommand   = ReactiveCommand.CreateFromTask(async() => await LoadKeyManagerAsync(requirePassword: true, isHardwareWallet: false), this.WhenAnyValue(x => x.CanTestPassword));
            OpenFolderCommand     = ReactiveCommand.Create(OpenWalletsFolder);
            ImportColdcardCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                var ofd = new OpenFileDialog
                {
                    AllowMultiple = false,
                    Title         = "Import Coldcard"
                };

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    ofd.Directory = Path.Combine("/media", Environment.UserName);
                }
                else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    ofd.Directory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
                }

                var window   = (Application.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).MainWindow;
                var selected = await ofd.ShowAsync(window, fallBack: true);
                if (selected != null && selected.Any())
                {
                    var path       = selected.First();
                    var jsonString = await File.ReadAllTextAsync(path);
                    var json       = JObject.Parse(jsonString);
                    var xpubString = json["ExtPubKey"].ToString();
                    var mfpString  = json["MasterFingerprint"].ToString();

                    // https://github.com/zkSNACKs/WalletWasabi/pull/1663#issuecomment-508073066
                    // Coldcard 2.1.0 improperly implemented Wasabi skeleton fingerprint at first, so we must reverse byte order.
                    // The solution was to add a ColdCardFirmwareVersion json field from 2.1.1 and correct the one generated by 2.1.0.
                    var coldCardVersionString = json["ColdCardFirmwareVersion"]?.ToString();
                    var reverseByteOrder      = false;
                    if (coldCardVersionString is null)
                    {
                        reverseByteOrder = true;
                    }
                    else
                    {
                        Version coldCardVersion = new Version(coldCardVersionString);

                        if (coldCardVersion == new Version("2.1.0"))                         // Should never happen though.
                        {
                            reverseByteOrder = true;
                        }
                    }

                    var bytes         = ByteHelpers.FromHex(Guard.NotNullOrEmptyOrWhitespace(nameof(mfpString), mfpString, trim: true));
                    HDFingerprint mfp = reverseByteOrder ? new HDFingerprint(bytes.Reverse().ToArray()) : new HDFingerprint(bytes);

                    ExtPubKey extPubKey = NBitcoinHelpers.BetterParseExtPubKey(xpubString);

                    Logger.LogInfo("Creating a new wallet file.");
                    var walletName     = Global.GetNextHardwareWalletName(customPrefix: "Coldcard");
                    var walletFullPath = Global.GetWalletFullPath(walletName);
                    KeyManager.CreateNewHardwareWalletWatchOnly(mfp, extPubKey, walletFullPath);
                    owner.SelectLoadWallet();
                }
            });

            EnumerateHardwareWalletsCommand = ReactiveCommand.CreateFromTask(async() => await EnumerateHardwareWalletsAsync());

            OpenBrowserCommand = ReactiveCommand.CreateFromTask <string>(IoHelpers.OpenBrowserAsync);

            Observable
            .Merge(OpenBrowserCommand.ThrownExceptions)
            .Merge(LoadCommand.ThrownExceptions)
            .Merge(TestPasswordCommand.ThrownExceptions)
            .Merge(OpenFolderCommand.ThrownExceptions)
            .Merge(ImportColdcardCommand.ThrownExceptions)
            .Merge(EnumerateHardwareWalletsCommand.ThrownExceptions)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(ex =>
            {
                Logger.LogError(ex);
                NotificationHelpers.Error(ex.ToUserFriendlyString());
            });

            SetLoadButtonText();
        }
Beispiel #15
0
        public async Task TrezorTMockTestsAsync(Network network)
        {
            var client = new HwiClient(network, new HwiProcessBridgeMock(HardwareWalletModels.Trezor_T));

            using var cts = new CancellationTokenSource(ReasonableRequestTimeout);
            IEnumerable <HwiEnumerateEntry> enumerate = await client.EnumerateAsync(cts.Token);

            Assert.Single(enumerate);
            HwiEnumerateEntry entry = enumerate.Single();

            Assert.Equal(HardwareWalletModels.Trezor_T, entry.Model);
            Assert.Equal("webusb: 001:4", entry.Path);
            Assert.False(entry.NeedsPassphraseSent);
            Assert.False(entry.NeedsPinSent);
            Assert.NotNull(entry.Error);
            Assert.NotEmpty(entry.Error);
            Assert.Equal(HwiErrorCode.DeviceNotInitialized, entry.Code);
            Assert.False(entry.IsInitialized());
            Assert.Null(entry.Fingerprint);

            var deviceType = entry.Model;
            var devicePath = entry.Path;

            await client.WipeAsync(deviceType, devicePath, cts.Token);

            await client.SetupAsync(deviceType, devicePath, false, cts.Token);

            await client.RestoreAsync(deviceType, devicePath, false, cts.Token);

            // Trezor T doesn't support it.
            var promptpin = await Assert.ThrowsAsync <HwiException>(async() => await client.PromptPinAsync(deviceType, devicePath, cts.Token));

            Assert.Equal("The PIN has already been sent to this device", promptpin.Message);
            Assert.Equal(HwiErrorCode.DeviceAlreadyUnlocked, promptpin.ErrorCode);

            var sendpin = await Assert.ThrowsAsync <HwiException>(async() => await client.SendPinAsync(deviceType, devicePath, 1111, cts.Token));

            Assert.Equal("The PIN has already been sent to this device", sendpin.Message);
            Assert.Equal(HwiErrorCode.DeviceAlreadyUnlocked, sendpin.ErrorCode);

            KeyPath   keyPath1 = KeyManager.DefaultAccountKeyPath;
            KeyPath   keyPath2 = KeyManager.DefaultAccountKeyPath.Derive(1);
            ExtPubKey xpub1    = await client.GetXpubAsync(deviceType, devicePath, keyPath1, cts.Token);

            ExtPubKey xpub2 = await client.GetXpubAsync(deviceType, devicePath, keyPath2, cts.Token);

            var expecteXpub1 = NBitcoinHelpers.BetterParseExtPubKey("xpub6DHjDx4gzLV37gJWMxYJAqyKRGN46MT61RHVizdU62cbVUYu9L95cXKzX62yJ2hPbN11EeprS8sSn8kj47skQBrmycCMzFEYBQSntVKFQ5M");
            var expecteXpub2 = NBitcoinHelpers.BetterParseExtPubKey("xpub6FJS1ne3STcKdQ9JLXNzZXidmCNZ9dxLiy7WVvsRkcmxjJsrDKJKEAXq4MGyEBM3vHEw2buqXezfNK5SNBrkwK7Fxjz1TW6xzRr2pUyMWFu");

            Assert.Equal(expecteXpub1, xpub1);
            Assert.Equal(expecteXpub2, xpub2);

            BitcoinWitPubKeyAddress address1 = await client.DisplayAddressAsync(deviceType, devicePath, keyPath1, cts.Token);

            BitcoinWitPubKeyAddress address2 = await client.DisplayAddressAsync(deviceType, devicePath, keyPath2, cts.Token);

            BitcoinAddress expectedAddress1;
            BitcoinAddress expectedAddress2;

            if (network == Network.Main)
            {
                expectedAddress1 = BitcoinAddress.Create("bc1q7zqqsmqx5ymhd7qn73lm96w5yqdkrmx7fdevah", Network.Main);
                expectedAddress2 = BitcoinAddress.Create("bc1qmaveee425a5xjkjcv7m6d4gth45jvtnj23fzyf", Network.Main);
            }
            else if (network == Network.TestNet)
            {
                expectedAddress1 = BitcoinAddress.Create("tb1q7zqqsmqx5ymhd7qn73lm96w5yqdkrmx7rtzlxy", Network.TestNet);
                expectedAddress2 = BitcoinAddress.Create("tb1qmaveee425a5xjkjcv7m6d4gth45jvtnjqhj3l6", Network.TestNet);
            }
            else if (network == Network.RegTest)
            {
                expectedAddress1 = BitcoinAddress.Create("bcrt1q7zqqsmqx5ymhd7qn73lm96w5yqdkrmx7pzmj3d", Network.RegTest);
                expectedAddress2 = BitcoinAddress.Create("bcrt1qmaveee425a5xjkjcv7m6d4gth45jvtnjz7tugn", Network.RegTest);
            }
            else
            {
                throw new NotSupportedNetworkException(network);
            }

            Assert.Equal(expectedAddress1, address1);
            Assert.Equal(expectedAddress2, address2);
        }
Beispiel #16
0
        public async Task LedgerNanoSTestsAsync(Network network)
        {
            var client = new HwiClient(network, new HwiProcessBridgeMock(HardwareWalletModels.Ledger_Nano_S));

            using var cts = new CancellationTokenSource(ReasonableRequestTimeout);
            IEnumerable <HwiEnumerateEntry> enumerate = await client.EnumerateAsync(cts.Token);

            Assert.Single(enumerate);
            HwiEnumerateEntry entry = enumerate.Single();

            Assert.Equal(HardwareWalletModels.Ledger_Nano_S, entry.Model);
            Assert.Equal(@"\\?\hid#vid_2c97&pid_0001&mi_00#7&e45ae20&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}", entry.Path);
            Assert.False(entry.NeedsPassphraseSent);
            Assert.False(entry.NeedsPinSent);
            Assert.Null(entry.Error);
            Assert.Null(entry.Code);
            Assert.True(entry.IsInitialized());
            Assert.Equal("4054d6f6", entry.Fingerprint.ToString());

            var deviceType = entry.Model;
            var devicePath = entry.Path;

            var wipe = await Assert.ThrowsAsync <HwiException>(async() => await client.WipeAsync(deviceType, devicePath, cts.Token));

            Assert.Equal("The Ledger Nano S does not support wiping via software", wipe.Message);
            Assert.Equal(HwiErrorCode.UnavailableAction, wipe.ErrorCode);

            var setup = await Assert.ThrowsAsync <HwiException>(async() => await client.SetupAsync(deviceType, devicePath, false, cts.Token));

            Assert.Equal("The Ledger Nano S does not support software setup", setup.Message);
            Assert.Equal(HwiErrorCode.UnavailableAction, setup.ErrorCode);

            var restore = await Assert.ThrowsAsync <HwiException>(async() => await client.RestoreAsync(deviceType, devicePath, false, cts.Token));

            Assert.Equal("The Ledger Nano S does not support restoring via software", restore.Message);
            Assert.Equal(HwiErrorCode.UnavailableAction, restore.ErrorCode);

            var promptpin = await Assert.ThrowsAsync <HwiException>(async() => await client.PromptPinAsync(deviceType, devicePath, cts.Token));

            Assert.Equal("The Ledger Nano S does not need a PIN sent from the host", promptpin.Message);
            Assert.Equal(HwiErrorCode.UnavailableAction, promptpin.ErrorCode);

            var sendpin = await Assert.ThrowsAsync <HwiException>(async() => await client.SendPinAsync(deviceType, devicePath, 1111, cts.Token));

            Assert.Equal("The Ledger Nano S does not need a PIN sent from the host", sendpin.Message);
            Assert.Equal(HwiErrorCode.UnavailableAction, sendpin.ErrorCode);

            KeyPath   keyPath1 = KeyManager.DefaultAccountKeyPath;
            KeyPath   keyPath2 = KeyManager.DefaultAccountKeyPath.Derive(1);
            ExtPubKey xpub1    = await client.GetXpubAsync(deviceType, devicePath, keyPath1, cts.Token);

            ExtPubKey xpub2 = await client.GetXpubAsync(deviceType, devicePath, keyPath2, cts.Token);

            var expecteXpub1 = NBitcoinHelpers.BetterParseExtPubKey("xpub6DHjDx4gzLV37gJWMxYJAqyKRGN46MT61RHVizdU62cbVUYu9L95cXKzX62yJ2hPbN11EeprS8sSn8kj47skQBrmycCMzFEYBQSntVKFQ5M");
            var expecteXpub2 = NBitcoinHelpers.BetterParseExtPubKey("xpub6FJS1ne3STcKdQ9JLXNzZXidmCNZ9dxLiy7WVvsRkcmxjJsrDKJKEAXq4MGyEBM3vHEw2buqXezfNK5SNBrkwK7Fxjz1TW6xzRr2pUyMWFu");

            Assert.Equal(expecteXpub1, xpub1);
            Assert.Equal(expecteXpub2, xpub2);

            BitcoinWitPubKeyAddress address1 = await client.DisplayAddressAsync(deviceType, devicePath, keyPath1, cts.Token);

            BitcoinWitPubKeyAddress address2 = await client.DisplayAddressAsync(deviceType, devicePath, keyPath2, cts.Token);

            BitcoinAddress expectedAddress1;
            BitcoinAddress expectedAddress2;

            if (network == Network.Main)
            {
                expectedAddress1 = BitcoinAddress.Create("bc1q7zqqsmqx5ymhd7qn73lm96w5yqdkrmx7fdevah", Network.Main);
                expectedAddress2 = BitcoinAddress.Create("bc1qmaveee425a5xjkjcv7m6d4gth45jvtnj23fzyf", Network.Main);
            }
            else if (network == Network.TestNet)
            {
                expectedAddress1 = BitcoinAddress.Create("tb1q7zqqsmqx5ymhd7qn73lm96w5yqdkrmx7rtzlxy", Network.TestNet);
                expectedAddress2 = BitcoinAddress.Create("tb1qmaveee425a5xjkjcv7m6d4gth45jvtnjqhj3l6", Network.TestNet);
            }
            else if (network == Network.RegTest)
            {
                expectedAddress1 = BitcoinAddress.Create("bcrt1q7zqqsmqx5ymhd7qn73lm96w5yqdkrmx7pzmj3d", Network.RegTest);
                expectedAddress2 = BitcoinAddress.Create("bcrt1qmaveee425a5xjkjcv7m6d4gth45jvtnjz7tugn", Network.RegTest);
            }
            else
            {
                throw new NotSupportedNetworkException(network);
            }

            Assert.Equal(expectedAddress1, address1);
            Assert.Equal(expectedAddress2, address2);
        }
Beispiel #17
0
        private TransactionBuildContext GetSetupTransactionBuildContext(IWalletTransactionHandler walletTransactionHandler,
                                                                        string coldWalletAddress, string hotWalletAddress, string walletName, string walletAccount,
                                                                        string walletPassword, Money amount, Money feeAmount, bool subtractFeeFromAmount, bool offline, bool useSegwitChangeAddress, int splitCount, ExtPubKey extPubKey = null)
        {
            Guard.NotNull(walletTransactionHandler, nameof(walletTransactionHandler));
            Guard.NotEmpty(coldWalletAddress, nameof(coldWalletAddress));
            Guard.NotEmpty(hotWalletAddress, nameof(hotWalletAddress));
            Guard.NotEmpty(walletName, nameof(walletName));
            Guard.NotEmpty(walletAccount, nameof(walletAccount));
            Guard.NotNull(amount, nameof(amount));

            Wallet.Wallet wallet = this.GetWallet(walletName);

            KeyId hotPubKeyHash  = null;
            KeyId coldPubKeyHash = null;

            if (!offline)
            {
                // Get/create the cold staking accounts.
                HdAccount coldAccount = this.GetOrCreateColdStakingAccount(walletName, true, walletPassword, extPubKey);
                HdAccount hotAccount  = this.GetOrCreateColdStakingAccount(walletName, false, walletPassword, extPubKey);

                HdAddress coldAddress = coldAccount?.ExternalAddresses.FirstOrDefault(s => s.Address == coldWalletAddress || s.Bech32Address == coldWalletAddress);
                HdAddress hotAddress  = hotAccount?.ExternalAddresses.FirstOrDefault(s => s.Address == hotWalletAddress || s.Bech32Address == hotWalletAddress);

                bool thisIsColdWallet = coldAddress != null;
                bool thisIsHotWallet  = hotAddress != null;

                this.logger.LogDebug("Local wallet '{0}' does{1} contain cold wallet address '{2}' and does{3} contain hot wallet address '{4}'.",
                                     walletName, thisIsColdWallet ? "" : " NOT", coldWalletAddress, thisIsHotWallet ? "" : " NOT", hotWalletAddress);

                if (thisIsColdWallet && thisIsHotWallet)
                {
                    this.logger.LogTrace("(-)[COLDSTAKE_BOTH_HOT_AND_COLD]");
                    throw new WalletException("You can't use this wallet as both the hot wallet and cold wallet.");
                }

                if (!thisIsColdWallet && !thisIsHotWallet)
                {
                    this.logger.LogTrace("(-)[COLDSTAKE_ADDRESSES_NOT_IN_ACCOUNTS]");
                    throw new WalletException("The hot and cold wallet addresses could not be found in the corresponding accounts.");
                }

                // Check if this is a segwit address.
                if (coldAddress?.Bech32Address == coldWalletAddress || hotAddress?.Bech32Address == hotWalletAddress)
                {
                    hotPubKeyHash  = new BitcoinWitPubKeyAddress(hotWalletAddress, wallet.Network).Hash.AsKeyId();
                    coldPubKeyHash = new BitcoinWitPubKeyAddress(coldWalletAddress, wallet.Network).Hash.AsKeyId();
                }
                else
                {
                    hotPubKeyHash  = new BitcoinPubKeyAddress(hotWalletAddress, wallet.Network).Hash;
                    coldPubKeyHash = new BitcoinPubKeyAddress(coldWalletAddress, wallet.Network).Hash;
                }
            }
            else
            {
                // In offline mode we relax all the restrictions to enable simpler setup. The user should ensure they are using separate wallets, or the cold private key could be inadvertently loaded on the online node.
                IDestination hot  = BitcoinAddress.Create(hotWalletAddress, this.network);
                IDestination cold = BitcoinAddress.Create(coldWalletAddress, this.network);

                if (hot is BitcoinPubKeyAddress && cold is BitcoinPubKeyAddress)
                {
                    hotPubKeyHash  = new BitcoinPubKeyAddress(hotWalletAddress, wallet.Network).Hash;
                    coldPubKeyHash = new BitcoinPubKeyAddress(coldWalletAddress, wallet.Network).Hash;
                }

                if (hot is BitcoinWitPubKeyAddress && cold is BitcoinWitPubKeyAddress)
                {
                    hotPubKeyHash  = new BitcoinWitPubKeyAddress(hotWalletAddress, wallet.Network).Hash.AsKeyId();
                    coldPubKeyHash = new BitcoinWitPubKeyAddress(coldWalletAddress, wallet.Network).Hash.AsKeyId();
                }
            }

            if (hotPubKeyHash == null || coldPubKeyHash == null)
            {
                this.logger.LogTrace("(-)[PUBKEYHASH_NOT_AVAILABLE]");
                throw new WalletException($"Unable to compute the needed hashes from the given addresses.");
            }

            Script destination = ColdStakingScriptTemplate.Instance.GenerateScriptPubKey(hotPubKeyHash, coldPubKeyHash);

            // Only normal accounts should be allowed.
            if (!this.GetAccounts(walletName).Any(a => a.Name == walletAccount))
            {
                this.logger.LogTrace("(-)[COLDSTAKE_ACCOUNT_NOT_FOUND]");
                throw new WalletException($"Can't find wallet account '{walletAccount}'.");
            }

            List <Recipient> recipients = GetRecipients(destination, amount, subtractFeeFromAmount, splitCount);

            var context = new TransactionBuildContext(wallet.Network)
            {
                AccountReference       = new WalletAccountReference(walletName, walletAccount),
                TransactionFee         = feeAmount,
                MinConfirmations       = 0,
                Shuffle                = false,
                UseSegwitChangeAddress = useSegwitChangeAddress,
                WalletPassword         = walletPassword,
                Recipients             = recipients
            };

            // Register the cold staking builder extension with the transaction builder.
            context.TransactionBuilder.Extensions.Add(new ColdStakingBuilderExtension(false));

            return(context);
        }
Beispiel #18
0
        public KeyManager(BitcoinEncryptedSecretNoEC encryptedSecret, byte[] chainCode, ExtPubKey extPubKey, string filePath = null)
        {
            HdPubKeys     = new List <HdPubKey>();
            HdPubKeysLock = new object();

            EncryptedSecret = Guard.NotNull(nameof(encryptedSecret), encryptedSecret);
            ChainCode       = Guard.NotNull(nameof(chainCode), chainCode);
            ExtPubKey       = Guard.NotNull(nameof(extPubKey), extPubKey);
            SetFilePath(filePath);
            ToFileLock = new object();
            ToFile();
        }
Beispiel #19
0
 public BitcoinExtPubKey CreateBitcoinExtPubKey(ExtPubKey pubkey)
 {
     return(new BitcoinExtPubKey(pubkey, this));
 }
Beispiel #20
0
        public HdPubKey GenerateNewKey(string label, KeyState keyState, bool isInternal, bool toFile = true)
        {
            // BIP44-ish derivation scheme
            // m / purpose' / coin_type' / account' / change / address_index
            var change = isInternal ? 1 : 0;

            lock (HdPubKeysLock)
            {
                IEnumerable <HdPubKey> relevantHdPubKeys;
                if (isInternal)
                {
                    relevantHdPubKeys = HdPubKeys.Where(x => x.IsInternal);
                }
                else
                {
                    relevantHdPubKeys = HdPubKeys.Where(x => !x.IsInternal);
                }

                KeyPath path;
                if (!relevantHdPubKeys.Any())
                {
                    path = new KeyPath($"{change}/0");
                }
                else
                {
                    int        largestIndex   = relevantHdPubKeys.Max(x => x.Index);
                    List <int> missingIndexes = Enumerable.Range(0, largestIndex).Except(relevantHdPubKeys.Select(x => x.Index)).ToList();
                    if (missingIndexes.Any())
                    {
                        int smallestMissingIndex = missingIndexes.Min();
                        path = relevantHdPubKeys.First(x => x.Index == (smallestMissingIndex - 1)).NonHardenedKeyPath.Increment();
                    }
                    else
                    {
                        path = relevantHdPubKeys.First(x => x.Index == largestIndex).NonHardenedKeyPath.Increment();
                    }
                }

                var fullPath = AccountKeyPath.Derive(path);
                var pubKey   = ExtPubKey.Derive(path).PubKey;

                var hdPubKey = new HdPubKey(pubKey, fullPath, label, keyState);
                HdPubKeys.Add(hdPubKey);
                lock (HdPubKeyScriptBytesLock)
                {
                    HdPubKeyScriptBytes.Add(hdPubKey.P2wpkhScript.ToCompressedBytes());
                }

                lock (ScriptHdPubkeyMapLock)
                {
                    ScriptHdPubkeyMap.Add(hdPubKey.P2wpkhScript, hdPubKey);
                }

                if (toFile)
                {
                    ToFile();
                }

                return(hdPubKey);
            }
        }
 public DirectDerivationStrategy CreateDerivationStrategy(ExtPubKey pubKey = null)
 {
     return((DirectDerivationStrategy)CreateDerivationStrategy(pubKey, false));
 }
Beispiel #22
0
        private IEnumerable <byte> DerivateScript(bool isInternal, int index)
        {
            var change = isInternal ? 1 : 0;

            return(ExtPubKey.Derive(change, false).Derive(index, false).PubKey.WitHash.ScriptPubKey.ToCompressedBytes());
        }
Beispiel #23
0
        /// <summary>
        /// Creates a cold staking account and ensures that it has at least one address.
        /// If the account already exists then the existing account is returned.
        /// </summary>
        /// <remarks>
        /// <para>In order to keep track of cold staking addresses and balances we are using <see cref="HdAccount"/>'s
        /// with indexes starting from the value defined in <see cref="Wallet.SpecialPurposeAccountIndexesStart"/>.
        /// </para><para>
        /// We are using two such accounts, one when the wallet is in the role of cold wallet, and another one when
        /// the wallet is in the role of hot wallet. For this reason we specify the required account when calling this
        /// method.
        /// </para></remarks>
        /// <param name="walletName">The name of the wallet where we wish to create the account.</param>
        /// <param name="isColdWalletAccount">Indicates whether we need the cold wallet account (versus the hot wallet account).</param>
        /// <param name="walletPassword">The wallet password which will be used to create the account.</param>
        /// <returns>The new or existing cold staking account.</returns>
        internal HdAccount GetOrCreateColdStakingAccount(string walletName, bool isColdWalletAccount, string walletPassword, ExtPubKey extPubKey)
        {
            Wallet.Wallet wallet = this.GetWallet(walletName);

            HdAccount account = this.GetColdStakingAccount(wallet, isColdWalletAccount);

            if (account != null)
            {
                this.logger.LogTrace("(-)[ACCOUNT_ALREADY_EXIST]:'{0}'", account.Name);
                return(account);
            }

            this.logger.LogDebug("The {0} wallet account for '{1}' does not exist and will now be created.", isColdWalletAccount ? "cold" : "hot", wallet.Name);

            int    accountIndex;
            string accountName;

            if (isColdWalletAccount)
            {
                accountIndex = ColdWalletAccountIndex;
                accountName  = ColdWalletAccountName;
            }
            else
            {
                accountIndex = HotWalletAccountIndex;
                accountName  = HotWalletAccountName;
            }

            if (extPubKey == null)
            {
                account = wallet.AddNewAccount(walletPassword, accountIndex, accountName, this.dateTimeProvider.GetTimeOffset());
            }
            else
            {
                account = wallet.AddNewAccount(extPubKey, accountIndex, accountName, this.dateTimeProvider.GetTimeOffset());
            }

            this.logger.LogTrace("(-):'{0}'", account.Name);
            return(account);
        }
Beispiel #24
0
        public static void Execute()
        {
            // HD Wallet (BIP 32)
            // from the master key, I can generate new keys:
            ExtKey masterKey = new ExtKey();

            Console.WriteLine("---------------------HD Wallet (BIP 32)---------------------");
            Console.WriteLine("Master key : " + masterKey.ToString(Network.Main));
            for (int i = 0; i < 5; i++)
            {
                ExtKey childKey = masterKey.Derive((uint)i);
                Console.WriteLine("Key " + i + " : " + childKey.ToString(Network.Main));
            }

            // go back from a Key to an ExtKey by supplying the Key and the ChainCode
            ExtKey extKey = new ExtKey();
            Key    key    = extKey.PrivateKey;

            byte[] chainCode = extKey.ChainCode;

            ExtKey newExtKey = new ExtKey(key, chainCode);

            Console.WriteLine("extKey==newExtKey: " +
                              (extKey.ToString(Network.Main) == newExtKey.ToString(Network.Main)));

            // delegating address creation to a peer
            // third party can generate public keys without knowing the private key
            ExtPubKey masterPubKey = masterKey.Neuter();

            Console.WriteLine("Master Pubkey : " + masterPubKey.ToString(Network.Main));
            for (int i = 0; i < 5; i++)
            {
                ExtPubKey pubkey = masterPubKey.Derive((uint)i);
                Console.WriteLine("PubKey " + i + " : " + pubkey.ToString(Network.Main));
            }

            // payment server generates pubkey1
            // we can get the corresponding private key with our private master key
            masterKey    = new ExtKey();
            masterPubKey = masterKey.Neuter();

            //The payment server generate pubkey1
            ExtPubKey pubkey1 = masterPubKey.Derive((uint)1);

            //You get the private key of pubkey1
            ExtKey key1 = masterKey.Derive((uint)1);

            //Check it is legit
            Console.WriteLine("Generated address : " + pubkey1.PubKey.GetAddress(Network.Main));
            Console.WriteLine("Expected address : " + key1.PrivateKey.PubKey.GetAddress(Network.Main));
            // Generated address : 1Jy8nALZNqpf4rFN9TWG2qXapZUBvquFfX
            // Expected address: 1Jy8nALZNqpf4rFN9TWG2qXapZUBvquFfX

            // “hierarchical”:  Parent Key + KeyPath => Child Key (and so on..)
            // derivate Child(1,1) from parent in two different way
            ExtKey parent = new ExtKey();
            ExtKey child1 = parent.Derive(1);
            ExtKey child11;

            child11 = child1.Derive(1);           //Or
            child11 = parent.Derive(1).Derive(1); //Or
            child11 = parent.Derive(new KeyPath("1/1"));

            // generate one hierarchy for each department.
            // non-hardened key, accounting department can “climb” the hierarchy
            // hardened key, so the marketing department will not be able to climb the hierarchy.
            ExtKey    ceoKey        = new ExtKey();
            ExtKey    accountingKey = ceoKey.Derive(0, hardened: false);
            ExtKey    marketingKey  = ceoKey.Derive(0, hardened: true);
            ExtPubKey ceoPubkey     = ceoKey.Neuter();

            //Recover ceo key with accounting private key and ceo public key
            ExtKey ceoKeyRecovered    = accountingKey.GetParentExtKey(ceoPubkey);
            ExtKey ceoKeyNotRecovered = marketingKey.GetParentExtKey(ceoPubkey); //Crash

            Console.WriteLine();
            Console.WriteLine("CEO Key: " + ceoKey.ToString(Network.Main));
            Console.WriteLine("CEO recovered: " + ceoKeyRecovered.ToString(Network.Main));
            Console.WriteLine("CEO Not recovered: " + ceoKeyNotRecovered.ToString(Network.Main));

            //Or
            KeyPath nonHardened = new KeyPath("1/2/3");
            KeyPath hardened    = new KeyPath("1/2/3'");

            ceoKey = new ExtKey();
            string  accounting = "1'";
            int     customerId = 5;
            int     paymentId  = 50;
            KeyPath path       = new KeyPath(accounting + "/" + customerId + "/" + paymentId);
            ExtKey  paymentKey = ceoKey.Derive(path); //Path : "1'/5/50"
        }
Beispiel #25
0
        private static void Main(string[] args)
        {
            // add entropy before creating key
            RandomUtils.AddEntropy("hello");
            RandomUtils.AddEntropy(new byte[] { 1, 2, 3 });

            // key created with added entropy
            var nsaProofKey = new Key();

            // What NBitcoin does when you call AddEntropy(data) is:
            // additionalEntropy = SHA(SHA(data) ^ additionalEntropy)

            // Then when you generate a new number:
            // result = SHA(PRNG() ^ additionalEntropy)

            // Key Derivation Function is a way to have a stronger key, even if your entropy is low
            // KDF is a hash function that wastes computing resources on purpose.

            var derived = SCrypt.BitcoinComputeDerivedKey("hello", new byte[] { 1, 2, 3 });

            RandomUtils.AddEntropy(derived);

            // even if attacker knows that your source of entropy contains 5 letters,
            // they will need to run Scrypt to check each possibility

            // standard for encrypting private key with a password using kdf is BIP38

            var privateKey        = new Key();
            var bitcoinPrivateKey = privateKey.GetWif(Network.Main);

            Console.WriteLine(bitcoinPrivateKey);

            BitcoinEncryptedSecret encryptedBitcoinPrivateKey = bitcoinPrivateKey.Encrypt("password");

            Console.WriteLine(encryptedBitcoinPrivateKey);

            var decryptedBitcoinPrivateKey = encryptedBitcoinPrivateKey.GetKey("password");

            Console.WriteLine(decryptedBitcoinPrivateKey);

            Key keyFromIncorrectPassword = null;

            Exception error = null;

            try
            {
                keyFromIncorrectPassword = encryptedBitcoinPrivateKey.GetKey("lahsdlahsdlakhslkdash");
            }
            catch (Exception e)
            {
                error = e;
            }

            var result = keyFromIncorrectPassword != null
                ? keyFromIncorrectPassword.ToString()
                : $"{error?.GetType().Name ?? "Error"}: icorrect password";

            Console.WriteLine(result);


            // BIP 38
            // how to delegate Key and Address creation to an untrusted peer

            // create pass phrase code
            BitcoinPassphraseCode passphraseCode = new BitcoinPassphraseCode("my secret", Network.Main, null);

            Console.WriteLine(passphraseCode);

            // then give passPhraseCode to 3rd party key generator
            // third party can generate encrypted keys on your behalf
            // without knowing your password and private key.
            EncryptedKeyResult encryptedKeyResult = passphraseCode.GenerateEncryptedSecret();
            var generatedAddress = encryptedKeyResult.GeneratedAddress;
            var encryptedKey     = encryptedKeyResult.EncryptedKey;

            // used by 3rd party to confirm generated key and address correspond to password
            var confirmationCode = encryptedKeyResult.ConfirmationCode;

            // check
            var isValid = confirmationCode.Check("my secret", generatedAddress);

            Console.WriteLine(isValid);

            var bitcoinPrivateKeyFromPassphraseCode = encryptedKey.GetSecret("my secret");

            Console.WriteLine(bitcoinPrivateKeyFromPassphraseCode.GetAddress() == generatedAddress);

            Console.WriteLine(bitcoinPrivateKey);

            // BIP 32
            // hierarchical deterministic wallets
            // prevent outdated backups

            var masterKey = new ExtKey();


            Console.WriteLine($"Master Key: {masterKey.ToString(Network.Main)}");

            for (uint i = 0; i < 5; i++)
            {
                ExtKey nextKey = masterKey.Derive(i);
                Console.WriteLine($"Key {i} : {nextKey.ToString(Network.Main)}");
            }

            // go back from a Key to ExtKey by supplying the Key and the ChainCode to the ExtKey constructor.

            var extKey = new ExtKey();

            byte[] chainCode = extKey.ChainCode;
            Key    key       = extKey.PrivateKey;

            var newExtKey = new ExtKey(key, chainCode);

            // the base58 type equivalent of ExtKey is BitcoinExtKey


            // "neuter" master key so 3rd party can generate public keys without knowing private key
            ExtPubKey masterPubKey = masterKey.Neuter();

            for (uint i = 0; i < 5; i++)
            {
                ExtPubKey pubKey = masterPubKey.Derive(i);
                Console.WriteLine($"PubKey {i} : {pubKey.ToString(Network.Main)}");
            }

            // get corresponding private key with master key
            masterKey    = new ExtKey();
            masterPubKey = masterKey.Neuter();

            // 3rd party generates pubkey1
            ExtPubKey pubKey1 = masterPubKey.Derive(1);

            // get privatekey of pubKey1
            ExtKey key1 = masterKey.Derive(1);

            Console.WriteLine($"Generated address: {pubKey1.PubKey.GetAddress(Network.Main)}");
            Console.WriteLine($"Expected address: {key1.PrivateKey.PubKey.GetAddress(Network.Main)}");

            // deterministic keys

            // derive the 1st child of the 1st child

            ExtKey parent = new ExtKey();

            // method 1:
            ExtKey child11 = parent.Derive(1).Derive(1);

            // method 2:
            child11 = parent.Derive(new KeyPath("1/1"));

            // why use HD wallets ?
            // easier control, easier to classify keys for multiple accounts

            // but child keys can recover parent key (non-hardened)

            ExtKey ceoExtKey = new ExtKey();

            Console.WriteLine($"CEO: {ceoExtKey.ToString(Network.Main)}");
            ExtKey accountingKey = ceoExtKey.Derive(0, hardened: false);

            ExtPubKey ceoPubKey = ceoExtKey.Neuter();

            // recover ceo key with accounting private key and ceo public key
            ExtKey ceoKeyRecovered = accountingKey.GetParentExtKey(ceoPubKey);

            Console.WriteLine($"CEO recovered: {ceoKeyRecovered.ToString(Network.Main)}");

            // create a hardened key
            var privateCeoExtKey = new ExtKey();

            Console.WriteLine($"Private CEO: {privateCeoExtKey.ToString(Network.Main)}");
            var assitantExtKey = privateCeoExtKey.Derive(1, hardened: true);

            ExtPubKey privateCeoPubKey = privateCeoExtKey.Neuter();

            ExtKey privateCeoKeyRecovered = null;

            try
            {
                privateCeoKeyRecovered = assitantExtKey.GetParentExtKey(privateCeoPubKey);
            }
            catch (Exception e)
            {
                Console.WriteLine($"{e.Message}");
            }

            // creating hardened keys via keypath
            var isNonHardened = new KeyPath("1/2/3").IsHardened;

            Console.WriteLine(isNonHardened);

            var isHardened = new KeyPath("1/2/3'").IsHardened;

            Console.WriteLine(isHardened);

            // imagine that the Accounting Department generates 1 parent key for each customer, and a child for each of the customer’s payments.
            // As the CEO, you want to spend the money on one of these addresses.

            var     accountingCeoKey = new ExtKey();
            string  accounting       = "1'"; // hardened with apostrophe
            int     customerId       = 5;
            int     paymentId        = 50;
            KeyPath path             = new KeyPath($"{accounting}/{customerId}/{paymentId}");

            // path: 1/5/50
            ExtKey paymentKey = accountingCeoKey.Derive(path);

            Console.WriteLine(paymentKey);


            // mnemonic code for HD keys BIP 39
            // used for easy to write keys
            Mnemonic mnemo  = new Mnemonic(Wordlist.English, WordCount.Twelve);
            ExtKey   hdRoot = mnemo.DeriveExtKey("my password");

            Console.WriteLine(mnemo);

            // recover hdRoot with mnemonic and password
            mnemo = new Mnemonic(mnemo.ToString(), Wordlist.English);
            ExtKey recoverdHdRoot = mnemo.DeriveExtKey("my password");

            Console.WriteLine(hdRoot.PrivateKey == recoverdHdRoot.PrivateKey);


            // dark wallet
            // Prevent outdated backups
            // Delegate key / address generation to an untrusted peer

            // bonus feature: only share one address (StealthAddress)

            var scanKey        = new Key();
            var spendKey       = new Key();
            var stealthAddress = new BitcoinStealthAddress(
                scanKey: scanKey.PubKey,
                pubKeys: new[] { spendKey.PubKey },
                signatureCount: 1,
                bitfield: null,
                network: Network.Main
                );

            // payer will take StealthAddress and generate temp key called Ephem Key, and generate a Stealth Pub Key
            // then they package the Ephem PubKey in Stealth Metadata obj embedded in OP_RETURN
            // they will also add the output to the generated bitcoin address (Stealth pub key)

            //The creation of the EphemKey is an implementation detail
            // it can be omitted as NBitcoin will generate one automatically:
            var ephemKey    = new Key();
            var transaction = new Transaction();

            stealthAddress.SendTo(transaction, Money.Coins(1.0m), ephemKey);
            Console.WriteLine(transaction);

            // the Scanner knows the StealthAddress
            // and recovers the Stealth PubKey and Bitcoin Address with the Scan Key

            // scanner then checks if if one of the tx corresponds to the address
            // if true, Scanner notifies the Receiver about tx

            // the receiver can get the private key of the address with their spend key

            // note: a StealthAddress can have mulitple spend pubkeys 9multi sig)

            // limit: use of OP_RETURN makes embedding data in tx difficult
            // OP_RETURN limit is 40 bytes

            Console.ReadLine();
        }
Beispiel #26
0
 public static KeyManager CreateNewHardwareWalletWatchOnly(HDFingerprint masterFingerprint, ExtPubKey extPubKey, string filePath = null)
 {
     return(new KeyManager(null, null, masterFingerprint, extPubKey, null, AbsoluteMinGapLimit, new BlockchainState(), filePath));
 }
Beispiel #27
0
		public void CanCheckChildKey()
		{
			var parent = new ExtKey();
			var child = parent.Derive(1);
			var notchild = new ExtKey();

			Assert.True(child.IsChildOf(parent));
			Assert.True(parent.IsParentOf(child));
			Assert.False(notchild.IsChildOf(parent));
			Assert.False(parent.IsParentOf(notchild));

			Assert.True(child.Neuter().IsChildOf(parent.Neuter()));
			Assert.True(parent.Neuter().IsParentOf(child.Neuter()));
			Assert.False(notchild.Neuter().IsChildOf(parent.Neuter()));
			Assert.False(parent.Neuter().IsParentOf(notchild.Neuter()));

			var keyA = parent.Neuter();
			var keyB = new ExtPubKey(keyA.ToBytes());
			AssertEx.CollectionEquals(keyA.ToBytes(), keyB.ToBytes());
		}
Beispiel #28
0
 private BitcoinAddress AddressOf(ExtPubKey pubkey, KeyPath path)
 {
     return(pubkey.Derive(path).PubKey.Hash.GetAddress(GetNetwork()));
 }
Beispiel #29
0
        public void When_BuildTransactionIsCalledWithoutTransactionFee_Then_MultipleSubtractFeeRecipients_ThrowsException()
        {
            DataFolder dataFolder = CreateDataFolder(this);

            IWalletRepository walletRepository = new SQLiteWalletRepository(this.LoggerFactory.Object, dataFolder, this.Network, DateTimeProvider.Default, new ScriptAddressReader())
            {
                TestMode = true
            };

            var walletFeePolicy = new Mock <IWalletFeePolicy>();

            walletFeePolicy.Setup(w => w.GetFeeRate(FeeType.Low.ToConfirmations())).Returns(new FeeRate(20000));

            var walletManager = new WalletManager(this.LoggerFactory.Object, this.Network, new ChainIndexer(this.Network), new WalletSettings(NodeSettings.Default(this.Network)),
                                                  dataFolder, walletFeePolicy.Object, new Mock <IAsyncProvider>().Object, new NodeLifetime(), DateTimeProvider.Default, this.scriptAddressReader, walletRepository);

            walletManager.Start();

            var reserveUtxoService = new ReserveUtxoService(this.loggerFactory, new Mock <ISignals>().Object);

            var walletTransactionHandler = new WalletTransactionHandler(this.LoggerFactory.Object, walletManager, walletFeePolicy.Object, this.Network, this.standardTransactionPolicy, reserveUtxoService);

            (Wallet wallet, ExtKey extKey) = WalletTestsHelpers.GenerateBlankWalletWithExtKey("myWallet1", "password", walletRepository);

            walletManager.Wallets.Add(wallet);

            int       accountIndex  = 0;
            ExtKey    addressExtKey = extKey.Derive(new KeyPath($"m/44'/{this.Network.Consensus.CoinType}'/{accountIndex}'"));
            ExtPubKey extPubKey     = addressExtKey.Neuter();

            HdAccount account = wallet.AddNewAccount(extPubKey, accountName: "account1");

            var address      = account.ExternalAddresses.First();
            var destination  = account.InternalAddresses.First();
            var destination2 = account.InternalAddresses.Skip(1).First();
            var destination3 = account.InternalAddresses.Skip(2).First();

            // Wallet with 4 coinbase outputs of 50 = 200.
            var chain = new ChainIndexer(wallet.Network);

            WalletTestsHelpers.AddBlocksWithCoinbaseToChain(wallet.Network, chain, address, 4);

            var walletReference = new WalletAccountReference
            {
                AccountName = "account1",
                WalletName  = "myWallet1"
            };

            // Create a transaction with 3 outputs 50 + 50 + 50 = 150 but with fees charged to recipients.
            var context = new TransactionBuildContext(this.Network)
            {
                AccountReference = walletReference,
                MinConfirmations = 0,
                FeeType          = FeeType.Low,
                WalletPassword   = "******",
                Recipients       = new[]
                {
                    new Recipient {
                        Amount = new Money(50, MoneyUnit.BTC), ScriptPubKey = destination.ScriptPubKey, SubtractFeeFromAmount = true
                    },
                    new Recipient {
                        Amount = new Money(50, MoneyUnit.BTC), ScriptPubKey = destination2.ScriptPubKey, SubtractFeeFromAmount = true
                    },
                    new Recipient {
                        Amount = new Money(50, MoneyUnit.BTC), ScriptPubKey = destination3.ScriptPubKey, SubtractFeeFromAmount = false
                    }
                }.ToList()
            };

            Assert.Throws <WalletException>(() => walletTransactionHandler.BuildTransaction(context));
        }
Beispiel #30
0
        private TransactionBuildContext GetSetupTransactionBuildContext(IWalletTransactionHandler walletTransactionHandler,
                                                                        string coldWalletAddress, string hotWalletAddress, string walletName, string walletAccount,
                                                                        string walletPassword, Money amount, Money feeAmount, bool subtractFeeFromAmount, bool offline, bool useSegwitChangeAddress, ExtPubKey extPubKey = null)
        {
            Guard.NotNull(walletTransactionHandler, nameof(walletTransactionHandler));
            Guard.NotEmpty(coldWalletAddress, nameof(coldWalletAddress));
            Guard.NotEmpty(hotWalletAddress, nameof(hotWalletAddress));
            Guard.NotEmpty(walletName, nameof(walletName));
            Guard.NotEmpty(walletAccount, nameof(walletAccount));
            Guard.NotNull(amount, nameof(amount));

            Wallet.Wallet wallet = this.GetWallet(walletName);

            // Get/create the cold staking accounts.
            HdAccount coldAccount;
            HdAccount hotAccount;

            if (offline)
            {
                coldAccount = this.GetColdStakingAccount(wallet, true);
                hotAccount  = this.GetColdStakingAccount(wallet, false);
            }
            else
            {
                coldAccount = this.GetOrCreateColdStakingAccount(walletName, true, walletPassword, extPubKey);
                hotAccount  = this.GetOrCreateColdStakingAccount(walletName, false, walletPassword, extPubKey);
            }

            HdAddress coldAddress = coldAccount?.ExternalAddresses.FirstOrDefault(s => s.Address == coldWalletAddress || s.Bech32Address == coldWalletAddress);
            HdAddress hotAddress  = hotAccount?.ExternalAddresses.FirstOrDefault(s => s.Address == hotWalletAddress || s.Bech32Address == hotWalletAddress);

            bool thisIsColdWallet = coldAddress != null;
            bool thisIsHotWallet  = hotAddress != null;

            this.logger.LogDebug("Local wallet '{0}' does{1} contain cold wallet address '{2}' and does{3} contain hot wallet address '{4}'.",
                                 walletName, thisIsColdWallet ? "" : " NOT", coldWalletAddress, thisIsHotWallet ? "" : " NOT", hotWalletAddress);

            // TODO: Relax the constraint that both cannot be from the same wallet
            if (thisIsColdWallet && thisIsHotWallet)
            {
                this.logger.LogTrace("(-)[COLDSTAKE_BOTH_HOT_AND_COLD]");
                throw new WalletException("You can't use this wallet as both the hot wallet and cold wallet.");
            }

            if (!thisIsColdWallet && !thisIsHotWallet)
            {
                this.logger.LogTrace("(-)[COLDSTAKE_ADDRESSES_NOT_IN_ACCOUNTS]");
                throw new WalletException("The hot and cold wallet addresses could not be found in the corresponding accounts.");
            }

            KeyId hotPubKeyHash;
            KeyId coldPubKeyHash;

            // Check if this is a segwit address.
            if (coldAddress?.Bech32Address == coldWalletAddress || hotAddress?.Bech32Address == hotWalletAddress)
            {
                hotPubKeyHash  = new BitcoinWitPubKeyAddress(hotWalletAddress, wallet.Network).Hash.AsKeyId();
                coldPubKeyHash = new BitcoinWitPubKeyAddress(coldWalletAddress, wallet.Network).Hash.AsKeyId();
            }
            else
            {
                hotPubKeyHash  = new BitcoinPubKeyAddress(hotWalletAddress, wallet.Network).Hash;
                coldPubKeyHash = new BitcoinPubKeyAddress(coldWalletAddress, wallet.Network).Hash;
            }

            Script destination = ColdStakingScriptTemplate.Instance.GenerateScriptPubKey(hotPubKeyHash, coldPubKeyHash);

            // Only normal accounts should be allowed.
            if (!this.GetAccounts(walletName).Any(a => a.Name == walletAccount))
            {
                this.logger.LogTrace("(-)[COLDSTAKE_ACCOUNT_NOT_FOUND]");
                throw new WalletException($"Can't find wallet account '{walletAccount}'.");
            }

            var context = new TransactionBuildContext(wallet.Network)
            {
                AccountReference       = new WalletAccountReference(walletName, walletAccount),
                TransactionFee         = feeAmount,
                MinConfirmations       = 0,
                Shuffle                = false,
                UseSegwitChangeAddress = useSegwitChangeAddress,
                WalletPassword         = walletPassword,
                Recipients             = new List <Recipient>()
                {
                    new Recipient {
                        Amount = amount, ScriptPubKey = destination, SubtractFeeFromAmount = subtractFeeFromAmount
                    }
                }
            };

            // Register the cold staking builder extension with the transaction builder.
            context.TransactionBuilder.Extensions.Add(new ColdStakingBuilderExtension(false));

            return(context);
        }
 /// <summary>
 /// Constructor. Creates a representation of an extended public key, within the specified network.
 /// </summary>
 public BitcoinExtPubKey(ExtPubKey key, Network network)
     : base(key, network)
 {
 }
        private static void Main()
        {
            ExtKey masterKey = new ExtKey();

            Console.WriteLine("Master key : " + masterKey.ToString(Network.Main));
            for (int i = 0; i < 5; i++)
            {
                ExtKey key = masterKey.Derive((uint)i);
                Console.WriteLine("Key " + i + " : " + key.ToString(Network.Main));
            }

            ExtPubKey masterPubKey = masterKey.Neuter();

            for (int i = 0; i < 5; i++)
            {
                ExtPubKey pubkey = masterPubKey.Derive((uint)i);
                Console.WriteLine("PubKey " + i + " : " + pubkey.ToString(Network.Main));
            }

            masterKey    = new ExtKey();
            masterPubKey = masterKey.Neuter();

            //The payment server generate pubkey1
            ExtPubKey pubkey1 = masterPubKey.Derive((uint)1);

            //You get the private key of pubkey1
            ExtKey key1 = masterKey.Derive((uint)1);

            //Check it is legit
            Console.WriteLine("Generated address : " + pubkey1.PubKey.GetAddress(Network.Main));
            Console.WriteLine("Expected address : " + key1.PrivateKey.PubKey.GetAddress(Network.Main));

            ExtKey parent  = new ExtKey();
            ExtKey child11 = parent.Derive(1).Derive(1);

            // OR
            parent  = new ExtKey();
            child11 = parent.Derive(new KeyPath("1/1"));

            ExtKey ceoKey = new ExtKey();

            Console.WriteLine("CEO: " + ceoKey.ToString(Network.Main));
            ExtKey accountingKey = ceoKey.Derive(0, hardened: true);

            ExtPubKey ceoPubkey = ceoKey.Neuter();

            //ExtKey ceoKeyRecovered = accountingKey.GetParentExtKey(ceoPubkey); //Crash

            var nonHardened = new KeyPath("1/2/3");
            var hardened    = new KeyPath("1/2/3'");

            ceoKey = new ExtKey();
            string  accounting = "1'";
            int     customerId = 5;
            int     paymentId  = 50;
            KeyPath path       = new KeyPath(accounting + "/" + customerId + "/" + paymentId);
            //Path : "1'/5/50"
            ExtKey paymentKey = ceoKey.Derive(path);

            Mnemonic mnemo  = new Mnemonic(Wordlist.English, WordCount.Twelve);
            ExtKey   hdRoot = mnemo.DeriveExtKey("my password");

            Console.WriteLine(mnemo);

            mnemo = new Mnemonic("minute put grant neglect anxiety case globe win famous correct turn link",
                                 Wordlist.English);
            hdRoot = mnemo.DeriveExtKey("my password");

            Console.ReadLine();
        }
 public LineStrategy(DirectDerivationStrategy up, ExtPubKey root, bool change)
 {
     this.up        = up;
     Path           = new KeyPath(change ? "1" : "0");
     rootDerivation = root.Derive(Path);
 }
Beispiel #34
0
		public BitcoinExtPubKey(ExtPubKey key, Network network)
			: base(key, network)
		{

		}
Beispiel #35
0
        public void Add(HdAccount account)
        {
            account.WalletAccounts = this;

            if (this.walletRepository == null)
            {
                this.accounts.Add(account);
                return;
            }

            this.walletRepository.CreateAccount(this.wallet.Name, account.Index, account.Name,
                                                (account.ExtendedPubKey == null) ? null : ExtPubKey.Parse(account.ExtendedPubKey), account.CreationTime);
        }