Skip to content

Commit

Permalink
refactor: ledger store
Browse files Browse the repository at this point in the history
  • Loading branch information
alter-eggo authored and kyranjamie committed Nov 2, 2023
1 parent 19eee1c commit d3d86cc
Show file tree
Hide file tree
Showing 32 changed files with 114 additions and 67 deletions.
8 changes: 6 additions & 2 deletions src/app/common/hooks/use-key-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import { useAppDispatch } from '@app/store';
import { createNewAccount, stxChainActions } from '@app/store/chains/stx-chain.actions';
import { useBitcoinClient, useStacksClientAnchored } from '@app/store/common/api-clients.hooks';
import { inMemoryKeyActions } from '@app/store/in-memory-key/in-memory-key.actions';
import { keyActions } from '@app/store/keys/key.actions';
import { useCurrentKeyDetails } from '@app/store/keys/key.selectors';
import { bitcoinKeysSlice } from '@app/store/ledger/bitcoin/bitcoin-key.slice';
import { stacksKeysSlice } from '@app/store/ledger/stacks/stacks-key.slice';
import { clearWalletSession } from '@app/store/session-restore';
import { keyActions } from '@app/store/software-keys/software-key.actions';
import { useCurrentKeyDetails } from '@app/store/software-keys/software-key.selectors';

import { useAnalytics } from './analytics/use-analytics';

