diff --git a/src/GWallet.Backend/Account.fs b/src/GWallet.Backend/Account.fs index ddc2255fd..7ca084de6 100644 --- a/src/GWallet.Backend/Account.fs +++ b/src/GWallet.Backend/Account.fs @@ -97,14 +97,20 @@ module Account = failwith "OK, all accounts and cache is clear, you can disable this code block again" #endif - seq { - for currency in allCurrencies do - let activeKinds = [AccountKind.ReadOnly; AccountKind.Normal] - for kind in activeKinds do - for accountFile in Config.GetAccountFiles [currency] kind do - yield GetAccountFromFile accountFile currency kind - } + let allAccounts = + seq { + for currency in allCurrencies do + let activeKinds = [AccountKind.ReadOnly; AccountKind.Normal] + for kind in activeKinds do + for accountFile in Config.GetAccountFiles [currency] kind do + yield GetAccountFromFile accountFile currency kind + } + +#if NATIVE_SEGWIT + UtxoCoin.Account.MigrateReadOnlyAccountsToNativeSegWit allAccounts +#endif + allAccounts let GetNormalAccountsPairingInfoForWatchWallet(): Option = let allCurrencies = Currency.GetAll() @@ -512,30 +518,17 @@ module Account = let json = SerializeSignedTransaction trans false File.WriteAllText(filePath, json) - let CreateReadOnlyAccounts (watchWalletInfo: WatchWalletInfo): Async = async { - for etherCurrency in Currency.GetAll().Where(fun currency -> currency.IsEtherBased()) do - do! ValidateAddress etherCurrency watchWalletInfo.EtherPublicAddress - let conceptAccountForReadOnlyAccount = { - Currency = etherCurrency - FileRepresentation = { Name = watchWalletInfo.EtherPublicAddress; Content = fun _ -> String.Empty } - ExtractPublicAddressFromConfigFileFunc = (fun file -> file.Name) - } - Config.AddAccount conceptAccountForReadOnlyAccount AccountKind.ReadOnly - |> ignore - - for utxoCurrency in Currency.GetAll().Where(fun currency -> currency.IsUtxo()) do - let address = - UtxoCoin.Account.GetPublicAddressFromPublicKey utxoCurrency - (NBitcoin.PubKey(watchWalletInfo.UtxoCoinPublicKey)) - do! ValidateAddress utxoCurrency address - let conceptAccountForReadOnlyAccount = { - Currency = utxoCurrency - FileRepresentation = { Name = address; Content = fun _ -> watchWalletInfo.UtxoCoinPublicKey } - ExtractPublicAddressFromConfigFileFunc = (fun file -> file.Name) + let CreateReadOnlyAccounts (watchWalletInfo: WatchWalletInfo): Async = + let ethJob = Ether.Account.CreateReadOnlyAccounts watchWalletInfo.EtherPublicAddress + let utxoJob = + async { + UtxoCoin.Account.CreateReadOnlyAccounts watchWalletInfo.UtxoCoinPublicKey } - Config.AddAccount conceptAccountForReadOnlyAccount AccountKind.ReadOnly - |> ignore - } + async { + do! + Async.Parallel [ethJob; utxoJob] + |> Async.Ignore + } let Remove (account: ReadOnlyAccount) = Config.RemoveReadOnlyAccount account diff --git a/src/GWallet.Backend/Config.fs b/src/GWallet.Backend/Config.fs index 17c213bd9..59a4bdd22 100644 --- a/src/GWallet.Backend/Config.fs +++ b/src/GWallet.Backend/Config.fs @@ -170,3 +170,10 @@ module Config = let RemoveReadOnlyAccount (account: ReadOnlyAccount): unit = RemoveAccount account + + [] + let private NoInitMsg = "This function never really existed, but it's here to warn you that yes, configuration needs to be initialized (e.g. for migrations) but it's done in Account.GetAllActiveAccounts() so that it's done by all frontends seamlessly (not explicitly)" + + [] + let Init() = + failwith NoInitMsg diff --git a/src/GWallet.Backend/Ether/EtherAccount.fs b/src/GWallet.Backend/Ether/EtherAccount.fs index 0daff27d7..e64496bae 100644 --- a/src/GWallet.Backend/Ether/EtherAccount.fs +++ b/src/GWallet.Backend/Ether/EtherAccount.fs @@ -6,6 +6,7 @@ open System open System.Numerics open System.Threading.Tasks +open System.Linq open Nethereum.ABI.Decoders open Nethereum.Signer @@ -154,6 +155,19 @@ module internal Account = raise (AddressWithInvalidChecksum(Some validCheckSumAddress)) } + let internal CreateReadOnlyAccounts (etherPublicAddress: string) = + async { + for etherCurrency in Currency.GetAll().Where(fun currency -> currency.IsEtherBased()) do + do! ValidateAddress etherCurrency etherPublicAddress + let conceptAccountForReadOnlyAccount = { + Currency = etherCurrency + FileRepresentation = { Name = etherPublicAddress; Content = fun _ -> String.Empty } + ExtractPublicAddressFromConfigFileFunc = (fun file -> file.Name) + } + Config.AddAccount conceptAccountForReadOnlyAccount AccountKind.ReadOnly + |> ignore + } + let private GetTransactionCount (currency: Currency) (publicAddress: string): Async = async { let! result = Ether.Server.GetTransactionCount currency publicAddress let value = result.Value diff --git a/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs b/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs index c31e496b2..09e57ea30 100644 --- a/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs +++ b/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs @@ -621,11 +621,12 @@ module Account = else addressOrUrl,None + let BITCOIN_ADDRESS_BECH32_PREFIX = "bc1" + let internal ValidateAddress (currency: Currency) (address: string) = if String.IsNullOrEmpty address then raise <| ArgumentNullException "address" - let BITCOIN_ADDRESS_BECH32_PREFIX = "bc1" let LITECOIN_ADDRESS_BECH32_PREFIX = "ltc1" let utxoCoinValidAddressPrefixes = @@ -683,6 +684,49 @@ module Account = | :? FormatException -> raise (AddressWithInvalidChecksum None) + let internal CreateReadOnlyAccounts (utxoPublicKey: string) = + for utxoCurrency in Currency.GetAll().Where(fun currency -> currency.IsUtxo()) do + let address = + GetPublicAddressFromPublicKey + utxoCurrency + (NBitcoin.PubKey utxoPublicKey) + ValidateAddress utxoCurrency address + let conceptAccountForReadOnlyAccount = { + Currency = utxoCurrency + FileRepresentation = { Name = address; Content = fun _ -> utxoPublicKey } + ExtractPublicAddressFromConfigFileFunc = (fun file -> file.Name) + } + Config.AddAccount conceptAccountForReadOnlyAccount AccountKind.ReadOnly + |> ignore + +#if NATIVE_SEGWIT + let internal MigrateReadOnlyAccountsToNativeSegWit (allAccounts: seq): unit = + let utxoAccountsToMigrate = + seq { + for utxoAccount in allAccounts.Where(fun acc -> acc.Currency.IsUtxo()) do + match utxoAccount with + | :? ReadOnlyAccount as readOnlyAccount -> + let accountFile = readOnlyAccount.AccountFile + if not (accountFile.Name.StartsWith BITCOIN_ADDRESS_BECH32_PREFIX) then + yield readOnlyAccount + | _ -> () + } + + let utxoPublicKeys = + seq { + for utxoReadOnlyAccount in utxoAccountsToMigrate do + let accountFile = utxoReadOnlyAccount.AccountFile + let utxoPublicKey = accountFile.Content() + yield utxoPublicKey + } |> Set.ofSeq + + for utxoPublicKey in utxoPublicKeys do + CreateReadOnlyAccounts utxoPublicKey + + for utxoReadOnlyAccount in utxoAccountsToMigrate do + Config.RemoveReadOnlyAccount utxoReadOnlyAccount +#endif + let GetSignedTransactionDetails<'T when 'T :> IBlockchainFeeInfo>(rawTransaction: string) (currency: Currency) : ITransactionDetails =