1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-25 20:02:58 +01:00
metamask-extension/app/scripts/migrations/088.ts
2023-06-09 15:48:48 -05:00

165 lines
5.0 KiB
TypeScript

import { hasProperty, Hex, isObject, isStrictHexString } from '@metamask/utils';
import { BN } from 'ethereumjs-util';
import { cloneDeep, mapKeys } from 'lodash';
type VersionedData = {
meta: { version: number };
data: Record<string, unknown>;
};
export const version = 88;
/**
* This migration does a few things:
*
* - Rebuilds `allNftContracts` and `allNfts` in NftController state to be keyed
* by a hex chain ID rather than a decimal chain ID.
* - Rebuilds `tokensChainsCache` in TokenListController to be keyed by a hex
* chain ID rather than a decimal chain ID.
* - Rebuilds `allTokens` and `allIgnoredTokens` in TokensController to be keyed
* by a hex chain ID rather than a decimal chain ID.
*
* @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist.
* @param originalVersionedData.meta - State metadata.
* @param originalVersionedData.meta.version - The current state version.
* @param originalVersionedData.data - The persisted MetaMask state, keyed by controller.
* @returns Updated versioned MetaMask extension state.
*/
export async function migrate(
originalVersionedData: VersionedData,
): Promise<VersionedData> {
const versionedData = cloneDeep(originalVersionedData);
versionedData.meta.version = version;
migrateData(versionedData.data);
return versionedData;
}
function migrateData(state: Record<string, unknown>): void {
if (hasProperty(state, 'NftController') && isObject(state.NftController)) {
const nftControllerState = state.NftController;
// Migrate NftController.allNftContracts
if (
hasProperty(nftControllerState, 'allNftContracts') &&
isObject(nftControllerState.allNftContracts)
) {
const { allNftContracts } = nftControllerState;
if (
Object.keys(allNftContracts).every((address) =>
isObject(allNftContracts[address]),
)
) {
Object.keys(allNftContracts).forEach((address) => {
const nftContractsByChainId = allNftContracts[address];
if (isObject(nftContractsByChainId)) {
allNftContracts[address] = mapKeys(
nftContractsByChainId,
(_, chainId: string) => toHex(chainId),
);
}
});
}
}
// Migrate NftController.allNfts
if (
hasProperty(nftControllerState, 'allNfts') &&
isObject(nftControllerState.allNfts)
) {
const { allNfts } = nftControllerState;
if (Object.keys(allNfts).every((address) => isObject(allNfts[address]))) {
Object.keys(allNfts).forEach((address) => {
const nftsByChainId = allNfts[address];
if (isObject(nftsByChainId)) {
allNfts[address] = mapKeys(nftsByChainId, (_, chainId: string) =>
toHex(chainId),
);
}
});
}
}
state.NftController = nftControllerState;
}
if (
hasProperty(state, 'TokenListController') &&
isObject(state.TokenListController)
) {
const tokenListControllerState = state.TokenListController;
// Migrate TokenListController.tokensChainsCache
if (
hasProperty(tokenListControllerState, 'tokensChainsCache') &&
isObject(tokenListControllerState.tokensChainsCache)
) {
tokenListControllerState.tokensChainsCache = mapKeys(
tokenListControllerState.tokensChainsCache,
(_, chainId: string) => toHex(chainId),
);
}
}
if (
hasProperty(state, 'TokensController') &&
isObject(state.TokensController)
) {
const tokensControllerState = state.TokensController;
// Migrate TokensController.allTokens
if (
hasProperty(tokensControllerState, 'allTokens') &&
isObject(tokensControllerState.allTokens)
) {
const { allTokens } = tokensControllerState;
tokensControllerState.allTokens = mapKeys(
allTokens,
(_, chainId: string) => toHex(chainId),
);
}
// Migrate TokensController.allIgnoredTokens
if (
hasProperty(tokensControllerState, 'allIgnoredTokens') &&
isObject(tokensControllerState.allIgnoredTokens)
) {
const { allIgnoredTokens } = tokensControllerState;
tokensControllerState.allIgnoredTokens = mapKeys(
allIgnoredTokens,
(_, chainId: string) => toHex(chainId),
);
}
// Migrate TokensController.allDetectedTokens
if (
hasProperty(tokensControllerState, 'allDetectedTokens') &&
isObject(tokensControllerState.allDetectedTokens)
) {
const { allDetectedTokens } = tokensControllerState;
tokensControllerState.allDetectedTokens = mapKeys(
allDetectedTokens,
(_, chainId: string) => toHex(chainId),
);
}
state.TokensController = tokensControllerState;
}
}
function toHex(value: number | string | BN): Hex {
if (typeof value === 'string' && isStrictHexString(value)) {
return value;
}
const hexString = BN.isBN(value)
? value.toString(16)
: new BN(value.toString(), 10).toString(16);
return `0x${hexString}`;
}