Expand Down Expand Up @@ -54,6 +56,8 @@ export function useKeyActions() {
async signOut() {
await clearWalletSession();
dispatch(keyActions.signOut());
dispatch(bitcoinKeysSlice.actions.signOut());
dispatch(stacksKeysSlice.actions.signOut());
await clearChromeStorage();
partiallyClearLocalStorage();
void analytics.track('sign_out');
Expand Down
34 changes: 19 additions & 15 deletions src/app/common/use-wallet-type.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useMemo } from 'react';

// eslint-disable-next-line no-restricted-imports
import { isUndefined } from '@shared/utils';
import { useHasLedgerKeys } from '@app/store/ledger/ledger.selectors';
import { useCurrentKeyDetails } from '@app/store/software-keys/software-key.selectors';

import { useHasBitcoinLedgerKeychain } from '@app/store/accounts/blockchain/bitcoin/bitcoin.ledger';
import { useCurrentKeyDetails } from '@app/store/keys/key.selectors';

type WalletType = 'ledger' | 'software';
enum WalletType {
Ledger = 'ledger',
Software = 'software',
}

function isLedgerWallet(walletType: WalletType) {
return walletType === 'ledger';
Expand All @@ -20,27 +20,31 @@ type WalletTypeMap<T> = Record<WalletType, T>;

function whenWallet(walletType: WalletType) {
return <T extends WalletTypeMap<unknown>>(walletTypeMap: T) => {
if (isLedgerWallet(walletType)) return walletTypeMap.ledger as T['ledger'];
if (isSoftwareWallet(walletType)) return walletTypeMap.software as T['software'];
if (isLedgerWallet(walletType)) return walletTypeMap.ledger as T[WalletType.Ledger];
if (isSoftwareWallet(walletType)) return walletTypeMap.software as T[WalletType.Software];
throw new Error('Wallet is neither of type `ledger` nor `software`');
};
}

export function useWalletType() {
const wallet = useCurrentKeyDetails();
const hasBitcoinLedgerKeychain = useHasBitcoinLedgerKeychain();
let walletType = wallet?.type;
const isLedger = useHasLedgerKeys();

if (isUndefined(walletType) && hasBitcoinLedgerKeychain) {
walletType = 'ledger';
// Any type here allows use within app without handling undefined
// case will error when use within onboarding
let walletType: any;

if (wallet?.encryptedSecretKey) {
walletType = WalletType.Software;
}
if (isLedger) {
walletType = WalletType.Ledger;
}

return useMemo(
() => ({
walletType,
// Coercing type here allows use within app without handling undefined
// case will error when use within onboarding
whenWallet: whenWallet(walletType as any),
whenWallet: whenWallet(walletType),
}),
[walletType]
);
Expand Down
10 changes: 6 additions & 4 deletions src/app/features/asset-list/asset-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { CurrentStacksAccountLoader } from '@app/components/stacks-account-loade
import { useHasBitcoinLedgerKeychain } from '@app/store/accounts/blockchain/bitcoin/bitcoin.ledger';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { useHasStacksKeychain } from '@app/store/accounts/blockchain/stacks/stacks.hooks';
import { useHasStacksLedgerKeychain } from '@app/store/accounts/blockchain/stacks/stacks.hooks';
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';

import { Collectibles } from '../collectibles/collectibles';
Expand All @@ -27,8 +27,8 @@ import { ConnectLedgerAssetBtn } from './components/connect-ledger-asset-button'
import { StacksBalanceItem } from './components/stacks-balance-item';

export function AssetsList() {
const hasStacksKeys = useHasStacksKeychain();
const hasBitcoinKeys = useHasBitcoinLedgerKeychain();
const hasStacksKeys = useHasStacksLedgerKeychain();
const hasBitcoinLedgerKeys = useHasBitcoinLedgerKeychain();
const btcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const network = useCurrentNetwork();
const currentAccount = useCurrentStacksAccount();
Expand Down Expand Up @@ -61,7 +61,9 @@ export function AssetsList() {
usdBalance={btcAvailableUsdBalance}
icon={<BtcIcon />}
address={btcAddress}
rightElement={hasBitcoinKeys ? undefined : <ConnectLedgerAssetBtn chain="bitcoin" />}
rightElement={
hasBitcoinLedgerKeys ? undefined : <ConnectLedgerAssetBtn chain="bitcoin" />
}
/>
) : null,
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ function LedgerRequestBitcoinKeys() {
},
});
dispatch(bitcoinKeysSlice.actions.addKeys(keys));
const targetId = latestDeviceResponse?.targetId;

if (targetId) {
dispatch(
bitcoinKeysSlice.actions.addTargetId({
targetId,
})
);
}
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
isStacksLedgerAppClosed,
useActionCancellableByUser,
} from '@app/features/ledger/utils/stacks-ledger-utils';
import { stacksKeysSlice } from '@app/store/ledger/bitcoin/stacks-key.slice';
import { stacksKeysSlice } from '@app/store/ledger/stacks/stacks-key.slice';

import { ledgerRequestKeysRoutes } from '../../generic-flows/request-keys/ledger-request-keys-route-generator';
import { RequestKeysFlow } from '../../generic-flows/request-keys/request-keys-flow';
Expand Down Expand Up @@ -57,6 +57,15 @@ function LedgerRequestStacksKeys() {
}))
)
);
const targetId = latestDeviceResponse?.targetId;

if (targetId) {
dispatch(
stacksKeysSlice.actions.addTargetId({
targetId,
})
);
}
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { ExternalLink } from '@app/components/external-link';
import { BtcLedgerIcon } from '@app/components/icons/btc-ledger-icon';
import { StxLedgerIcon } from '@app/components/icons/stx-ledger-icon';
import { Divider } from '@app/components/layout/divider';
import { useHasBitcoinKeychain } from '@app/store/accounts/blockchain/bitcoin/bitcoin.hooks';
import { useHasBitcoinLedgerKeychain } from '@app/store/accounts/blockchain/bitcoin/bitcoin.ledger';

import { LedgerWrapper } from '../../components/ledger-wrapper';

Expand All @@ -38,7 +38,7 @@ export function ConnectLedgerLayout(props: ConnectLedgerLayoutProps) {
showInstructions,
awaitingLedgerConnection,
} = props;
const hasBitcoinAccount = useHasBitcoinKeychain();
const hasBitcoinAccount = useHasBitcoinLedgerKeychain();

