/// <summary>
        /// Create new non-root address
        /// </summary>
        public void CreateCompanyAddress(long addressCategory, string name, string account)
        {
            long addressType  = (long)CustomAddressType.Company;
            var  rootXPrivKey = ExtKey.Parse(CurrentWallet.RootXPrivKey);

            var  parentKeyPath = new KeyPath($"/{addressType}'/{addressCategory}'");
            long maxIndex      = AddressDao.GetMaxPathIndex(CurrentWallet.Id, parentKeyPath.ToString());
            long currentIndex  = maxIndex + 1;

            var keyPath = parentKeyPath.Derive((uint)currentIndex);
            var address = KeyOperator.Instance.DeriveNewAddress(rootXPrivKey, keyPath);

            var addressInfo = new AddressInfo
            {
                Id              = Guid.NewGuid().ToString("N"),
                Address         = address,
                ExtPubKeyWif    = null,
                WalletId        = CurrentWallet.Id,
                Network         = (NetworkOperator.Instance.Network == Network.Main) ? (int)NetworkType.Mainnet : (int)NetworkType.Testnet,
                KeyPath         = keyPath.ToString(),
                ParentKeyPath   = parentKeyPath.ToString(),
                PathIndex       = currentIndex,
                AddressType     = addressType,
                AddressCategory = addressCategory,
                Name            = (addressCategory == (long)AddressCategory.Receiver ? "收款" : "付款") + " " + currentIndex,
                Account         = account
            };

            AddressDao.Create(addressInfo);
        }
Exemple #2
0
        public void CanUseKeyPath()
        {
            var keyPath = KeyPath.Parse("0/1/2/3");

            Assert.Equal(keyPath.ToString(), "0/1/2/3");
            var key = new ExtKey();

            Assert.Equal(key
                         .Derive(0)
                         .Derive(1)
                         .Derive(2)
                         .Derive(3)
                         .ToString(Network.Main), key.Derive(keyPath).ToString(Network.Main));

            var neuter = key.Neuter();

            Assert.Equal(neuter
                         .Derive(0)
                         .Derive(1)
                         .Derive(2)
                         .Derive(3)
                         .ToString(Network.Main), neuter.Derive(keyPath).ToString(Network.Main));

            Assert.Equal(neuter.Derive(keyPath).ToString(Network.Main),
                         key.Derive(keyPath).Neuter().ToString(Network.Main));

            keyPath = new KeyPath(0x8000002Cu, 1u);
            Assert.Equal(keyPath.ToString(), "44'/1");

            keyPath = KeyPath.Parse("44'/1");
            Assert.False(keyPath.IsHardened);
            Assert.True(KeyPath.Parse("44'/1'").IsHardened);
            Assert.Equal(keyPath[0], 0x8000002Cu);
            Assert.Equal(keyPath[1], 1u);

            key = new ExtKey();
            Assert.Equal(key.Derive(keyPath).ToString(Network.Main),
                         key.Derive(44, true).Derive(1, false).ToString(Network.Main));

            keyPath = KeyPath.Parse("");
            keyPath = keyPath.Derive(44, true).Derive(1, false);
            Assert.Equal(keyPath.ToString(), "44'/1");
            Assert.Equal(keyPath.Increment().ToString(), "44'/2");
            Assert.Equal(keyPath.Derive(1, true).Increment().ToString(), "44'/1/2'");
            Assert.Equal(keyPath.Parent.ToString(), "44'");
            Assert.Equal(keyPath.Parent.Parent.ToString(), "");
            Assert.Equal(keyPath.Parent.Parent.Parent, null);
            Assert.Equal(keyPath.Parent.Parent.Increment(), null);
            Assert.Equal(key.Derive(keyPath).ToString(Network.Main),
                         key.Derive(44, true).Derive(1, false).ToString(Network.Main));

            Assert.True(key.Derive(44, true).IsHardened);
            Assert.False(key.Derive(44, false).IsHardened);

            neuter = key.Derive(44, true).Neuter();
            Assert.True(neuter.IsHardened);
            neuter = key.Derive(44, false).Neuter();
            Assert.False(neuter.IsHardened);
        }
