Skip to content
This repository has been archived by the owner on Oct 10, 2023. It is now read-only.

Rename (keystore) account{s} to wallet{s} #2349

Merged
merged 2 commits into from
Aug 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 39 additions & 39 deletions src/main/api/keystore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as FP from 'fp-ts/lib/function'
import * as TE from 'fp-ts/lib/TaskEither'
import * as fs from 'fs-extra'

import { KeystoreAccounts, ipcKeystoreAccountsIO, keystoreIO } from '../../shared/api/io'
import { KeystoreWallets, ipcKeystoreWalletsIO, keystoreIO } from '../../shared/api/io'
import { ApiKeystore, IPCExportKeystoreParams } from '../../shared/api/types'
import { mapIOErrors } from '../../shared/utils/fp'
import { defaultWalletName } from '../../shared/utils/wallet'
Expand All @@ -17,7 +17,7 @@ import { STORAGE_DIR } from './const'
export const LEGACY_KEYSTORE_ID = 1
const LEGACY_KEYSTORE_FILE = path.join(STORAGE_DIR, `keystore.json`)

const ACCOUNTS_STORAGE_FILE = path.join(STORAGE_DIR, `accounts.json`)
const WALLETS_STORAGE_FILE = path.join(STORAGE_DIR, `wallets.json`)

