Skip to content

Commit

Permalink
wallet-ext: use new accounts in UI (MystenLabs#13371)
Browse files Browse the repository at this point in the history
## Description 

* removes all previous account types/classes from the UI (including
hooks, redux slice)
* now ui uses the new accounts for reading
* most of the create flows are disabled/broken
* moves active account handling from keyring to new accounts handling
* changes popup height to 600px
* skips all e2e tests since UI flows are broken (mainly cause of
onboarding)
* removes NEW_ACCOUNTS_ENABLED flag
* locked screen is remove from routes and locked screen is now tokens
page
* storage migration is now enabled and will run if necessary
* removes all tests for keyring and old accounts

part of APPS-1501

## Test Plan 

👀 

---
If your changes are not user-facing and not a breaking change, you can
skip the following section. Otherwise, please indicate what changed, and
then add to the Release Notes section as highlighted during the release
process.

### Type of Change (Check all that apply)

- [ ] protocol change
- [ ] user-visible impact
- [ ] breaking change for a client SDKs
- [ ] breaking change for FNs (FN binary must upgrade)
- [ ] breaking change for validators or node operators (must upgrade
binaries)
- [ ] breaking change for on-chain data layout
- [ ] necessitate either a data wipe or data migration

### Release notes
  • Loading branch information
pchrysochoidis authored Aug 16, 2023
1 parent a7e1bbf commit 1e9765f
Show file tree
Hide file tree
Showing 100 changed files with 747 additions and 1,551 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ type EphemeralData = {
interface QredoAccountSourceSerialized extends AccountSourceSerialized, QredoConnectIdentity {
type: 'qredo';
encrypted: string;
originFavIcon: string;
}

interface QredoAccountSourceSerializedUI extends AccountSourceSerializedUI, QredoConnectIdentity {
type: 'qredo';
originFavIcon: string;
}

export class QredoAccountSource extends AccountSource<QredoAccountSourceSerialized, EphemeralData> {
Expand All @@ -44,13 +46,15 @@ export class QredoAccountSource extends AccountSource<QredoAccountSourceSerializ
origin,
service,
refreshToken,
originFavIcon,
}: {
password: string;
apiUrl: string;
organization: string;
origin: string;
service: string;
refreshToken: string;
originFavIcon: string;
}) {
const decryptedData: DataDecrypted = {
refreshToken,
Expand All @@ -63,6 +67,7 @@ export class QredoAccountSource extends AccountSource<QredoAccountSourceSerializ
origin,
service,
encrypted: await encrypt(password, decryptedData),
originFavIcon,
};
const allAccountSources = await getAccountSources();
for (const anAccountSource of allAccountSources) {
Expand Down Expand Up @@ -106,7 +111,7 @@ export class QredoAccountSource extends AccountSource<QredoAccountSourceSerializ
}

async toUISerialized(): Promise<QredoAccountSourceSerializedUI> {
const { apiUrl, id, organization, origin, service } = await this.getStoredData();
const { apiUrl, id, organization, origin, service, originFavIcon } = await this.getStoredData();
return {
id,
type: 'qredo',
Expand All @@ -115,6 +120,7 @@ export class QredoAccountSource extends AccountSource<QredoAccountSourceSerializ
organization,
service,
isLocked: await this.isLocked(),
originFavIcon,
};
}

Expand Down
8 changes: 8 additions & 0 deletions apps/wallet/src/background/accounts/Account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ export interface SerializedAccount {
readonly address: string;
readonly publicKey: string | null;
readonly lastUnlockedOn: number | null;
/**
* indicates if it's the selected account in the UI (active account)
*/
readonly selected: boolean;
}

export interface SerializedUIAccount {
Expand All @@ -131,6 +135,10 @@ export interface SerializedUIAccount {
* This is used to determine if the account is locked for read or not. (eg. lastUnlockedOn more than 4 hours ago -> read locked)
*/
readonly lastUnlockedOn: number | null;
/**
* indicates if it's the selected account in the UI (active account)
*/
readonly selected: boolean;
}

export interface PasswordUnlockableAccount {
Expand Down
4 changes: 3 additions & 1 deletion apps/wallet/src/background/accounts/ImportedAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export class ImportedAccount
publicKey: keyPair.getPublicKey().toBase64(),
encrypted: await encrypt(inputs.password, dataToEncrypt),
lastUnlockedOn: null,
selected: false,
};
}

Expand All @@ -74,14 +75,15 @@ export class ImportedAccount
}

async toUISerialized(): Promise<ImportedAccountSerializedUI> {
const { address, publicKey, type } = await this.getStoredData();
const { address, publicKey, type, selected } = await this.getStoredData();
return {
id: this.id,
type,
address,
publicKey,
isLocked: await this.isLocked(),
lastUnlockedOn: await this.lastUnlockedOn,
selected,
};
}

Expand Down
4 changes: 3 additions & 1 deletion apps/wallet/src/background/accounts/LedgerAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export class LedgerAccount
encrypted: await encrypt(password, {}),
derivationPath,
lastUnlockedOn: null,
selected: false,
};
}

