From 8d9f59c63d419b3ecce9559c56e3f1716b1b0846 Mon Sep 17 00:00:00 2001 From: Igor Matsak Date: Fri, 13 Aug 2021 14:09:21 +0300 Subject: [PATCH] Feature/standard Tezos key support --- Atomex.Client.Core | 2 +- Atomex.Client.Wpf.Installer/Product.wxs | 2 +- .../ViewModels/AddressesViewModel.cs | 89 +++++++++++++++---- .../DelegateConfirmationViewModel.cs | 6 +- .../ViewModels/DelegateViewModel.cs | 6 +- Atomex.Client.Wpf/Views/AddressesView.xaml | 4 + .../Views/SendViews/TezosTokensSendPage.xaml | 2 +- 7 files changed, 85 insertions(+), 26 deletions(-) diff --git a/Atomex.Client.Core b/Atomex.Client.Core index 42a0bb1..b83730f 160000 --- a/Atomex.Client.Core +++ b/Atomex.Client.Core @@ -1 +1 @@ -Subproject commit 42a0bb156d0a31862bf1f6b7dd101d61cd7ff237 +Subproject commit b83730fca98d596a3b33caf4840530e50449bed4 diff --git a/Atomex.Client.Wpf.Installer/Product.wxs b/Atomex.Client.Wpf.Installer/Product.wxs index ea41784..ea1cf29 100644 --- a/Atomex.Client.Wpf.Installer/Product.wxs +++ b/Atomex.Client.Wpf.Installer/Product.wxs @@ -3,7 +3,7 @@ - + diff --git a/Atomex.Client.Wpf/ViewModels/AddressesViewModel.cs b/Atomex.Client.Wpf/ViewModels/AddressesViewModel.cs index 9d2345c..30857ab 100644 --- a/Atomex.Client.Wpf/ViewModels/AddressesViewModel.cs +++ b/Atomex.Client.Wpf/ViewModels/AddressesViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.Linq; @@ -16,18 +17,19 @@ using Atomex.Client.Wpf.Controls; using Atomex.Wallet; using Atomex.Wallet.Tezos; -using System.Collections.ObjectModel; +using Atomex.Cryptography; +using Atomex.Blockchain.Tezos.Internal; namespace Atomex.Client.Wpf.ViewModels { public class AddressInfo { public string Address { get; set; } + public string Type { get; set; } public string Path { get; set; } public string Balance { get; set; } - //public string CurrencyCode { get; set; } public string TokenBalance { get; set; } - //public string TokenCode { get; set; } + public Action CopyToClipboard { get; set; } public Action OpenInExplorer { get; set; } public Action Update { get; set; } @@ -65,7 +67,7 @@ public class AddressesViewModel : BaseViewModel private CurrencyConfig _currency; private bool _isBalanceUpdating; private CancellationTokenSource _cancellation; - private string _tokenContract; + private readonly string _tokenContract; public ObservableCollection Addresses { get; set; } public bool HasTokens { get; set; } @@ -117,23 +119,41 @@ public async void RealodAddresses() addresses.Sort((a1, a2) => { + var typeResult = a1.KeyType.CompareTo(a2.KeyType); + + if (typeResult != 0) + return typeResult; + + var accountResult = a1.KeyIndex.Account.CompareTo(a2.KeyIndex.Account); + + if (accountResult != 0) + return accountResult; + var chainResult = a1.KeyIndex.Chain.CompareTo(a2.KeyIndex.Chain); - return chainResult == 0 - ? a1.KeyIndex.Index.CompareTo(a2.KeyIndex.Index) - : chainResult; + return chainResult != 0 + ? chainResult + : a1.KeyIndex.Index.CompareTo(a2.KeyIndex.Index); }); Addresses = new ObservableCollection( - addresses.Select(a => new AddressInfo + addresses.Select(a => { - Address = a.Address, - Path = $"m/44'/{_currency.Bip44Code}/0'/{a.KeyIndex.Chain}/{a.KeyIndex.Index}", - Balance = $"{a.Balance.ToString(CultureInfo.InvariantCulture)} {_currency.Name}", - CopyToClipboard = CopyToClipboard, - OpenInExplorer = OpenInExplorer, - Update = Update, - ExportKey = ExportKey + var path = a.KeyType == CurrencyConfig.StandardKey && Currencies.IsTezosBased(_currency.Name) + ? $"m/44'/{_currency.Bip44Code}'/{a.KeyIndex.Account}'/{a.KeyIndex.Chain}'" + : $"m/44'/{_currency.Bip44Code}'/{a.KeyIndex.Account}'/{a.KeyIndex.Chain}/{a.KeyIndex.Index}"; + + return new AddressInfo + { + Address = a.Address, + Type = KeyTypeToString(a.KeyType), + Path = path, + Balance = $"{a.Balance.ToString(CultureInfo.InvariantCulture)} {_currency.Name}", + CopyToClipboard = CopyToClipboard, + OpenInExplorer = OpenInExplorer, + Update = Update, + ExportKey = ExportKey + }; })); // token balances @@ -183,6 +203,14 @@ public async void RealodAddresses() } } + private string KeyTypeToString(int keyType) => + keyType switch + { + CurrencyConfig.StandardKey => "Standard", + TezosConfig.Bip32Ed25519Key => "Atomex", + _ => throw new NotSupportedException($"Key type {keyType} not supported.") + }; + private void CopyToClipboard(string address) { try @@ -282,14 +310,37 @@ private async void ExportKey(string address) var hdWallet = _app.Account.Wallet as HdWallet; - using var privateKey = hdWallet.KeyStorage - .GetPrivateKey(_currency, walletAddress.KeyIndex); + using var privateKey = hdWallet.KeyStorage.GetPrivateKey( + currency: _currency, + keyIndex: walletAddress.KeyIndex, + keyType: walletAddress.KeyType); using var unsecuredPrivateKey = privateKey.ToUnsecuredBytes(); - var hex = Hex.ToHexString(unsecuredPrivateKey.Data); + if (Currencies.IsBitcoinBased(_currency.Name)) + { + var btcBasedConfig = _currency as BitcoinBasedConfig; + + var wif = new NBitcoin.Key(unsecuredPrivateKey) + .GetWif(btcBasedConfig.Network) + .ToWif(); + + Clipboard.SetText(wif); + } + else if (Currencies.IsTezosBased(_currency.Name)) + { + var base58 = unsecuredPrivateKey.Length == 32 + ? Base58Check.Encode(unsecuredPrivateKey, Prefix.Edsk) + : Base58Check.Encode(unsecuredPrivateKey, Prefix.EdskSecretKey); + + Clipboard.SetText(base58); + } + else + { + var hex = Hex.ToHexString(unsecuredPrivateKey.Data); - Clipboard.SetText(hex); + Clipboard.SetText(hex); + } Warning = "Private key successfully copied to clipboard."; } diff --git a/Atomex.Client.Wpf/ViewModels/DelegateConfirmationViewModel.cs b/Atomex.Client.Wpf/ViewModels/DelegateConfirmationViewModel.cs index 49f2dd1..91f818a 100644 --- a/Atomex.Client.Wpf/ViewModels/DelegateConfirmationViewModel.cs +++ b/Atomex.Client.Wpf/ViewModels/DelegateConfirmationViewModel.cs @@ -91,8 +91,10 @@ await tezosAccount.AddressLocker OperationType = OperationType.Delegation }; - using var securePublicKey = App.Account.Wallet - .GetPublicKey(Currency, WalletAddress.KeyIndex); + using var securePublicKey = App.Account.Wallet.GetPublicKey( + currency: Currency, + keyIndex: WalletAddress.KeyIndex, + keyType: WalletAddress.KeyType); await tx.FillOperationsAsync( securePublicKey: securePublicKey, diff --git a/Atomex.Client.Wpf/ViewModels/DelegateViewModel.cs b/Atomex.Client.Wpf/ViewModels/DelegateViewModel.cs index 30c0a66..3f0f266 100644 --- a/Atomex.Client.Wpf/ViewModels/DelegateViewModel.cs +++ b/Atomex.Client.Wpf/ViewModels/DelegateViewModel.cs @@ -407,8 +407,10 @@ private async Task> GetDelegate( .GetAddressAsync(_selectedAddress.Address) .WaitForResult(); - using var securePublicKey = App.Account.Wallet - .GetPublicKey(_tezosConfig, walletAddress.KeyIndex); + using var securePublicKey = App.Account.Wallet.GetPublicKey( + currency: _tezosConfig, + keyIndex: walletAddress.KeyIndex, + keyType: walletAddress.KeyType); var isSuccess = await tx.FillOperationsAsync( securePublicKey: securePublicKey, diff --git a/Atomex.Client.Wpf/Views/AddressesView.xaml b/Atomex.Client.Wpf/Views/AddressesView.xaml index 3bc9e68..b64aa25 100644 --- a/Atomex.Client.Wpf/Views/AddressesView.xaml +++ b/Atomex.Client.Wpf/Views/AddressesView.xaml @@ -76,6 +76,10 @@ +