/**
* Exports existing keystore to let an user save it anywhere
Expand Down Expand Up @@ -46,7 +46,7 @@ export const loadKeystore = async () => {
}
}

const migrateLegacyAccount = (): TE.TaskEither<Error, KeystoreAccounts> =>
const migrateLegacyWallet = (): TE.TaskEither<Error, KeystoreWallets> =>
FP.pipe(
exists(LEGACY_KEYSTORE_FILE),
// Switch to error if file does not exists
Expand All @@ -58,7 +58,7 @@ const migrateLegacyAccount = (): TE.TaskEither<Error, KeystoreAccounts> =>
TE.chain(() => readJSON(LEGACY_KEYSTORE_FILE)),
// decode keystore content
TE.chain(FP.flow(keystoreIO.decode, E.mapLeft(mapIOErrors), TE.fromEither)),
// create legacy account
// create legacy wallet
TE.map((keystore) => [
{
id: LEGACY_KEYSTORE_ID,
Expand All @@ -67,74 +67,74 @@ const migrateLegacyAccount = (): TE.TaskEither<Error, KeystoreAccounts> =>
keystore
}
]),
TE.chain((accounts) =>
TE.chain((wallets) =>
FP.pipe(
// rename keystore file to backup it
renameFile(LEGACY_KEYSTORE_FILE, path.join(STORAGE_DIR, `keystore-legacy-${new Date().getTime()}.json`)),
// return accounts in case of successfull backup
TE.map(() => accounts)
// return wallets in case of successfull backup
TE.map(() => wallets)
)
)
)

const loadAccounts: TE.TaskEither<Error, KeystoreAccounts> = FP.pipe(
const loadWallets: TE.TaskEither<Error, KeystoreWallets> = FP.pipe(
TE.tryCatch(
async () => {
const exists = await fs.pathExists(ACCOUNTS_STORAGE_FILE)
// empty list of accounts if `accounts.json` does not exist
return exists ? fs.readJSON(ACCOUNTS_STORAGE_FILE) : []
const exists = await fs.pathExists(WALLETS_STORAGE_FILE)
// empty list of wallets if `wallets.json` does not exist
return exists ? fs.readJSON(WALLETS_STORAGE_FILE) : []
},
(e: unknown) => Error(`${e}`)
),
TE.chain(FP.flow(ipcKeystoreAccountsIO.decode, E.mapLeft(mapIOErrors), TE.fromEither))
TE.chain(FP.flow(ipcKeystoreWalletsIO.decode, E.mapLeft(mapIOErrors), TE.fromEither))
)

/**
* Saves keystore accounts
* It returns a list of accounts
* Saves keystore wallets
* It returns a list of wallets
*/
export const saveKeystoreAccounts = (accounts: KeystoreAccounts): TE.TaskEither<Error, KeystoreAccounts> =>
// 1. encode accounts
FP.pipe(accounts, ipcKeystoreAccountsIO.encode, (accountsEncoded) =>
export const saveKeystoreWallets = (wallets: KeystoreWallets): TE.TaskEither<Error, KeystoreWallets> =>
// 1. encode wallets
FP.pipe(wallets, ipcKeystoreWalletsIO.encode, (walletsEncoded) =>
FP.pipe(
// 2. save accounts to disk
writeJSON(`${ACCOUNTS_STORAGE_FILE}`, accountsEncoded),
// return accounts
TE.map((_) => accounts)
// 2. save wallets to disk
writeJSON(`${WALLETS_STORAGE_FILE}`, walletsEncoded),
// return wallets
TE.map((_) => wallets)
)
)

/**
* Initializes keystore accounts to migrate legacy keystore.json (if needed)
* Initializes keystore wallets to migrate legacy keystore.json (if needed)
*
* It does the following:
* 1. Load accounts (if available)
* 2. Merge legacy keystore (if available and if no accounts)
* 3. Save updated accounts to disk
* 1. Load wallets (if available)
* 2. Merge legacy keystore (if available and if no wallets)
* 3. Save updated wallets to disk
*/
export const initKeystoreAccounts: TE.TaskEither<Error, KeystoreAccounts> = FP.pipe(
loadAccounts,
TE.chain((accounts) => {
// If we have already stored accounts,
export const initKeystoreWallets: TE.TaskEither<Error, KeystoreWallets> = FP.pipe(
loadWallets,
TE.chain((wallets) => {
// If we have already stored wallets,
// another migration is not needed anymore.
if (accounts.length) return TE.right(accounts)
if (wallets.length) return TE.right(wallets)

// In other case (no previous migration | no accounts)
// Try to migrate legacy account and save accounts
// In other case (no previous migration | no wallets)
// Try to migrate legacy wallet and save wallets
return FP.pipe(
migrateLegacyAccount(),
migrateLegacyWallet(),
// Ignore any legacy keystore errors, but return empty list
TE.alt(() => TE.right<Error, KeystoreAccounts>([])),
// save accounts to disk
TE.chain(saveKeystoreAccounts)
TE.alt(() => TE.right<Error, KeystoreWallets>([])),
// save wallets to disk
TE.chain(saveKeystoreWallets)
)
})
)

export const apiKeystore: ApiKeystore = {
// Note: `params` need to be encoded by `ipcKeystoreAccountsIO` before calling `saveKeystoreAccounts` */
saveKeystoreAccounts: (params: unknown) => ipcRenderer.invoke(IPCMessages.SAVE_KEYSTORE_ACCOUNTS, params),
// Note: `params` need to be encoded by `ipcKeystoreWalletsIO` before calling `saveKeystoreWallets` */
saveKeystoreWallets: (params: unknown) => ipcRenderer.invoke(IPCMessages.SAVE_KEYSTORE_WALLETS, params),
exportKeystore: (params: IPCExportKeystoreParams) => ipcRenderer.invoke(IPCMessages.EXPORT_KEYSTORE, params),
load: () => ipcRenderer.invoke(IPCMessages.LOAD_KEYSTORE),
initKeystoreAccounts: () => ipcRenderer.invoke(IPCMessages.INIT_KEYSTORE_ACCOUNTS)
initKeystoreWallets: () => ipcRenderer.invoke(IPCMessages.INIT_KEYSTORE_WALLETS)
}
12 changes: 6 additions & 6 deletions src/main/electron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as E from 'fp-ts/lib/Either'
import * as FP from 'fp-ts/lib/function'

import {
ipcKeystoreAccountsIO,
ipcKeystoreWalletsIO,
ipcLedgerApproveERC20TokenParamsIO,
ipcLedgerDepositTxParamsIO,
ipcLedgerSendTxParamsIO
Expand All @@ -20,7 +20,7 @@ import { DEFAULT_STORAGES } from '../shared/const'
import type { Locale } from '../shared/i18n/types'
import { registerAppCheckUpdatedHandler } from './api/appUpdate'
import { getFileStoreService } from './api/fileStore'
import { exportKeystore, initKeystoreAccounts, loadKeystore, saveKeystoreAccounts } from './api/keystore'
import { exportKeystore, initKeystoreWallets, loadKeystore, saveKeystoreWallets } from './api/keystore'
import {
getAddress as getLedgerAddress,
sendTx as sendLedgerTx,
Expand Down Expand Up @@ -140,19 +140,19 @@ const initIPC = () => {
// Lang
ipcMain.on(IPCMessages.UPDATE_LANG, (_, locale: Locale) => langChangeHandler(locale))
// Keystore
ipcMain.handle(IPCMessages.SAVE_KEYSTORE_ACCOUNTS, async (_, params: unknown) => {
ipcMain.handle(IPCMessages.SAVE_KEYSTORE_WALLETS, async (_, params: unknown) => {
return FP.pipe(
// params need to be decoded
ipcKeystoreAccountsIO.decode(params),
ipcKeystoreWalletsIO.decode(params),
E.fold(
(e) => Promise.reject(e),
(accounts) => saveKeystoreAccounts(accounts)()
(wallets) => saveKeystoreWallets(wallets)()
)
)
})
ipcMain.handle(IPCMessages.EXPORT_KEYSTORE, async (_, params: IPCExportKeystoreParams) => exportKeystore(params))
ipcMain.handle(IPCMessages.LOAD_KEYSTORE, async () => loadKeystore())
ipcMain.handle(IPCMessages.INIT_KEYSTORE_ACCOUNTS, async () => initKeystoreAccounts())
ipcMain.handle(IPCMessages.INIT_KEYSTORE_WALLETS, async () => initKeystoreWallets())
// Ledger
ipcMain.handle(IPCMessages.GET_LEDGER_ADDRESS, async (_, params: IPCLedgerAdddressParams) => getLedgerAddress(params))
ipcMain.handle(IPCMessages.VERIFY_LEDGER_ADDRESS, async (_, params: IPCLedgerAdddressParams) =>
Expand Down
4 changes: 2 additions & 2 deletions src/main/ipc/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ enum IPCMessages {
UPDATE_LANG = 'UPDATE_LANG',
// keystore
LOAD_KEYSTORE = 'LOAD_KEYSTORE',
SAVE_KEYSTORE_ACCOUNTS = 'SAVE_KEYSTORE_ACCOUNTS',
SAVE_KEYSTORE_WALLETS = 'SAVE_KEYSTORE_WALLETS',
EXPORT_KEYSTORE = 'EXPORT_KEYSTORE',
INIT_KEYSTORE_ACCOUNTS = 'INIT_KEYSTORE_ACCOUNTS',
INIT_KEYSTORE_WALLETS = 'INIT_KEYSTORE_WALLETS',
// Ledger
GET_LEDGER_ADDRESS = 'GET_LEDGER_ADDRESS',
VERIFY_LEDGER_ADDRESS = 'VERIFY_LEDGER_ADDRESS',
Expand Down
22 changes: 11 additions & 11 deletions src/renderer/components/settings/WalletSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ import { isEnabledWallet } from '../../helpers/walletHelper'
import * as appRoutes from '../../routes/app'
import * as walletRoutes from '../../routes/wallet'
import {
KeystoreAccountsUI,
KeystoreWalletsUI,
KeystoreState,
RemoveAccountHandler,
RemoveKeystoreWalletHandler,
ValidatePasswordHandler,
WalletAccounts,
WalletAddressAsync
Expand All @@ -72,13 +72,13 @@ type Props = {
network: Network
walletAccounts: O.Option<WalletAccounts>
lockWallet: FP.Lazy<void>
removeKeystore: RemoveAccountHandler
removeKeystore: RemoveKeystoreWalletHandler
exportKeystore: () => Promise<void>
addLedgerAddress: (chain: Chain, walletIndex: number) => void
verifyLedgerAddress: (chain: Chain, walletIndex: number) => Promise<boolean>
removeLedgerAddress: (chain: Chain) => void
keystore: KeystoreState
keystoreAccounts: KeystoreAccountsUI
keystoreWallets: KeystoreWalletsUI
clickAddressLinkHandler: (chain: Chain, address: Address) => void
validatePassword$: ValidatePasswordHandler
collapsed: boolean
Expand All @@ -100,7 +100,7 @@ export const WalletSettings: React.FC<Props> = (props): JSX.Element => {
verifyLedgerAddress,
removeLedgerAddress,
keystore,
keystoreAccounts,
keystoreWallets,
clickAddressLinkHandler,
validatePassword$,
collapsed,
Expand Down Expand Up @@ -138,12 +138,12 @@ export const WalletSettings: React.FC<Props> = (props): JSX.Element => {
const closeQrModal = useCallback(() => setShowQRModal(O.none), [setShowQRModal])

const removeWalletHandler = useCallback(async () => {
const noAccounts = await removeKeystore()
if (noAccounts >= 1) {
// goto unlock screen to unlock another account
const noWallets = await removeKeystore()
if (noWallets >= 1) {
// goto unlock screen to unlock another wallet
navigate(walletRoutes.locked.path())
} else {
// no accounts -> go to homepage
// no wallet -> go to homepage
navigate(appRoutes.base.template)
}
}, [removeKeystore, navigate])
Expand Down Expand Up @@ -495,7 +495,7 @@ export const WalletSettings: React.FC<Props> = (props): JSX.Element => {
<div className="card my-20px w-full ">
{/* TODO(@veado) Make wallet name editable */}
<p className="pt-20px text-center font-main text-18 uppercase text-text0 dark:text-text0d">{walletName}</p>
<div className="flex flex-col items-center p-20px md:flex-row">
<div className="flex flex-col items-center md:flex-row">
<div className="flex w-full justify-center md:w-1/2">
<TextButton
className="m-0 min-w-[200px] md:m-20px"
Expand Down Expand Up @@ -541,7 +541,7 @@ export const WalletSettings: React.FC<Props> = (props): JSX.Element => {
{intl.formatMessage({ id: 'wallet.add.another' })}
</FlatButton>
</div>
<div className="flex w-full justify-center md:w-1/2">accounts: {JSON.stringify(keystoreAccounts)}</div>
<div className="flex w-full justify-center md:w-1/2">accounts: {JSON.stringify(keystoreWallets)}</div>
</div>
</div>
<div key={'accounts'} className="w-full">
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/wallet/unlock/UnlockForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { getUrlSearchParam } from '../../../helpers/url.helper'
import * as appRoutes from '../../../routes/app'
import { ReferrerState } from '../../../routes/types'
import * as walletRoutes from '../../../routes/wallet'
import { KeystoreState, RemoveAccountHandler } from '../../../services/wallet/types'
import { KeystoreState, RemoveKeystoreWalletHandler } from '../../../services/wallet/types'
import { isLocked, getWalletName } from '../../../services/wallet/util'
import { RemoveWalletConfirmationModal } from '../../modal/confirmation/RemoveWalletConfirmationModal'
import { BackLink } from '../../uielements/backLink'
Expand All @@ -25,7 +25,7 @@ type FormData = {
export type Props = {
keystore: KeystoreState
unlock: (password: string) => Promise<void>
removeKeystore: RemoveAccountHandler
removeKeystore: RemoveKeystoreWalletHandler
}

export const UnlockForm: React.FC<Props> = (props): JSX.Element => {
Expand Down
21 changes: 0 additions & 21 deletions src/renderer/hooks/useKeystoreAccounts.ts

This file was deleted.

6 changes: 3 additions & 3 deletions src/renderer/hooks/useKeystoreState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ import * as RxOp from 'rxjs/operators'

import { useWalletContext } from '../contexts/WalletContext'
import { INITIAL_KEYSTORE_STATE } from '../services/wallet/const'
import { KeystoreState, Phrase, RemoveAccountHandler } from '../services/wallet/types'
import { KeystoreState, Phrase, RemoveKeystoreWalletHandler } from '../services/wallet/types'
import { getPhrase, getWalletName } from '../services/wallet/util'

export const useKeystoreState = (): {
state: KeystoreState
phrase: O.Option<Phrase>
walletName: O.Option<string>
remove: RemoveAccountHandler
remove: RemoveKeystoreWalletHandler
unlock: (password: string) => Promise<void>
lock: FP.Lazy<void>
} => {
const {
keystoreService: { keystore$, unlock, lock, removeKeystoreAccount: remove }
keystoreService: { keystore$, unlock, lock, removeKeystoreWallet: remove }
} = useWalletContext()

const state = useObservableState(keystore$, INITIAL_KEYSTORE_STATE)
Expand Down
21 changes: 21 additions & 0 deletions src/renderer/hooks/useKeystoreWallets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as RD from '@devexperts/remote-data-ts'
import * as FP from 'fp-ts/lib/function'
import { useObservableState } from 'observable-hooks'

import { useWalletContext } from '../contexts/WalletContext'
import { KeystoreWalletsRD, KeystoreWalletsUI } from '../services/wallet/types'

export const useKeystoreWallets = (): {
wallets: KeystoreWalletsRD
reload: FP.Lazy<void>
walletsUI: KeystoreWalletsUI
} => {
const {
keystoreService: { reloadKeystoreWallets: reload, keystoreWallets$, keystoreWalletsUI$ }
} = useWalletContext()

const wallets = useObservableState(keystoreWallets$, RD.initial)
const walletsUI = useObservableState(keystoreWalletsUI$, [])

return { wallets: wallets, walletsUI, reload }
}
4 changes: 2 additions & 2 deletions src/renderer/services/wallet/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { network$ } from '../app/service'
import { createBalancesService } from './balances'
import { setSelectedAsset, selectedAsset$, client$ } from './common'
import { keystoreService, removeKeystoreAccount } from './keystore'
import { keystoreService, removeKeystoreWallet } from './keystore'
import { createLedgerService } from './ledger'
import { getTxs$, loadTxs, explorerUrl$, resetTxsPage } from './transaction'

Expand All @@ -22,7 +22,7 @@ const { reloadBalances, reloadBalancesByChain, balancesState$, chainBalances$ }
export {
client$,
keystoreService,
removeKeystoreAccount as removeKeystore,
removeKeystoreWallet,
setSelectedAsset,
selectedAsset$,
loadTxs,
Expand Down
Loading