Exemple #3
0
        public void CanUseKeyPath()
        {
            var keyPath = KeyPath.Parse("0/1/2/3");

            Assert.Equal("0/1/2/3", keyPath.ToString());
            var key = new ExtKey();

            Assert.Equal(key
                         .Derive(0)
                         .Derive(1)
                         .Derive(2)
                         .Derive(3)
                         .ToString(Network.PurpleMain), key.Derive(keyPath).ToString(Network.PurpleMain));

            var neuter = key.Neuter();

            Assert.Equal(neuter
                         .Derive(0)
                         .Derive(1)
                         .Derive(2)
                         .Derive(3)
                         .ToString(Network.PurpleMain), neuter.Derive(keyPath).ToString(Network.PurpleMain));

            Assert.Equal(neuter.Derive(keyPath).ToString(Network.PurpleMain), key.Derive(keyPath).Neuter().ToString(Network.PurpleMain));

            keyPath = new KeyPath(new uint[] { 0x8000002Cu, 1u });
            Assert.Equal("44'/1", keyPath.ToString());

            keyPath = KeyPath.Parse("44'/1");
            Assert.False(keyPath.IsHardened);
            Assert.True(KeyPath.Parse("44'/1'").IsHardened);
            Assert.Equal(0x8000002Cu, keyPath[0]);
            Assert.Equal(1u, keyPath[1]);

            key = new ExtKey();
            Assert.Equal(key.Derive(keyPath).ToString(Network.PurpleMain), key.Derive(44, true).Derive(1, false).ToString(Network.PurpleMain));

            keyPath = KeyPath.Parse("");
            keyPath = keyPath.Derive(44, true).Derive(1, false);
            Assert.Equal("44'/1", keyPath.ToString());
            Assert.Equal("44'/2", keyPath.Increment().ToString());
            Assert.Equal("44'/1/2'", keyPath.Derive(1, true).Increment().ToString());
            Assert.Equal("44'", keyPath.Parent.ToString());
            Assert.Equal("", keyPath.Parent.Parent.ToString());
            Assert.Null(keyPath.Parent.Parent.Parent);
            Assert.Null(keyPath.Parent.Parent.Increment());
            Assert.Equal(key.Derive(keyPath).ToString(Network.PurpleMain), key.Derive(44, true).Derive(1, false).ToString(Network.PurpleMain));

            Assert.True(key.Derive(44, true).IsHardened);
            Assert.False(key.Derive(44, false).IsHardened);

            neuter = key.Derive(44, true).Neuter();
            Assert.True(neuter.IsHardened);
            neuter = key.Derive(44, false).Neuter();
            Assert.False(neuter.IsHardened);
        }
        public List <string> CreateCustomerAddresses(int count)
        {
            var customerId = AddressDao.GetMaxCustomerId(CurrentWallet.Id);

            var rootXPrivKey = ExtKey.Parse(CurrentWallet.RootXPrivKey);

            var addresses = new List <AddressInfo>();

            for (int i = 0; i < count; i++)
            {
                ++customerId;
                var keyPath = new KeyPath($"/{(int)CustomAddressType.Customer}'/{customerId}'");
                var address = KeyOperator.Instance.DeriveNewAddress(rootXPrivKey, keyPath);
                addresses.Add(new AddressInfo
                {
                    Id              = Guid.NewGuid().ToString("N"),
                    Address         = address,
                    WalletId        = CurrentWallet.Id,
                    Network         = (NetworkOperator.Instance.Network == Network.Main) ? (int)NetworkType.Mainnet : (int)NetworkType.Testnet,
                    KeyPath         = keyPath.ToString(),
                    CustomerId      = customerId,
                    PathIndex       = customerId,
                    AddressType     = (long)CustomAddressType.Customer,
                    AddressCategory = (long)AddressCategory.Receiver,
                    Name            = "客户" + customerId + "--充币"
                });
            }

            AddressDao.BatchCreate(addresses);

            return(addresses.Select(o => o.Address).ToList());
        }
