From 5ade4e3f566b5a8b614dffed5a7606d4b96ab663 Mon Sep 17 00:00:00 2001 From: Harry Date: Wed, 1 Mar 2023 15:22:09 -0800 Subject: [PATCH 1/5] add WIF account support --- src/neoxp/Extensions/Extensions.cs | 37 +++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/neoxp/Extensions/Extensions.cs b/src/neoxp/Extensions/Extensions.cs index 53da8f9d..d1f6b185 100644 --- a/src/neoxp/Extensions/Extensions.cs +++ b/src/neoxp/Extensions/Extensions.cs @@ -168,6 +168,11 @@ public static bool TryGetSigningAccount(this ExpressChainManager chainManager, s } } + if (TryGetWIF(name, settings, out wallet, out accountHash)) + { + return true; + } + if (!string.IsNullOrEmpty(password)) { if (TryGetNEP2Wallet(name, password, settings, out wallet, out accountHash)) @@ -186,14 +191,27 @@ public static bool TryGetSigningAccount(this ExpressChainManager chainManager, s accountHash = null; return false; + static bool TryGetWIF(string wif, ProtocolSettings settings, [MaybeNullWhen(false)] out Wallet wallet, [MaybeNullWhen(false)] out UInt160 accountHash) + { + try + { + var privateKey = Wallet.GetPrivateKeyFromWIF(wif); + CreateWallet(privateKey, settings, out wallet, out accountHash); + return true; + } + catch + { + wallet = null; + accountHash = null; + return false; + } + } static bool TryGetNEP2Wallet(string nep2, string password, ProtocolSettings settings, [MaybeNullWhen(false)] out Wallet wallet, [MaybeNullWhen(false)] out UInt160 accountHash) { try { var privateKey = Wallet.GetPrivateKeyFromNEP2(nep2, password, settings.AddressVersion); - wallet = new DevWallet(settings, string.Empty); - var account = wallet.CreateAccount(privateKey); - accountHash = account.ScriptHash; + CreateWallet(privateKey, settings, out wallet, out accountHash); return true; } catch @@ -214,9 +232,7 @@ static bool TryGetNEP6Wallet(string path, string password, ProtocolSettings sett ?? throw new InvalidOperationException("Neo-express only supports NEP-6 wallets with a single default account or a single account"); if (nep6account.IsMultiSigContract()) throw new Exception("Neo-express doesn't supports multi-sig NEP-6 accounts"); var keyPair = nep6account.GetKey() ?? throw new Exception("account.GetKey() returned null"); - wallet = new DevWallet(settings, string.Empty); - var account = wallet.CreateAccount(keyPair.PrivateKey); - accountHash = account.ScriptHash; + CreateWallet(keyPair.PrivateKey, settings, out wallet, out accountHash); return true; } catch @@ -226,6 +242,15 @@ static bool TryGetNEP6Wallet(string path, string password, ProtocolSettings sett return false; } } + + static void CreateWallet(byte[] privateKey, ProtocolSettings settings, out Wallet wallet, out UInt160 accountHash) + { + wallet = new DevWallet(settings, string.Empty); + var account = wallet.CreateAccount(privateKey); + accountHash = account.ScriptHash; + } + + } } } From 5d1e31a5443ce95db4cc63fa6bad51e003a74e6f Mon Sep 17 00:00:00 2001 From: Harry Date: Wed, 1 Mar 2023 15:32:06 -0800 Subject: [PATCH 2/5] add WIF to wallet list command --- src/neoxp/Commands/WalletCommand.List.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/neoxp/Commands/WalletCommand.List.cs b/src/neoxp/Commands/WalletCommand.List.cs index f82d7428..8e9b1338 100644 --- a/src/neoxp/Commands/WalletCommand.List.cs +++ b/src/neoxp/Commands/WalletCommand.List.cs @@ -83,6 +83,8 @@ static void PrintAccountInfo(JsonTextWriter writer, string walletName, Neo.Walle writer.WriteValue(account.ScriptHash.ToString()); writer.WritePropertyName("private-key"); writer.WriteValue(Convert.ToHexString(keyPair.PrivateKey)); + writer.WritePropertyName("private-key-wif"); + writer.WriteValue(keyPair.Export()); writer.WritePropertyName("public-key"); writer.WriteValue(Convert.ToHexString(keyPair.PublicKey.EncodePoint(true))); writer.WriteEndObject(); @@ -121,9 +123,10 @@ static void PrintAccountInfo(TextWriter writer, Neo.Wallets.WalletAccount accoun var keyPair = account.GetKey() ?? throw new Exception(); writer.WriteLine($" {account.Address} ({(account.IsDefault ? "Default" : account.Label)})"); - writer.WriteLine($" script hash: {BitConverter.ToString(account.ScriptHash.ToArray())}"); - writer.WriteLine($" public key: {Convert.ToHexString(keyPair.PublicKey.EncodePoint(true))}"); - writer.WriteLine($" private key: {Convert.ToHexString(keyPair.PrivateKey)}"); + writer.WriteLine($" script hash: {BitConverter.ToString(account.ScriptHash.ToArray())}"); + writer.WriteLine($" public key: {Convert.ToHexString(keyPair.PublicKey.EncodePoint(true))}"); + writer.WriteLine($" private key: {Convert.ToHexString(keyPair.PrivateKey)}"); + writer.WriteLine($" private key (WIF): {keyPair.Export()}"); } } From 39c3e36524272e577a2a670350441cd6503c691e Mon Sep 17 00:00:00 2001 From: Harry Date: Wed, 1 Mar 2023 15:42:00 -0800 Subject: [PATCH 3/5] support WIF strings where account hash is needed --- src/neoxp/Extensions/ExpressNodeExtensions.cs | 22 +++++++++++++++++++ src/neoxp/Extensions/Extensions.cs | 5 +++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/neoxp/Extensions/ExpressNodeExtensions.cs b/src/neoxp/Extensions/ExpressNodeExtensions.cs index d0079c17..2a85266d 100644 --- a/src/neoxp/Extensions/ExpressNodeExtensions.cs +++ b/src/neoxp/Extensions/ExpressNodeExtensions.cs @@ -114,7 +114,29 @@ public static async Task> TryGetAccountHashAsync(this IExpr return accountHash; } + if (TryGetWIFAccountHash(name, out accountHash)) + { + return accountHash; + } + return default(None); + + static bool TryGetWIFAccountHash(string wif, out UInt160 accountHash) + { + try + { + var privateKey = Wallet.GetPrivateKeyFromWIF(wif); + var keyPair = new KeyPair(privateKey); + var contract = Contract.CreateSignatureContract(keyPair.PublicKey); + accountHash = contract.ScriptHash; + return true; + } + catch + { + accountHash = UInt160.Zero; + return false; + } + } } public static async Task ParseAssetAsync(this IExpressNode expressNode, string asset) diff --git a/src/neoxp/Extensions/Extensions.cs b/src/neoxp/Extensions/Extensions.cs index d1f6b185..19548982 100644 --- a/src/neoxp/Extensions/Extensions.cs +++ b/src/neoxp/Extensions/Extensions.cs @@ -168,7 +168,7 @@ public static bool TryGetSigningAccount(this ExpressChainManager chainManager, s } } - if (TryGetWIF(name, settings, out wallet, out accountHash)) + if (TryGetWIFWallet(name, settings, out wallet, out accountHash)) { return true; } @@ -191,7 +191,7 @@ public static bool TryGetSigningAccount(this ExpressChainManager chainManager, s accountHash = null; return false; - static bool TryGetWIF(string wif, ProtocolSettings settings, [MaybeNullWhen(false)] out Wallet wallet, [MaybeNullWhen(false)] out UInt160 accountHash) + static bool TryGetWIFWallet(string wif, ProtocolSettings settings, [MaybeNullWhen(false)] out Wallet wallet, [MaybeNullWhen(false)] out UInt160 accountHash) { try { @@ -206,6 +206,7 @@ static bool TryGetWIF(string wif, ProtocolSettings settings, [MaybeNullWhen(fals return false; } } + static bool TryGetNEP2Wallet(string nep2, string password, ProtocolSettings settings, [MaybeNullWhen(false)] out Wallet wallet, [MaybeNullWhen(false)] out UInt160 accountHash) { try From 29cb87f94c9f1c3f39be46001ea69b19a0f99ab3 Mon Sep 17 00:00:00 2001 From: Harry Date: Mon, 6 Mar 2023 14:51:36 -0800 Subject: [PATCH 4/5] Update command reference for WIF support --- docs/command-reference.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/command-reference.md b/docs/command-reference.md index 141ba6f7..bcbe1025 100644 --- a/docs/command-reference.md +++ b/docs/command-reference.md @@ -21,12 +21,22 @@ multiple ways: - `genesis` to use the consensus node multi-sig account which holds the genesis NEO and GAS - Neo-Express wallet nickname (see `wallet create` below). Note, this includes `node1` etc to specify the default wallet account associated with each consensus node +- A [WIF encoded](https://developer.bitcoin.org/devguide/wallets.html#wallet-import-format-wif) private key - A [standard NEP-2 Passphrase-protected private key](https://github.com/neo-project/proposals/blob/master/nep-2.mediawiki). - When using a NEP-2 protected private key, the passphrase must be specified using the `--password` option - The path to a [standard NEP-6 JSON wallet](https://github.com/neo-project/proposals/blob/master/nep-6.mediawiki). - When using a NEP-6 wallet, the password must be specified using the `--password` option. - Note, Neo-Express only supports NEP-6 wallets with either a single account or a single default account +NEP-2 private key and NEP-6 JSON wallet are password protected. When using one of these methods, the password +can be specified using the `--password` option. If the password is not specified on the command line, Neo-Express +will prompt the user to enter the password. + +> Note, `neoxp batch` command does not support interactive prompting. Using a NEP-2 private key or NEP-6 wallet +> with `neoxp batch` also requires specifying the `--password` option. Needless to say, storing a password in +> an unencrpted batch file is not secure, and developers should not use wallets associated with production, mainnet +> assets with Neo-Express. + ### Specifying a Non-Signing Account A account used that is not used for signing doesn't need an accessible private key. Non-Signing accounts @@ -36,6 +46,7 @@ can be specified in multiple ways: - Neo-Express wallet nickname (see `wallet create` below). Note, this includes `node1` etc to specify the default wallet account associated with each consensus node - A standard Neo N3 address such as `Ne4Ko2JkzjAd8q2sasXsQCLfZ7nu8Gm5vR` +- A [WIF encoded](https://developer.bitcoin.org/devguide/wallets.html#wallet-import-format-wif) private key ## neoxp create From 4ad405a0a4fca7eb421ed979fb93f98fa4446e8a Mon Sep 17 00:00:00 2001 From: Harry Date: Mon, 6 Mar 2023 14:58:07 -0800 Subject: [PATCH 5/5] update changelog --- changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index 05f3f2b3..19b87695 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,10 @@ may not exactly match a publicly released version. ## [3.6] - Unreleased +### Added + +* WIF encoded private keys can be used to specify signing and non-signing accounts + ## [3.5] - 2023-01-03 ### Changed