Skip to content

Commit

Permalink
WIP: use archived account
Browse files Browse the repository at this point in the history
Ditch ImportedAccount type completely to avoid errors in
legacy CI lanes.
  • Loading branch information
webwarrior-ws committed Jul 23, 2024
1 parent 66ee288 commit 33f52b0
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 120 deletions.
30 changes: 25 additions & 5 deletions src/GWallet.Backend/Account.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ open System.Threading.Tasks

open GWallet.Backend.FSharpUtil.UwpHacks

open NBitcoin

// this exception, if it happens, it would cause a crash because we don't handle it yet
type UnhandledCurrencyServerException(currency: Currency,
innerException: Exception) =
Expand Down Expand Up @@ -395,12 +397,30 @@ module Account =
|> ignore<ArchivedAccount>
Config.RemoveNormalAccount account

let ArchiveImportedAccount (importedAccount: UtxoCoin.ImportedAccount) =
let currency = (importedAccount :> IAccount).Currency
let CreateArchivedAccountFromSeedMenmonic (mnemonic: string) : UtxoCoin.ArchivedUtxoAccount =
let rootKey = Mnemonic(mnemonic).DeriveExtKey().Derive(KeyPath("m/84'/0'/0'"))
let firstReceivingAddressKey = rootKey.Derive(0u).Derive(0u)

let currency = Currency.BTC
let network = UtxoCoin.Account.GetNetwork currency
let privateKeyString =
importedAccount.PrivateKey.GetWif(UtxoCoin.Account.GetNetwork currency).ToWif()
CreateArchivedAccount currency privateKeyString
|> ignore<ArchivedAccount>
firstReceivingAddressKey.PrivateKey.GetWif(network).ToWif()
let archivedAccount = CreateArchivedAccount currency privateKeyString

let fromAccountFileToPrivateKey (accountConfigFile: FileRepresentation) =
Key.Parse(accountConfigFile.Content(), network)

let fromAccountFileToPublicAddress (accountConfigFile: FileRepresentation) =
fromAccountFileToPrivateKey(accountConfigFile).PubKey.GetAddress(ScriptPubKeyType.Segwit, network).ToString()

let fromAccountFileToPublicKey (accountConfigFile: FileRepresentation) =
fromAccountFileToPrivateKey(accountConfigFile).PubKey

UtxoCoin.ArchivedUtxoAccount(
currency,
archivedAccount.AccountFile,
fromAccountFileToPublicAddress,
fromAccountFileToPublicKey)

let SweepArchivedFunds (account: ArchivedAccount)
(balance: decimal)
Expand Down
4 changes: 3 additions & 1 deletion src/GWallet.Backend/Config.fs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ module Config =
let configDirForAccounts = GetConfigDirForAccounts()
Directory.Delete(configDirForAccounts.FullName, true)

// we don't expose this as public because we don't want to allow removing archived accounts
let private RemoveAccount (account: BaseAccount): unit =
let configFile = GetFile (account:>IAccount).Currency account
if not configFile.Exists then
Expand All @@ -173,6 +172,9 @@ module Config =
let RemoveReadOnlyAccount (account: ReadOnlyAccount): unit =
RemoveAccount account

let RemoveArchivedAccount (account: ArchivedAccount): unit =
RemoveAccount account