Exemple #5
0
        public void CanUseKeyPath()
        {
            var keyPath = new KeyPath("0/1/2/3");

            Assert.Equal(keyPath.ToString(), "0/1/2/3");
            var key = new ExtKey();

            Assert.Equal(key
                         .Derive(0)
                         .Derive(1)
                         .Derive(2)
                         .Derive(3)
                         .ToString(Network.Main), key.Derive(keyPath).ToString(Network.Main));

            var neuter = key.Neuter();

            Assert.Equal(neuter
                         .Derive(0)
                         .Derive(1)
                         .Derive(2)
                         .Derive(3)
                         .ToString(Network.Main), neuter.Derive(keyPath).ToString(Network.Main));

            Assert.Equal(neuter.Derive(keyPath).ToString(Network.Main), key.Derive(keyPath).Neuter().ToString(Network.Main));
        }
Exemple #6
0
        public async Task DisplayAddressAsync(ScriptPubKeyType addressType, KeyPath keyPath, CancellationToken cancellationToken = default)
        {
            if (keyPath == null)
            {
                throw new ArgumentNullException(nameof(keyPath));
            }
            List <string> commandArguments = new List <string>();

            commandArguments.Add("--path");
            commandArguments.Add(keyPath.ToString(true, "h"));

            switch (addressType)
            {
            case ScriptPubKeyType.Segwit:
                commandArguments.Add("--wpkh");
                break;

            case ScriptPubKeyType.SegwitP2SH:
                commandArguments.Add("--sh_wpkh");
                break;
            }

            var response = await SendCommandAsync(
                command : HwiCommands.DisplayAddress,
                commandArguments : commandArguments.ToArray(),
                cancellationToken).ConfigureAwait(false);

            if (!HwiClient.IgnoreInvalidNetwork)
            {
                HwiParser.ParseAddress(response, HwiClient.Network);
            }
        }
Exemple #7
0
        public async Task <string> SignMessageAsync(string message, KeyPath keyPath, CancellationToken cancellationToken = default)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            if (keyPath == null)
            {
                throw new ArgumentNullException(nameof(keyPath));
            }
            var response = await SendCommandAsync(
                command : HwiCommands.SignMessage,
                commandArguments : new[] { message, keyPath.ToString(true, "h") },
                cancellationToken).ConfigureAwait(false);

            if (!JsonHelpers.TryParseJToken(response, out JToken token))
            {
                throw new InvalidOperationException($"Invalid response from hwi");
            }
            var signature = token["signature"]?.ToString().Trim();

            if (signature == null)
            {
                throw new InvalidOperationException($"Invalid response from hwi");
            }
            return(signature);
        }
Exemple #8
0
        /// <inheritdoc />
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            KeyPath keyPath = value as KeyPath;

            if (keyPath != null)
            {
                writer.WriteValue(keyPath.ToString());
            }
        }
Exemple #9
0
 private void AddDerivationSchemeToJson(string propertyName, JObject result, KeyPath keyPath, BitcoinExtPubKey xpub, DerivationStrategyBase strategy)
 {
     result.Add(new JProperty(propertyName, new JObject()
     {
         new JProperty("strategy", strategy.ToString()),
         new JProperty("accountKey", xpub.ToString()),
         new JProperty("keyPath", keyPath.ToString()),
     }));
 }
        public async Task<BitcoinExtPubKey> GetXPubAsync(KeyPath keyPath, CancellationToken cancellationToken = default)
        {
            if (keyPath == null)
                throw new ArgumentNullException(nameof(keyPath));
            string keyPathString = keyPath.ToString(true, "h");
            var response = await SendCommandAsync(
                command: HwiCommands.GetXpub,
                commandArguments: new[] { keyPathString },
                cancellationToken).ConfigureAwait(false);

            return ParseExtPubKey(response);
        }
Exemple #11
0
        private async Task <ExtPubKey> GetXpubImplAsync(HardwareWalletModels?deviceType, string devicePath, HDFingerprint?fingerprint, KeyPath keyPath, CancellationToken cancel)
        {
            string keyPathString = keyPath.ToString(true, "h");
            var    response      = await SendCommandAsync(
                options : BuildOptions(deviceType, devicePath, fingerprint),
                command : HwiCommands.GetXpub,
                commandArguments : keyPathString,
                openConsole : false,
                cancel).ConfigureAwait(false);

            var extPubKey = HwiParser.ParseExtPubKey(response);

            return(extPubKey);
        }