Expand Down Expand Up @@ -83,7 +84,7 @@ export class LedgerAccount
}

async toUISerialized(): Promise<LedgerAccountSerializedUI> {
const { address, type, publicKey, derivationPath } = await this.getStoredData();
const { address, type, publicKey, derivationPath, selected } = await this.getStoredData();
return {
id: this.id,
type,
Expand All @@ -92,6 +93,7 @@ export class LedgerAccount
publicKey,
derivationPath,
lastUnlockedOn: await this.lastUnlockedOn,
selected,
};
}
}
5 changes: 4 additions & 1 deletion apps/wallet/src/background/accounts/MnemonicAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export class MnemonicAccount
derivationPath,
publicKey: keyPair.getPublicKey().toBase64(),
lastUnlockedOn: null,
selected: false,
};
}

Expand Down Expand Up @@ -88,7 +89,8 @@ export class MnemonicAccount
}

async toUISerialized(): Promise<MnemonicSerializedUiAccount> {
const { id, type, address, derivationPath, publicKey, sourceID } = await this.getStoredData();
const { id, type, address, derivationPath, publicKey, sourceID, selected } =
await this.getStoredData();
return {
id,
type,
Expand All @@ -98,6 +100,7 @@ export class MnemonicAccount
publicKey,
sourceID,
lastUnlockedOn: await this.lastUnlockedOn,
selected,
};
}

Expand Down
3 changes: 2 additions & 1 deletion apps/wallet/src/background/accounts/QredoAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class QredoAccount
}

async toUISerialized(): Promise<QredoSerializedUiAccount> {
const { id, type, address, publicKey, sourceID, labels, network, walletID } =
const { id, type, address, publicKey, sourceID, labels, network, walletID, selected } =
await this.getStoredData();
return {
id,
Expand All @@ -75,6 +75,7 @@ export class QredoAccount
network,
walletID,
lastUnlockedOn: await this.lastUnlockedOn,
selected,
};
}

Expand Down
1 change: 1 addition & 0 deletions apps/wallet/src/background/accounts/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import mitt from 'mitt';
type AccountsEvents = {
accountsChanged: void;
accountStatusChanged: { accountID: string };
activeAccountChanged: { accountID: string };
};

export const accountsEvents = mitt<AccountsEvents>();
29 changes: 22 additions & 7 deletions apps/wallet/src/background/accounts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { getAccountSourceByID } from '../account-sources';
import { MnemonicAccountSource } from '../account-sources/MnemonicAccountSource';
import { type UiConnection } from '../connections/UiConnection';
import { backupDB, getDB } from '../db';
import { getFromLocalStorage, makeUniqueKey } from '../storage-utils';
import { makeUniqueKey } from '../storage-utils';
import { createMessage, type Message } from '_src/shared/messaging/messages';
import {
type MethodPayload,
Expand Down Expand Up @@ -71,12 +71,17 @@ export async function isAccountsInitialized() {
return (await (await getDB()).accounts.count()) > 0;
}

export async function getActiveAccount() {
const accountID = await getFromLocalStorage<string>('active-account-id-key');
if (!accountID) {
return null;
}
return getAccountByID(accountID);
export async function changeActiveAccount(accountID: string) {
const db = await getDB();
return db.transaction('rw', db.accounts, async () => {
const newSelectedAccount = await db.accounts.get(accountID);
if (!newSelectedAccount) {
throw new Error(`Failed, account with id ${accountID} not found`);
}
await db.accounts.where('id').notEqual(accountID).modify({ selected: false });
await db.accounts.update(accountID, { selected: true });
accountsEvents.emit('activeAccountChanged', { accountID });
});
}

async function deleteQredoAccounts<T extends SerializedAccount>(accounts: Omit<T, 'id'>[]) {
Expand Down Expand Up @@ -148,6 +153,11 @@ export async function addNewAccounts<T extends SerializedAccount>(accounts: Omit
}
accountInstances.push(accountInstance);
}
const selectedAccount = await db.accounts.filter(({ selected }) => selected).first();
if (!selectedAccount && accountInstances.length) {
const firstAccount = accountInstances[0];
await db.accounts.update(firstAccount.id, { selected: true });
}
return accountInstances;
});
await backupDB();
Expand Down Expand Up @@ -244,5 +254,10 @@ export async function accountsHandleUIMessage(msg: Message, uiConnection: UiConn
);
return true;
}
if (isMethodPayload(payload, 'switchAccount')) {
await changeActiveAccount(payload.args.accountID);
await uiConnection.send(createMessage({ type: 'done' }, msg.id));
return true;
}
return false;
}
4 changes: 3 additions & 1 deletion apps/wallet/src/background/accounts/zk/ZkAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export class ZkAccount
provider,
publicKey: null,
lastUnlockedOn: null,
selected: false,
};
}

