/// <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); }
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); }
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()); }
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)); }
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); } }
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); }
/// <inheritdoc /> public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { KeyPath keyPath = value as KeyPath; if (keyPath != null) { writer.WriteValue(keyPath.ToString()); } }
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); }
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); }
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); }
/// <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); }
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); }
/// <inheritdoc /> public override void WriteJson(JsonWriter writer, KeyPath?value, JsonSerializer serializer) { var s = value?.ToString() ?? throw new ArgumentNullException(nameof(value)); writer.WriteValue(s); }