Exemple #12
0
        private async Task <BitcoinWitPubKeyAddress> DisplayAddressImplAsync(HardwareWalletModels?deviceType, string devicePath, HDFingerprint?fingerprint, KeyPath keyPath, CancellationToken cancel)
        {
            var response = await SendCommandAsync(
                options : BuildOptions(deviceType, devicePath, fingerprint),
                command : HwiCommands.DisplayAddress,
                commandArguments : $"--path {keyPath.ToString(true, "h")} --wpkh",
                openConsole : false,
                cancel).ConfigureAwait(false);

            var address = HwiParser.ParseAddress(response, Network) as BitcoinWitPubKeyAddress;

            address = address.TransformToNetworkNetwork(Network);

            return(address);
        }
Exemple #13
0
        /// <summary>
        ///  Describe ext public key
        /// </summary>
        /// <param name="extPubKey"></param>
        /// <param name="keyPath">The root of the keypath to follow</param>
        /// <returns></returns>
        public static ScanTxoutPubkey ExtPubKey(BitcoinExtPubKey extPubKey, KeyPath keyPath)
        {
            if (extPubKey == null)
            {
                throw new ArgumentNullException(nameof(extPubKey));
            }

            StringBuilder builder = new StringBuilder();

            builder.Append(extPubKey.ToString());
            if (keyPath != null && keyPath.Indexes.Length != 0)
            {
                builder.Append(keyPath.ToString().Replace("m/", String.Empty));
            }
            return(new ScanTxoutPubkey($"{builder.ToString()}"));
        }
        public XDSPubKeyAddress CreateHdAddress(byte[] walletSeed, int accountIndex, int changePath, int addressIndex)
        {
            var keyPath    = new KeyPath($"m/44'/{XDSPrincipal.XDSCoinType}'/{accountIndex}'/{changePath}/{addressIndex}");
            var seedExtKey = new ExtKey(walletSeed);
            var derivedKey = seedExtKey.Derive(keyPath);

            CompressedPubKey compressedPubKey = derivedKey.PrivateKey.CompressedPubKey;
            var hash    = compressedPubKey.GetHash160();
            var bech    = new Bech32Encoder("xds");
            var address = bech.Encode(0, hash);

            return(new XDSPubKeyAddress
            {
                PrivateKey = derivedKey.PrivateKey.RawBytes,
                PublicKey = derivedKey.PrivateKey.CompressedPubKey.ToBytes(),
                Hash = hash,
                KeyPath = keyPath.ToString(),
                Address = address,
                ScriptPubKey = ByteArrays.Concatenate(new byte[1], hash)
            });
        }