Expand Down Expand Up @@ -196,7 +197,7 @@ export class ZkAccount
}

async toUISerialized(): Promise<ZkAccountSerializedUI> {
const { address, publicKey, type, claims } = await this.getStoredData();
const { address, publicKey, type, claims, selected } = await this.getStoredData();
const { email, picture } = await deobfuscate<JwtSerializedClaims>(claims);
return {
id: this.id,
Expand All @@ -207,6 +208,7 @@ export class ZkAccount
lastUnlockedOn: await this.lastUnlockedOn,
email,
picture,
selected,
};
}

Expand Down
19 changes: 0 additions & 19 deletions apps/wallet/src/background/connections/UiConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import {
import type { Message } from '_messages';
import type { PortChannelName } from '_messaging/PortChannelName';
import type { LoadedFeaturesPayload } from '_payloads/feature-gating';
import type { KeyringPayload } from '_payloads/keyring';
import type { Permission, PermissionRequests } from '_payloads/permissions';
import type { UpdateActiveOrigin } from '_payloads/tabs/updateActiveOrigin';
import type { ApprovalRequest } from '_payloads/transactions/ApprovalRequest';
Expand Down Expand Up @@ -72,24 +71,6 @@ export class UiConnection extends Connection {
});
}

public async sendLockedStatusUpdate(isLocked: boolean, replyForId?: string) {
this.send(
createMessage<KeyringPayload<'walletStatusUpdate'>>(
{
type: 'keyring',
method: 'walletStatusUpdate',
return: {
isLocked,
accounts: (await Keyring.getAccounts())?.map((anAccount) => anAccount.toJSON()) || [],
activeAddress: (await Keyring.getActiveAccount())?.address || null,
isInitialized: await Keyring.isWalletInitialized(),
},
},
replyForId,
),
);
}

public async notifyEntitiesUpdated(entitiesType: UIAccessibleEntityType) {
this.send(
createMessage<MethodPayload<'entitiesUpdated'>>({
Expand Down
4 changes: 0 additions & 4 deletions apps/wallet/src/background/connections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ export class Connections {
public notifyUI(
notification:
| { event: 'networkChanged'; network: NetworkEnvType }
| { event: 'lockStatusUpdate'; isLocked: boolean }
| { event: 'storedEntitiesUpdated'; type: UIAccessibleEntityType },
) {
for (const aConnection of this.#connections) {
Expand All @@ -128,9 +127,6 @@ export class Connections {
}),
);
break;
case 'lockStatusUpdate':
aConnection.sendLockedStatusUpdate(notification.isLocked);
break;
case 'storedEntitiesUpdated':
aConnection.notifyEntitiesUpdated(notification.type);
break;
Expand Down
22 changes: 4 additions & 18 deletions apps/wallet/src/background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { getAllAccounts } from './accounts';
import { accountsEvents } from './accounts/events';
import { Connections } from './connections';
import Keyring from './keyring';
import { deleteAccountsPublicInfo, getStoredAccountsPublicInfo } from './keyring/accounts';
import { getStoredAccountsPublicInfo } from './keyring/accounts';
import * as Qredo from './qredo';
import { initSentry } from './sentry';
import { isSessionStorageSupported } from './storage-utils';
Expand Down Expand Up @@ -87,23 +87,6 @@ Permissions.on('connectedAccountsChanged', async ({ origin, accounts }) => {
});
});

const keyringStatusCallback = () => {
connections.notifyUI({
event: 'lockStatusUpdate',
isLocked: Keyring.isLocked,
});
};
Keyring.on('lockedStatusUpdate', keyringStatusCallback);
Keyring.on('accountsChanged', keyringStatusCallback);
Keyring.on('activeAccountChanged', keyringStatusCallback);

Keyring.on('accountsChanged', async (accounts) => {
await deleteAccountsPublicInfo({
toKeep: accounts.map(({ address }) => address),
});
await Permissions.ensurePermissionAccountsUpdated(accounts);
});

accountsEvents.on('accountsChanged', async () => {
connections.notifyUI({ event: 'storedEntitiesUpdated', type: 'accounts' });
await Permissions.ensurePermissionAccountsUpdated(
Expand All @@ -115,6 +98,9 @@ accountsEvents.on('accountsChanged', async () => {
accountsEvents.on('accountStatusChanged', () => {
connections.notifyUI({ event: 'storedEntitiesUpdated', type: 'accounts' });
});
accountsEvents.on('activeAccountChanged', () => {
connections.notifyUI({ event: 'storedEntitiesUpdated', type: 'accounts' });
});
accountSourcesEvents.on('accountSourceStatusUpdated', () => {
connections.notifyUI({ event: 'storedEntitiesUpdated', type: 'accountSources' });
});
Expand Down
Loading

0 comments on commit 1e9765f

Please sign in to comment.