/// NOTE: the real initialization happens in Account.fs , see isInitialized
let internal Init() =
// In case a new token was added it will not have a config for an existing user
Expand Down
1 change: 0 additions & 1 deletion src/GWallet.Backend/GWallet.Backend-legacy.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
<Compile Include="UtxoCoin\UtxoCoinMinerFee.fs" />
<Compile Include="UtxoCoin\TransactionTypes.fs" />
<Compile Include="UtxoCoin\UtxoCoinAccount.fs" />
<Compile Include="UtxoCoin\ImportedAccount.fs" />
<Compile Include="Ether\EtherExceptions.fs" />
<Compile Include="Ether\EtherMinerFee.fs" />
<Compile Include="Ether\TransactionMetadata.fs" />
Expand Down
1 change: 0 additions & 1 deletion src/GWallet.Backend/GWallet.Backend.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
<Compile Include="UtxoCoin\UtxoCoinMinerFee.fs" />
<Compile Include="UtxoCoin\TransactionTypes.fs" />
<Compile Include="UtxoCoin\UtxoCoinAccount.fs" />
<Compile Include="UtxoCoin\ImportedAccount.fs" />
<Compile Include="Ether\EtherExceptions.fs" />
<Compile Include="Ether\EtherMinerFee.fs" />
<Compile Include="Ether\TransactionMetadata.fs" />
Expand Down
35 changes: 0 additions & 35 deletions src/GWallet.Backend/UtxoCoin/ImportedAccount.fs

This file was deleted.

10 changes: 0 additions & 10 deletions src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs
Original file line number Diff line number Diff line change
Expand Up @@ -535,16 +535,6 @@ module Account =
let finalTransaction = SignTransaction account txMetadata destination amount password
BroadcastRawTransaction baseAccount.Currency finalTransaction ignoreHigherMinerFeeThanAmount

let internal SendPaymentFromImportedAccount (account: IUtxoAccount)
(destination: string)
(amount: TransferAmount)
(privateKey: Key) =
async {
let! txMetadata = EstimateFee account amount destination
let signedTransaction = SignTransactionWithPrivateKey account txMetadata destination amount privateKey
return! BroadcastRawTransaction account.Currency (signedTransaction.ToHex()) false
}

// TODO: maybe move this func to Backend.Account module, or simply inline it (simple enough)
let public ExportUnsignedTransactionToJson trans =
Marshalling.Serialize trans
Expand Down
149 changes: 82 additions & 67 deletions src/GWallet.Frontend.Console/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -351,11 +351,11 @@ module Program =
()

let TransferFundsFromWalletUsingMenmonic() =
let rec askForMnemonic() : UtxoCoin.ImportedAccount =
let rec askForMnemonic() : UtxoCoin.ArchivedUtxoAccount =
Console.WriteLine "Enter mnemonic seed phrase (12, 15, 18, 21 or 24 words):"
let mnemonic = Console.ReadLine()
try
UtxoCoin.ImportedAccount mnemonic
Account.CreateArchivedAccountFromSeedMenmonic mnemonic
with
| :? FormatException as exn ->
printfn "Error reading mnemonic seed phrase: %s" exn.Message
Expand All @@ -364,72 +364,87 @@ module Program =
let importedAccount = askForMnemonic()
let currency = BTC

let maybeTotalBalance = importedAccount.GetTotalBalance() |> Async.RunSynchronously
match maybeTotalBalance with
| None -> Console.WriteLine "Could not retrieve balance"
| Some 0.0m -> Console.WriteLine "Balance on imported account is zero. No funds to transfer."
| Some balance ->
let _, maybeUsdValue = UserInteraction.GetAccountBalance importedAccount |> Async.RunSynchronously

printfn
"Balance on imported account: %s BTC (%s)"
(balance.ToString())
(UserInteraction.BalanceInUsdString balance maybeUsdValue)

let rec chooseAccount() =
Console.WriteLine "Choose account to send funds to:"
Console.WriteLine()
let allAccounts = Account.GetAllActiveAccounts() |> Seq.toList
let btcAccounts = allAccounts |> List.filter (fun acc -> acc.Currency = currency)

match btcAccounts with
| [ singleAccount ] -> Some singleAccount
| [] -> failwith "No BTC accounts found"
| _ ->
allAccounts |> Seq.iteri (fun i account ->
if account.Currency = currency then
let balance, maybeUsdValue =
UserInteraction.GetAccountBalance account
|> Async.RunSynchronously
UserInteraction.DisplayAccountStatus (i + 1) account balance maybeUsdValue
|> Seq.iter Console.WriteLine
)
let deleteImportedAccountFile() =
Config.RemoveArchivedAccount importedAccount

