Skip to content

Commit

Permalink
feat: add migrator for testnet 5
Browse files Browse the repository at this point in the history
  • Loading branch information
jinoosss committed Nov 12, 2024
1 parent bfa54c0 commit 5b597ad
Show file tree
Hide file tree
Showing 4 changed files with 354 additions and 6 deletions.
15 changes: 9 additions & 6 deletions packages/adena-extension/src/hooks/use-network.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { useCallback, useMemo } from 'react';
import { useRecoilState, useResetRecoilState } from 'recoil';

import { useAdenaContext, useWalletContext } from './use-context';
import { fetchHealth } from '@common/utils/fetch-utils';
import { EventMessage } from '@inject/message';
import { useAdenaContext, useWalletContext } from './use-context';
import { useEvent } from './use-event';
import { fetchHealth } from '@common/utils/fetch-utils';

import { NetworkMetainfo } from '@types';
import CHAIN_DATA from '@resources/chains/chains.json';
import { BalanceState, NetworkState, WalletState } from '@states';
import { useQuery } from '@tanstack/react-query';
import CHAIN_DATA from '@resources/chains/chains.json';
import { NetworkMetainfo } from '@types';

interface NetworkResponse {
networks: NetworkMetainfo[];
Expand Down Expand Up @@ -54,8 +54,11 @@ export const useNetwork = (): NetworkResponse => {
if (!currentNetwork) {
return null;
}
const isCustomNetwork = ['test4', 'portal-loop'].includes(currentNetwork.networkId);
const networkParameters: { [key in string]: string } = isCustomNetwork
const officialNetworkIds = CHAIN_DATA.filter((network) => !!network.apiUrl).map(
(network) => network.networkId,
);
const isOfficialNetwork = officialNetworkIds.includes(currentNetwork.networkId);
const networkParameters: { [key in string]: string } = isOfficialNetwork
? {
chainId: currentNetwork.networkId,
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { decryptAES } from 'adena-module';
import { StorageMigration008 } from './storage-migration-v008';

const mockStorageData = {
NETWORKS: [],
CURRENT_CHAIN_ID: 'test4',
CURRENT_NETWORK_ID: 'test4',
SERIALIZED: 'U2FsdGVkX19eI8kOCI/T9o1Ru0b2wdj5rHxmG4QbLQ0yZH4kDa8/gg6Ac2JslvEm',
ENCRYPTED_STORED_PASSWORD: '',
CURRENT_ACCOUNT_ID: '',
ACCOUNT_NAMES: {},
ESTABLISH_SITES: {},
ADDRESS_BOOK: '',
ACCOUNT_TOKEN_METAINFOS: {},
QUESTIONNAIRE_EXPIRED_DATE: null,
WALLET_CREATION_GUIDE_CONFIRM_DATE: null,
ADD_ACCOUNT_GUIDE_CONFIRM_DATE: null,
ACCOUNT_GRC721_COLLECTIONS: {},
ACCOUNT_GRC721_PINNED_PACKAGES: {},
};

describe('serialized wallet migration V008', () => {
it('version', () => {
const migration = new StorageMigration008();
expect(migration.version).toBe(8);
});

it('up success', async () => {
const mockData = {
version: 7,
data: mockStorageData,
};
const migration = new StorageMigration008();
const result = await migration.up(mockData);

expect(result.data.CURRENT_CHAIN_ID).toEqual('test5');
expect(result.data.CURRENT_NETWORK_ID).toEqual('test5');
});

it('up password success', async () => {
const mockData = {
version: 1,
data: mockStorageData,
};
const password = '123';
const migration = new StorageMigration008();
const result = await migration.up(mockData);

expect(result.version).toBe(8);
expect(result.data).not.toBeNull();
expect(result.data.ACCOUNT_GRC721_COLLECTIONS).toEqual({});
expect(result.data.ACCOUNT_GRC721_PINNED_PACKAGES).toEqual({});

const serialized = result.data.SERIALIZED;
const decrypted = await decryptAES(serialized, password);
const wallet = JSON.parse(decrypted);

expect(wallet.accounts).toHaveLength(0);
expect(wallet.keyrings).toHaveLength(0);

expect(result.data.CURRENT_CHAIN_ID).toEqual('test5');
expect(result.data.CURRENT_NETWORK_ID).toEqual('test5');
});

it('up failed throw error', async () => {
const mockData: any = {
version: 1,
data: { ...mockStorageData, SERIALIZED: null },
};
const migration = new StorageMigration008();

await expect(migration.up(mockData)).rejects.toThrow(
'Storage Data does not match version V007',
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { StorageModel } from '@common/storage';
import { Migration } from '@migrates/migrator';
import CHAIN_DATA from '@resources/chains/chains.json';
import {
CurrentChainIdModelV007,
CurrentNetworkIdModelV007,
NetworksModelV007,
StorageModelDataV007,
} from '../v007/storage-model-v007';
import {
CurrentChainIdModelV008,
CurrentNetworkIdModelV008,
NetworksModelV008,
StorageModelDataV008,
} from './storage-model-v008';

export class StorageMigration008 implements Migration<StorageModelDataV008> {
public readonly version = 8;

async up(
current: StorageModel<StorageModelDataV007>,
): Promise<StorageModel<StorageModelDataV008>> {
if (!this.validateModelV007(current.data)) {
throw new Error('Storage Data does not match version V007');
}
const previous: StorageModelDataV007 = current.data;
return {
version: this.version,
data: {
...previous,
CURRENT_CHAIN_ID: this.migrateCurrentChainId(previous.CURRENT_CHAIN_ID),
CURRENT_NETWORK_ID: this.migrateCurrentNetworkId(previous.CURRENT_NETWORK_ID),
NETWORKS: this.migrateNetwork(previous.NETWORKS),
},
};
}

private validateModelV007(currentData: StorageModelDataV007): boolean {
const storageDataKeys = [
'NETWORKS',
'CURRENT_CHAIN_ID',
'CURRENT_NETWORK_ID',
'SERIALIZED',
'ENCRYPTED_STORED_PASSWORD',
'CURRENT_ACCOUNT_ID',
'ESTABLISH_SITES',
'ADDRESS_BOOK',
'ACCOUNT_TOKEN_METAINFOS',
'ACCOUNT_GRC721_COLLECTIONS',
'ACCOUNT_GRC721_PINNED_PACKAGES',
];
const currentDataKeys = Object.keys(currentData);
const hasKeys = storageDataKeys.every((dataKey) => {
return currentDataKeys.includes(dataKey);
});

if (!hasKeys) {
return false;
}
if (!Array.isArray(currentData.NETWORKS)) {
return false;
}
if (typeof currentData.CURRENT_CHAIN_ID !== 'string') {
return false;
}
if (typeof currentData.CURRENT_NETWORK_ID !== 'string') {
return false;
}
if (typeof currentData.SERIALIZED !== 'string') {
return false;
}
if (typeof currentData.ENCRYPTED_STORED_PASSWORD !== 'string') {
return false;
}
if (typeof currentData.CURRENT_ACCOUNT_ID !== 'string') {
return false;
}
if (currentData.ACCOUNT_NAMES && typeof currentData.ACCOUNT_NAMES !== 'object') {
return false;
}
if (currentData.ESTABLISH_SITES && typeof currentData.ESTABLISH_SITES !== 'object') {
return false;
}
return true;
}

private migrateCurrentChainId(currentChainId: CurrentChainIdModelV007): CurrentChainIdModelV008 {
if (currentChainId === 'test4') {
return 'test5';
}
return currentChainId;
}

private migrateCurrentNetworkId(
currentNetworkId: CurrentNetworkIdModelV007,
): CurrentNetworkIdModelV008 {
if (currentNetworkId === 'test4') {
return 'test5';
}
return currentNetworkId;
}

private migrateNetwork(networks: NetworksModelV007): NetworksModelV008 {
const defaultNetworks = CHAIN_DATA.filter((network) => network.default);
const customNetworks = networks
.filter((network) => !network.default)
.map((network) => {
const providedNetwork = CHAIN_DATA.find((data) => data.chainId === network.id);
if (providedNetwork) {
return {
...providedNetwork,
chainName: network.chainName,
networkName: network.networkName,
rpcUrl: network.rpcUrl,
};
}
return {
...network,
indexerUrl: '',
};
});
return [...defaultNetworks, ...customNetworks];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
export type StorageModelV008 = {
version: 8;
data: StorageModelDataV008;
};

export type StorageModelDataV008 = {
NETWORKS: NetworksModelV008;
CURRENT_CHAIN_ID: CurrentChainIdModelV008;
CURRENT_NETWORK_ID: CurrentNetworkIdModelV008;
SERIALIZED: SerializedModelV008;
ENCRYPTED_STORED_PASSWORD: EncryptedStoredPasswordModelV008;
CURRENT_ACCOUNT_ID: CurrentAccountIdModelV008;
ACCOUNT_NAMES: AccountNamesModelV008;
ESTABLISH_SITES: EstablishSitesModelV008;
ADDRESS_BOOK: AddressBookModelV008;
ACCOUNT_TOKEN_METAINFOS: AccountTokenMetainfoModelV008;
QUESTIONNAIRE_EXPIRED_DATE: QuestionnaireExpiredDateModelV008;
WALLET_CREATION_GUIDE_CONFIRM_DATE: WalletCreationGuideConfirmDateModelV008;
ADD_ACCOUNT_GUIDE_CONFIRM_DATE: AddAccountGuideConfirmDateModelV008;
ACCOUNT_GRC721_COLLECTIONS: AccountGRC721CollectionsV008;
ACCOUNT_GRC721_PINNED_PACKAGES: AccountGRC721PinnedPackagesV008;
};

export type NetworksModelV008 = {
id: string;
default: boolean;
main: boolean;
chainId: string;
chainName: string;
networkId: string;
networkName: string;
addressPrefix: string;
rpcUrl: string;
indexerUrl: string;
gnoUrl: string;
apiUrl: string;
linkUrl: string;
deleted?: boolean;
}[];

export type CurrentChainIdModelV008 = string;

export type CurrentNetworkIdModelV008 = string;

export type SerializedModelV008 = string;

export type QuestionnaireExpiredDateModelV008 = number | null;

export type WalletCreationGuideConfirmDateModelV008 = number | null;

export type AddAccountGuideConfirmDateModelV008 = number | null;

export type WalletModelV008 = {
accounts: AccountDataModelV008[];
keyrings: KeyringDataModelV008[];
currentAccountId?: string;
};

type AccountDataModelV008 = {
id?: string;
index: number;
type: 'HD_WALLET' | 'PRIVATE_KEY' | 'LEDGER' | 'WEB3_AUTH' | 'AIRGAP';
name: string;
keyringId: string;
hdPath?: number;
publicKey: number[];
addressBytes?: number[];
};

type KeyringDataModelV008 = {
id?: string;
type: 'HD_WALLET' | 'PRIVATE_KEY' | 'LEDGER' | 'WEB3_AUTH' | 'AIRGAP';
publicKey?: number[];
privateKey?: number[];
seed?: number[];
mnemonic?: string;
addressBytes?: number[];
};

export type EncryptedStoredPasswordModelV008 = string;

export type CurrentAccountIdModelV008 = string;

type AccountId = string;
type NetworkId = string;

export type AccountNamesModelV008 = { [key in AccountId]: string };

export type EstablishSitesModelV008 = {
[key in AccountId]: {
hostname: string;
chainId: string;
account: string;
name: string;
favicon: string | null;
establishedTime: string;
}[];
};

export type AddressBookModelV008 = string;

export type AccountTokenMetainfoModelV008 = {
[key in string]: {
main: boolean;
tokenId: string;
networkId: string;
display: boolean;
type: 'gno-native' | 'grc20' | 'ibc-native' | 'ibc-tokens';
name: string;
symbol: string;
decimals: number;
description?: string;
websiteUrl?: string;
image: string;
denom?: string;
pkgPath?: string;
originChain?: string;
originDenom?: string;
originType?: string;
path?: string;
channel?: string;
port?: string;
}[];
};

export type AccountGRC721CollectionsV008 = {
[key in AccountId]: {
[key in NetworkId]: {
tokenId: string;
networkId: string;
display: boolean;
type: 'grc721';
packagePath: string;
name: string;
symbol: string;
image: string | null;
isTokenUri: boolean;
isMetadata: boolean;
}[];
};
};

export type AccountGRC721PinnedPackagesV008 = {
[key in AccountId]: { [key in NetworkId]: string[] };
};

0 comments on commit 5b597ad

Please sign in to comment.