Skip to content

Commit

Permalink
Allow testnet ledger accounts (#688)
Browse files Browse the repository at this point in the history
* Allow testnet ledger accounts

* Fix merge issue

* Enable account switch on ledger

* pr review fix

* Fix ledger device account index

* Fix ledger filtering on select account screen

* fix ledger account ID derivation

---------

Co-authored-by: Den <[email protected]>
Co-authored-by: Tim Man <[email protected]>
  • Loading branch information
3 people authored Jan 11, 2024
1 parent 2f7a7dc commit 7898e48
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 27 deletions.
16 changes: 14 additions & 2 deletions src/app/hooks/useWalletReducer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getDeviceAccountIndex } from '@common/utils/ledger';
import { filterLedgerAccounts, getDeviceAccountIndex } from '@common/utils/ledger';
import useBtcWalletData from '@hooks/queries/useBtcWalletData';
import useStxWalletData from '@hooks/queries/useStxWalletData';
import useNetworkSelector from '@hooks/useNetwork';
Expand Down Expand Up @@ -85,7 +85,16 @@ const useWalletReducer = () => {
if (!selectedAccount) {
[selectedAccountData] = walletAccounts;
} else if (isLedgerAccount(selectedAccount)) {
selectedAccountData = ledgerAccountsList.find((a) => a.id === selectedAccount.id);
const networkLedgerAccounts = filterLedgerAccounts(ledgerAccountsList, currentNetwork.type);
const selectedAccountDataInNetwork = networkLedgerAccounts.find(
(a) => a.id === selectedAccount.id,
);

// we try find the specific matching ledger account
// If we can't find it, we default to the first ledger account in the selected network
// If we can't find that, we default to the first software account in the wallet
selectedAccountData =
selectedAccountDataInNetwork ?? networkLedgerAccounts[0] ?? walletAccounts[0];
} else {
selectedAccountData = walletAccounts.find((a) => a.id === selectedAccount.id);
}
Expand All @@ -106,6 +115,9 @@ const useWalletReducer = () => {

dispatch(fetchAccountAction(selectedAccountData, walletAccounts));

// ledger accounts initially didn't have a deviceAccountIndex
// this is a migration to add the deviceAccountIndex to the ledger accounts without them
// it should only fire once if ever
if (ledgerAccountsList.some((account) => account.deviceAccountIndex === undefined)) {
const newLedgerAccountsList = ledgerAccountsList.map((account) => ({
...account,
Expand Down
21 changes: 9 additions & 12 deletions src/app/screens/accountList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import ConnectLedger from '@assets/img/dashboard/connect_ledger.svg';
import Plus from '@assets/img/dashboard/plus.svg';
import { filterLedgerAccounts } from '@common/utils/ledger';
import AccountRow from '@components/accountRow';
import Separator from '@components/separator';
import TopRow from '@components/topRow';
Expand Down Expand Up @@ -85,10 +86,8 @@ function AccountList(): JSX.Element {
const { createAccount, switchAccount } = useWalletReducer();

const displayedAccountsList = useMemo(() => {
if (network.type === 'Mainnet') {
return [...ledgerAccountsList, ...accountsList];
}
return accountsList;
const networkLedgerAccounts = filterLedgerAccounts(ledgerAccountsList, network.type);
return [...networkLedgerAccounts, ...accountsList];
}, [accountsList, ledgerAccountsList, network]);

const handleAccountSelect = async (account: Account, goBack = true) => {
Expand Down Expand Up @@ -140,14 +139,12 @@ function AccountList(): JSX.Element {
</AddAccountContainer>
<AddAccountText>{t('NEW_ACCOUNT')}</AddAccountText>
</ButtonContainer>
{network.type === 'Mainnet' && (
<ButtonContainer onClick={onImportLedgerAccount}>
<AddAccountContainer>
<ButtonImage src={ConnectLedger} />
</AddAccountContainer>
<AddAccountText>{t('LEDGER_ACCOUNT')}</AddAccountText>
</ButtonContainer>
)}
<ButtonContainer onClick={onImportLedgerAccount}>
<AddAccountContainer>
<ButtonImage src={ConnectLedger} />
</AddAccountContainer>
<AddAccountText>{t('LEDGER_ACCOUNT')}</AddAccountText>
</ButtonContainer>
</ButtonsWrapper>
</Container>
);
Expand Down
5 changes: 4 additions & 1 deletion src/app/screens/btcSelectAddressScreen/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import OrdinalsIcon from '@assets/img/nftDashboard/white_ordinals_icon.svg';
import XverseLogo from '@assets/img/settings/logo.svg';
import DropDownIcon from '@assets/img/transactions/dropDownIcon.svg';
import DappPlaceholderIcon from '@assets/img/webInteractions/authPlaceholder.svg';
import { filterLedgerAccounts } from '@common/utils/ledger';
import AccountRow from '@components/accountRow';
import ActionButton from '@components/button';
import Separator from '@components/separator';
Expand Down Expand Up @@ -234,6 +235,8 @@ function BtcSelectAddressScreen() {
switchAccountBasedOnRequest();
}, []);

const networkLedgerAccounts = filterLedgerAccounts(ledgerAccountsList, network.type);

return (
<>
<LogoContainer>
Expand Down Expand Up @@ -262,7 +265,7 @@ function BtcSelectAddressScreen() {
</TitleContainer>
{showAccountList ? (
<AccountListContainer style={springProps}>
{[...ledgerAccountsList, ...accountsList].map((account) => (
{[...networkLedgerAccounts, ...accountsList].map((account) => (
<AccountListRow key={account.id}>
<AccountRow
key={account.stxAddress}
Expand Down
2 changes: 2 additions & 0 deletions src/app/screens/ledger/importLedgerAccount/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ function ImportLedger(): JSX.Element {
setAccountId(newAccountId);
const deviceNewAccountIndex = getDeviceNewAccountIndex(
ledgerAccountsList,
network.type,
masterPubKey || masterFingerPrint,
);
if (isBitcoinSelected) {
Expand Down Expand Up @@ -206,6 +207,7 @@ function ImportLedger(): JSX.Element {
accountName: `Ledger Account ${newAccountId + 1}`,
deviceAccountIndex: getDeviceNewAccountIndex(
ledgerAccountsList,
network.type,
masterPubKey || masterFingerPrint,
),
};
Expand Down
13 changes: 5 additions & 8 deletions src/app/screens/settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,11 @@ function Setting() {
icon={ArrowIcon}
showDivider
/>
{!isLedgerAccount(selectedAccount) && (
<SettingComponent
text={t('NETWORK')}
onClick={openChangeNetworkScreen}
textDetail={network.type}
/>
)}

<SettingComponent
text={t('NETWORK')}
onClick={openChangeNetworkScreen}
textDetail={network.type}
/>
<SettingComponent
title={t('SECURITY')}
text={t('UPDATE_PASSWORD')}
Expand Down
2 changes: 1 addition & 1 deletion src/app/screens/speedUpTransaction/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ function SpeedUpTransactionScreen() {
...selectedAccount,
accountType: accountType || 'software',
accountId:
isLedgerAccount(selectedAccount) && selectedAccount.deviceAccountIndex
isLedgerAccount(selectedAccount) && typeof selectedAccount.deviceAccountIndex === 'number'
? selectedAccount.deviceAccountIndex
: selectedAccount.id,
network: network.type,
Expand Down
20 changes: 17 additions & 3 deletions src/common/utils/ledger.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { Account } from '@secretkeylabs/xverse-core';
import { Account, NetworkType } from '@secretkeylabs/xverse-core';

export const delay = (ms: number) =>
new Promise((res) => {
setTimeout(res, ms);
});

export const filterLedgerAccounts = (accounts: Account[], network: NetworkType) =>
accounts.filter((account) =>
account.ordinalsAddress?.startsWith(network === 'Mainnet' ? 'bc1' : 'tb1'),
);

// this is used for migrating the old ledger accounts to the new format
// it returns the index of the account in the list, which now maps to the deviceAccountIndex
export const getDeviceAccountIndex = (
ledgerAccountsList: Account[],
id: number,
Expand All @@ -31,10 +38,17 @@ export const getNewAccountId = (ledgerAccountsList: Account[]) => {
return ledgerAccountsList[ledgerAccountsList.length - 1].id + 1;
};

export const getDeviceNewAccountIndex = (ledgerAccountsList: Account[], masterKey?: string) => {
const ledgerAccountsIndexList = ledgerAccountsList
export const getDeviceNewAccountIndex = (
ledgerAccountsList: Account[],
network: NetworkType,
masterKey?: string,
) => {
const networkLedgerAccounts = filterLedgerAccounts(ledgerAccountsList, network);

const ledgerAccountsIndexList = networkLedgerAccounts
.filter((account) => masterKey === account.masterPubKey)
.map((account, key) =>
// ledger accounts initially didn't have deviceAccountIndex, so we map to their list index as as the initial behaviour
account.deviceAccountIndex !== undefined ? account.deviceAccountIndex : key,
)
.sort((a, b) => a - b);
Expand Down

0 comments on commit 7898e48

Please sign in to comment.