Console.Write("Write the account number (or 0 to cancel): ")
let accountNumber = Console.ReadLine()
match Int32.TryParse(accountNumber) with
| false, _ -> chooseAccount()
| true, 0 -> None
| true, accountParsed ->
let theAccountChosen =
try
let selectedAccount = allAccounts.[accountParsed - 1]
if selectedAccount.Currency = BTC then
Some selectedAccount
else
chooseAccount()
with
| _ -> chooseAccount()
theAccountChosen

match chooseAccount() with
| Some targetAccount ->
let destination = targetAccount.PublicAddress
let transferAmount = TransferAmount(balance, balance, currency) // send all funds
let maybeFee = UserInteraction.AskFee importedAccount transferAmount destination
match maybeFee with
| None -> ()
| Some(_fee) ->
let txId = importedAccount.SendFunds targetAccount transferAmount |> Async.RunSynchronously
let uri = BlockExplorer.GetTransaction currency txId
printfn "Transaction successful:\n%s" (uri.ToString())

Console.WriteLine "Archiving imported account..."
Account.ArchiveImportedAccount importedAccount
Console.WriteLine "Account archived."

UserInteraction.PressAnyKeyToContinue()
| None -> ()
try
let maybeTotalBalance, maybeUsdValue = UserInteraction.GetAccountBalance importedAccount |> Async.RunSynchronously
match maybeTotalBalance with
| NotFresh _ ->
Console.WriteLine "Could not retrieve balance"
deleteImportedAccountFile()
UserInteraction.PressAnyKeyToContinue()
| Fresh 0.0m ->
Console.WriteLine "Balance on imported account is zero. No funds to transfer."
deleteImportedAccountFile()
UserInteraction.PressAnyKeyToContinue()
| Fresh balance ->
printfn
"Balance on imported account: %s BTC (%s)"
(balance.ToString())
(UserInteraction.BalanceInUsdString balance maybeUsdValue)

let rec chooseAccount() =
Console.WriteLine "Choose account to send funds to:"
Console.WriteLine()
let allAccounts = Account.GetAllActiveAccounts() |> Seq.toList
let btcAccounts = allAccounts |> List.filter (fun acc -> acc.Currency = currency)

match btcAccounts with
| [ singleAccount ] -> Some singleAccount
| [] -> failwith "No BTC accounts found"
| _ ->
allAccounts |> Seq.iteri (fun i account ->
if account.Currency = currency then
let balance, maybeUsdValue =
UserInteraction.GetAccountBalance account
|> Async.RunSynchronously
UserInteraction.DisplayAccountStatus (i + 1) account balance maybeUsdValue
|> Seq.iter Console.WriteLine
)

Console.Write("Write the account number (or 0 to cancel): ")
let accountNumber = Console.ReadLine()
match Int32.TryParse(accountNumber) with
| false, _ -> chooseAccount()
| true, 0 -> None
| true, accountParsed ->
let theAccountChosen =
try
let selectedAccount = allAccounts.[accountParsed - 1]
if selectedAccount.Currency = BTC then
Some selectedAccount
else
chooseAccount()
with
| _ -> chooseAccount()
theAccountChosen

match chooseAccount() with
| Some targetAccount ->
let destination = targetAccount.PublicAddress
let transferAmount = TransferAmount(balance, balance, currency) // send all funds
let maybeFee = UserInteraction.AskFee importedAccount transferAmount destination
match maybeFee with
| None -> ()
| Some(fee) ->
let txId =
Account.SweepArchivedFunds
importedAccount
balance
targetAccount
fee
false
|> Async.RunSynchronously
let uri = BlockExplorer.GetTransaction currency txId
printfn "Transaction successful:\n%s" (uri.ToString())
UserInteraction.PressAnyKeyToContinue()
| None ->
deleteImportedAccountFile()
with
| _ ->
deleteImportedAccountFile()
reraise()

let WalletOptions(): unit =
let rec AskWalletOption(): GenericWalletOption =
Expand Down

0 comments on commit 33f52b0

Please sign in to comment.