#pragma warning disable CS0618 // Type or member is obsolete
        public void SetWalletKeyPathRoot(PaymentMethodId paymentMethodId, KeyPath keyPath)
        {
            if (keyPath == null)
            {
                WalletKeyPathRoots.Remove(paymentMethodId.ToString());
            }
            else
            {
                WalletKeyPathRoots.AddOrReplace(paymentMethodId.ToString().ToLowerInvariant(), keyPath.ToString());
            }
        }
        public void MarkAsUsed(KeyInformation info)
        {
            var tableName            = $"U-{Hashes.Hash160(info.RootKey).ToString()}";
            var highestUsedIndexes   = new Dictionary <KeyPath, long>();
            var highestUnusedIndexes = new Dictionary <KeyPath, long>();

            using (var tx = _Engine.GetTransaction())
            {
                tx.ValuesLazyLoadingIsOn = false;
                if (info.KeyPath != null)
                {
                    tx.Insert(tableName, info.KeyPath.ToString(), true);
                }

                foreach (var row in tx.SelectForward <string, bool>(tableName))
                {
                    if (info.KeyPath == null)
                    {
                        return;                         //Early exit, no need to create the first keys, it has already been done
                    }
                    var     highestIndexes = row.Value ? highestUsedIndexes : highestUnusedIndexes;
                    KeyPath k = new KeyPath(row.Key);
                    long    highestKey;
                    if (!highestIndexes.TryGetValue(k.Parent, out highestKey))
                    {
                        highestKey = -1;
                    }
                    highestKey = Math.Max(highestKey, k.Indexes.Last());
                    highestIndexes.AddOrReplace(k.Parent, highestKey);
                }

                foreach (var trackedPath in TrackedPathes)
                {
                    ExtPubKey pathPubKey = null;
                    long      highestUnused;
                    if (!highestUnusedIndexes.TryGetValue(trackedPath, out highestUnused))
                    {
                        highestUnused = -1;
                    }

                    long highestUsed;
                    if (!highestUsedIndexes.TryGetValue(trackedPath, out highestUsed))
                    {
                        highestUsed = -1;
                    }

                    KeyPath highestUnusedPath = null;
                    while (highestUnused - highestUsed < MinGap)
                    {
                        if (highestUnused == uint.MaxValue)
                        {
                            break;
                        }
                        highestUnused++;

                        highestUnusedPath = trackedPath.Derive((uint)highestUnused);
                        pathPubKey        = pathPubKey ?? new ExtPubKey(info.RootKey).Derive(trackedPath);

                        var scriptPubKey = pathPubKey.Derive((uint)highestUnused).PubKey.Hash.ScriptPubKey;
                        InsertKeyInformation(tx, scriptPubKey, new KeyInformation()
                        {
                            KeyPath = trackedPath.Derive((uint)highestUnused),
                            RootKey = info.RootKey
                        });
                    }

                    if (highestUnusedPath != null)
                    {
                        byte[] inserted;
                        bool   existed;
                        tx.Insert(tableName, highestUnusedPath.ToString(), false, out inserted, out existed, dontUpdateIfExists: true);
                    }
                }
                tx.Commit();
            }
        }
 public ClientDestinationWallet(BitcoinExtPubKey extPubKey, KeyPath derivationPath, IRepository repository, Network network)
 {
     if (derivationPath == null)
     {
         throw new ArgumentNullException("derivationPath");
     }
     if (extPubKey == null)
     {
         throw new ArgumentNullException("extPubKey");
     }
     if (repository == null)
     {
         throw new ArgumentNullException("repository");
     }
     if (network == null)
     {
         throw new ArgumentNullException("network");
     }
     _Network        = network;
     _Repository     = repository;
     _ExtPubKey      = extPubKey.ExtPubKey.Derive(derivationPath);
     _DerivationPath = derivationPath;
     _WalletId       = "Wallet_" + Encoders.Base58.EncodeData(Hashes.Hash160(Encoding.UTF8.GetBytes(_ExtPubKey.ToString() + "-" + derivationPath.ToString())).ToBytes());
 }
        public void CanUseKeyPath()
        {
            var keyPath = KeyPath.Parse("0/1/2/3");

            Assert.Equal("0/1/2/3", keyPath.ToString());
            var key = new ExtKey();

            Assert.Equal(key
                         .Derive(0)
                         .Derive(1)
                         .Derive(2)
                         .Derive(3)
                         .ToString(Network.Main), key.Derive(keyPath).ToString(Network.Main));

            var neuter = key.Neuter();

            Assert.Equal(neuter
                         .Derive(0)
                         .Derive(1)
                         .Derive(2)
                         .Derive(3)
                         .ToString(Network.Main), neuter.Derive(keyPath).ToString(Network.Main));

            Assert.Equal(neuter.Derive(keyPath).ToString(Network.Main), key.Derive(keyPath).Neuter().ToString(Network.Main));

            keyPath = new KeyPath(new uint[] { 0x8000002Cu, 1u });
            Assert.Equal("44'/1", keyPath.ToString());

            keyPath = KeyPath.Parse("44'/1");
            Assert.False(keyPath.IsHardened);
            Assert.True(KeyPath.Parse("44'/1'").IsHardened);
            Assert.Equal(0x8000002Cu, keyPath[0]);
            Assert.Equal(1u, keyPath[1]);

            key = new ExtKey();
            Assert.Equal(key.Derive(keyPath).ToString(Network.Main), key.Derive(44, true).Derive(1, false).ToString(Network.Main));

            keyPath = KeyPath.Parse("");
            keyPath = keyPath.Derive(44, true).Derive(1, false);
            Assert.Equal("44'/1", keyPath.ToString());
            Assert.Equal("44'/2", keyPath.Increment().ToString());
            Assert.Equal("44'/1/2'", keyPath.Derive(1, true).Increment().ToString());
            Assert.Equal("44'", keyPath.Parent.ToString());
            Assert.Equal("", keyPath.Parent.Parent.ToString());
            Assert.Null(keyPath.Parent.Parent.Parent);
            Assert.Throws <InvalidOperationException>(() => keyPath.Parent.Parent.Increment());
            Assert.Equal(key.Derive(keyPath).ToString(Network.Main), key.Derive(44, true).Derive(1, false).ToString(Network.Main));

            Assert.True(key.Derive(44, true).IsHardened);
            Assert.False(key.Derive(44, false).IsHardened);

            neuter = key.Derive(44, true).Neuter();
            Assert.True(neuter.IsHardened);
            neuter = key.Derive(44, false).Neuter();
            Assert.False(neuter.IsHardened);

            KeyPath a = new KeyPath("3/2");
            KeyPath b = new KeyPath("5/6");

            Assert.Equal(new KeyPath("3/2/5/6"), a + b);
            b = null;
            Assert.Equal(a, a + b);
            a = null;
            Assert.Null(a + b);
            b = new KeyPath("5/6");
            Assert.Equal(new KeyPath("5/6"), a + b);
            a += new KeyPath("3/2");
            a += new KeyPath("5/6");
            Assert.Equal(new KeyPath("3/2/5/6"), a);
        }