const showBitcoinConnectButton = useMemo(() => {
return LEDGER_BITCOIN_ENABLED && !hasBitcoinAccount;
Expand Down
10 changes: 6 additions & 4 deletions src/app/features/settings-dropdown/settings-dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { openInNewTab, openIndexPageInNewTab } from '@app/common/utils/open-in-n
import { Divider } from '@app/components/layout/divider';
import { Caption } from '@app/components/typography';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { useCurrentKeyDetails } from '@app/store/keys/key.selectors';
import { useHasLedgerKeys, useLedgerDeviceTargetId } from '@app/store/ledger/ledger.selectors';
import { useCurrentNetworkId } from '@app/store/networks/networks.selectors';

import { extractDeviceNameFromKnownTargetIds } from '../ledger/utils/generic-ledger-utils';
Expand All @@ -37,7 +37,8 @@ export function SettingsDropdown() {
const navigate = useNavigate();
const analytics = useAnalytics();
const { walletType } = useWalletType();
const key = useCurrentKeyDetails();
const targetId = useLedgerDeviceTargetId();

const { isPressed: showAdvancedMenuOptions } = useModifierKey('alt', 120);
const location = useLocation();

Expand All @@ -52,6 +53,7 @@ export function SettingsDropdown() {
);

const isShowing = isShowingSettings;
const isLedger = useHasLedgerKeys();

useOnClickOutside(ref, isShowing ? handleClose : null);

Expand All @@ -63,8 +65,8 @@ export function SettingsDropdown() {
<SlideFade initialOffset="-20px" timeout={150} in={isShowing}>
{styles => (
<MenuWrapper ref={ref} style={styles} pointerEvents={!isShowing ? 'none' : 'all'}>
{key && key.type === 'ledger' && (
<LedgerDeviceItemRow deviceType={extractDeviceNameFromKnownTargetIds(key.targetId)} />
{isLedger && targetId && (
<LedgerDeviceItemRow deviceType={extractDeviceNameFromKnownTargetIds(targetId)} />
)}
{hasGeneratedWallet && walletType === 'software' && (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useWalletType } from '@app/common/use-wallet-type';
import { Brc20TokensLoader } from '@app/components/brc20-tokens-loader';
import { ModalHeader } from '@app/components/modal-header';
import { useHasCurrentBitcoinAccount } from '@app/store/accounts/blockchain/bitcoin/bitcoin.hooks';
import { useHasStacksKeychain } from '@app/store/accounts/blockchain/stacks/stacks.hooks';
import { useHasStacksLedgerKeychain } from '@app/store/accounts/blockchain/stacks/stacks.hooks';

import { Brc20TokenAssetList } from '../../../components/crypto-assets/bitcoin/brc20-token-asset-list/brc20-token-asset-list';
import { ChooseCryptoAssetLayout } from './components/choose-crypto-asset.layout';
Expand All @@ -17,7 +17,7 @@ export function ChooseCryptoAsset() {

const { whenWallet } = useWalletType();
const hasBitcoinLedgerKeys = useHasCurrentBitcoinAccount();
const hasStacksLedgerKeys = useHasStacksKeychain();
const hasStacksLedgerKeys = useHasStacksLedgerKeychain();

const chechKeychainAvailable = useCallback(
(symbol: string) => {
Expand Down
9 changes: 5 additions & 4 deletions src/app/routes/account-gate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { Navigate } from 'react-router-dom';

import { RouteUrls } from '@shared/route-urls';

import { useHasBitcoinLedgerKeychain } from '@app/store/accounts/blockchain/bitcoin/bitcoin.ledger';
import { useDefaultWalletSecretKey } from '@app/store/in-memory-key/in-memory-key.selectors';
import { useCurrentKeyDetails } from '@app/store/keys/key.selectors';
import { useHasLedgerKeys } from '@app/store/ledger/ledger.selectors';
import { useCurrentKeyDetails } from '@app/store/software-keys/software-key.selectors';

export function shouldNavigateToOnboardingStartPage(currentKeyDetails?: any) {
return !currentKeyDetails;
Expand All @@ -21,8 +21,9 @@ interface AccountGateProps {
export function AccountGate({ children }: AccountGateProps) {
const currentKeyDetails = useCurrentKeyDetails();
const currentInMemorySecretKey = useDefaultWalletSecretKey();
const hasBitcoinKeychain = useHasBitcoinLedgerKeychain();
if (currentKeyDetails?.type === 'ledger' || hasBitcoinKeychain) return <>{children}</>;

const isLedger = useHasLedgerKeys();
if (isLedger) return <>{children}</>;

if (shouldNavigateToOnboardingStartPage(currentKeyDetails))
return <Navigate to={RouteUrls.Onboarding} />;
Expand Down
2 changes: 1 addition & 1 deletion src/app/routes/hooks/use-on-sign-out.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useOnMount } from '@app/common/hooks/use-on-mount';
import { keyActions } from '@app/store/keys/key.actions';
import { keyActions } from '@app/store/software-keys/software-key.actions';

export function useOnSignOut(handler: () => void) {
useOnMount(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/app/routes/onboarding-gate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Navigate } from 'react-router-dom';
import { RouteUrls } from '@shared/route-urls';

import { useDefaultWalletSecretKey } from '@app/store/in-memory-key/in-memory-key.selectors';
import { useCurrentKeyDetails } from '@app/store/keys/key.selectors';
import { useCurrentKeyDetails } from '@app/store/software-keys/software-key.selectors';

function hasAlreadyMadeWalletAndPlaintextKeyInMemory(encryptedKey?: string, inMemoryKey?: string) {
return !!encryptedKey && !!inMemoryKey;
Expand Down
2 changes: 1 addition & 1 deletion src/app/store/accounts/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useSelector } from 'react-redux';

import { atom, useAtom } from 'jotai';

import { selectCurrentAccountIndex } from '../keys/key.selectors';
import { selectCurrentAccountIndex } from '../software-keys/software-key.selectors';

// This is only used when there is a pending transaction request and
// the user switches accounts during the signing process
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import {

import { useWalletType } from '@app/common/use-wallet-type';
import { selectRootKeychain } from '@app/store/in-memory-key/in-memory-key.selectors';
import { selectDefaultSoftwareKey } from '@app/store/keys/key.selectors';
import { selectDefaultWalletBitcoinKeyEntities } from '@app/store/ledger/bitcoin/bitcoin-key.slice';
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
import { selectDefaultSoftwareKey } from '@app/store/software-keys/software-key.selectors';

// This factory selector extends from the wallet root keychain to derive child
// keychains. It accepts a curried fn that takes a keychain and returns a fn
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useSelector } from 'react-redux';

import { selectDefaultWalletBitcoinKeyEntities } from '@app/store/ledger/bitcoin-key.slice';
import { selectDefaultWalletBitcoinKeyEntities } from '@app/store/ledger/bitcoin/bitcoin-key.slice';

export function useHasBitcoinLedgerKeychain() {
const bitcoinEntities = useSelector(selectDefaultWalletBitcoinKeyEntities);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import {
} from '@shared/crypto/bitcoin/p2wpkh-address-gen';

import { mnemonicToRootNode } from '@app/common/keychain/keychain';
import { selectCurrentAccountIndex } from '@app/store/keys/key.selectors';
import { selectCurrentNetwork } from '@app/store/networks/networks.selectors';
import { selectCurrentAccountIndex } from '@app/store/software-keys/software-key.selectors';

import { useCurrentAccountIndex } from '../../account';
import {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {
getTaprootPaymentFromAddressIndex,
} from '@shared/crypto/bitcoin/p2tr-address-gen';

import { selectCurrentAccountIndex } from '@app/store/keys/key.selectors';
import { selectCurrentNetwork, useCurrentNetwork } from '@app/store/networks/networks.selectors';
import { selectCurrentAccountIndex } from '@app/store/software-keys/software-key.selectors';

import { useCurrentAccountIndex } from '../../account';
import {
Expand Down
9 changes: 7 additions & 2 deletions src/app/store/accounts/blockchain/stacks/stacks-accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
selectDefaultWalletKey,
selectRootKeychain,
} from '@app/store/in-memory-key/in-memory-key.selectors';
import { selectDefaultWalletStacksKeys } from '@app/store/ledger/bitcoin/stacks-key.slice';
import { selectDefaultWalletStacksKeys } from '@app/store/ledger/stacks/stacks-key.slice';
import { currentNetworkAtom } from '@app/store/networks/networks';

import {
Expand Down Expand Up @@ -116,7 +116,12 @@ const ledgerAccountsState = atom<HardwareStacksAccount[] | undefined>(get => {
export const stacksAccountState = atom<StacksAccount[]>(get => {
const ledgerAccounts = get(ledgerAccountsState);
const softwareAccounts = get(softwareAccountsState);
return ledgerAccounts ?? softwareAccounts ?? [];

if (ledgerAccounts?.length) {
return ledgerAccounts;
}

return softwareAccounts ?? [];
});

/**
Expand Down
4 changes: 2 additions & 2 deletions src/app/store/accounts/blockchain/stacks/stacks.hooks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { store } from '@app/store';

export function useHasStacksKeychain() {
return Object.keys(store.getState().keys.entities).length > 0;
export function useHasStacksLedgerKeychain() {
return Object.keys(store.getState().ledger.stacks.entities).length > 0;
}
2 changes: 1 addition & 1 deletion src/app/store/chains/stx-chain.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { PayloadAction, createSlice } from '@reduxjs/toolkit';

import { defaultWalletKeyId } from '@shared/utils';

import { keySlice } from '../keys/key.slice';
import { keySlice } from '../software-keys/software-key.slice';

interface StxChainKeyState {
highestAccountIndex: number;
Expand Down
2 changes: 1 addition & 1 deletion src/app/store/in-memory-key/in-memory-key.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PayloadAction, createSlice } from '@reduxjs/toolkit';
import { logger } from '@shared/logger';
import { defaultWalletKeyId } from '@shared/utils';

import { keySlice } from '../keys/key.slice';
import { keySlice } from '../software-keys/software-key.slice';

interface InMemoryKeyState {
hasRestoredKeys: boolean;
Expand Down
8 changes: 4 additions & 4 deletions src/app/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ import { analyticsSlice } from './analytics/analytics.slice';
import { appPermissionsSlice } from './app-permissions/app-permissions.slice';
import { stxChainSlice } from './chains/stx-chain.slice';
import { inMemoryKeySlice } from './in-memory-key/in-memory-key.slice';
import { keySlice } from './keys/key.slice';
import { bitcoinKeysSlice } from './ledger/bitcoin/bitcoin-key.slice';
import { stacksKeysSlice } from './ledger/bitcoin/stacks-key.slice';
import { stacksKeysSlice } from './ledger/stacks/stacks-key.slice';
import { networksSlice } from './networks/networks.slice';
import { ordinalsSlice } from './ordinals/ordinals.slice';
import { settingsSlice } from './settings/settings.slice';
import { keySlice } from './software-keys/software-key.slice';
import { submittedTransactionsSlice } from './submitted-transactions/submitted-transactions.slice';
import { broadcastActionTypeToOtherFramesMiddleware } from './utils/broadcast-action-types';

Expand All @@ -42,7 +42,7 @@ export interface RootState {
};
ordinals: ReturnType<typeof ordinalsSlice.reducer>;
inMemoryKeys: ReturnType<typeof inMemoryKeySlice.reducer>;
keys: ReturnType<typeof keySlice.reducer>;
'software-keys': ReturnType<typeof keySlice.reducer>;
networks: ReturnType<typeof networksSlice.reducer>;
submittedTransactions: ReturnType<typeof submittedTransactionsSlice.reducer>;
settings: ReturnType<typeof settingsSlice.reducer>;
Expand All @@ -60,7 +60,7 @@ const appReducer = combineReducers({
}),
ordinals: ordinalsSlice.reducer,
inMemoryKeys: inMemoryKeySlice.reducer,
keys: keySlice.reducer,
'software-keys': keySlice.reducer,
networks: networksSlice.reducer,
submittedTransactions: submittedTransactionsSlice.reducer,
settings: settingsSlice.reducer,
Expand Down
Loading

0 comments on commit d3d86cc

Please sign in to comment.