Exemple #19
0
		public void CanUseKeyPath()
		{
			var keyPath = KeyPath.Parse("0/1/2/3");
			Assert.Equal(keyPath.ToString(), "0/1/2/3");
			var key = new ExtKey();
			Assert.Equal(key
							.Derive(0)
							.Derive(1)
							.Derive(2)
							.Derive(3)
							.ToString(Network.Main), key.Derive(keyPath).ToString(Network.Main));

			var neuter = key.Neuter();
			Assert.Equal(neuter
							.Derive(0)
							.Derive(1)
							.Derive(2)
							.Derive(3)
							.ToString(Network.Main), neuter.Derive(keyPath).ToString(Network.Main));

			Assert.Equal(neuter.Derive(keyPath).ToString(Network.Main), key.Derive(keyPath).Neuter().ToString(Network.Main));

			keyPath = new KeyPath(new uint[] { 0x8000002Cu, 1u });
			Assert.Equal(keyPath.ToString(), "44'/1");

			keyPath = KeyPath.Parse("44'/1");
			Assert.False(keyPath.IsHardened);
			Assert.True(KeyPath.Parse("44'/1'").IsHardened);
			Assert.Equal(keyPath[0], 0x8000002Cu);
			Assert.Equal(keyPath[1], 1u);

			key = new ExtKey();
			Assert.Equal(key.Derive(keyPath).ToString(Network.Main), key.Derive(44, true).Derive(1, false).ToString(Network.Main));

			keyPath = KeyPath.Parse("");
			keyPath = keyPath.Derive(44, true).Derive(1, false);
			Assert.Equal(keyPath.ToString(), "44'/1");
			Assert.Equal(keyPath.Increment().ToString(), "44'/2");
			Assert.Equal(keyPath.Derive(1,true).Increment().ToString(), "44'/1/2'");
			Assert.Equal(keyPath.Parent.ToString(), "44'");
			Assert.Equal(keyPath.Parent.Parent.ToString(), "");
			Assert.Equal(keyPath.Parent.Parent.Parent, null);
			Assert.Equal(keyPath.Parent.Parent.Increment(), null);
			Assert.Equal(key.Derive(keyPath).ToString(Network.Main), key.Derive(44, true).Derive(1, false).ToString(Network.Main));

			Assert.True(key.Derive(44, true).IsHardened);
			Assert.False(key.Derive(44, false).IsHardened);

			neuter = key.Derive(44, true).Neuter();
			Assert.True(neuter.IsHardened);
			neuter = key.Derive(44, false).Neuter();
			Assert.False(neuter.IsHardened);
		}
Exemple #20
0
    /// <inheritdoc />
    public override void WriteJson(JsonWriter writer, KeyPath?value, JsonSerializer serializer)
    {
        var s = value?.ToString() ?? throw new ArgumentNullException(nameof(value));

        writer.WriteValue(s);
    }