diff --git a/src/ppom-controller.test.ts b/src/ppom-controller.test.ts index 9471375e..b6dbabca 100644 --- a/src/ppom-controller.test.ts +++ b/src/ppom-controller.test.ts @@ -195,7 +195,7 @@ describe('PPOMController', () => { }).rejects.toThrow('User has securityAlertsEnabled set to false'); }); - it('should throw error if the user is not on ethereum mainnet', async () => { + it('should throw error if the user is not on supported chain id', async () => { buildFetchSpy(); ppomController = buildPPOMController({ chainId: '0x2', @@ -206,7 +206,7 @@ describe('PPOMController', () => { return Promise.resolve(); }); }).rejects.toThrow( - 'Blockaid validation is available only on ethereum mainnet', + 'Blockaid validation is not available on selected network', ); }); @@ -460,7 +460,7 @@ describe('PPOMController', () => { await ppomController.updatePPOM(); jest.runOnlyPendingTimers(); await flushPromises(); - expect(spy).toHaveBeenCalledTimes(13); + expect(spy).toHaveBeenCalledTimes(12); }); it('should not re-throw error if file write fails', async () => { @@ -493,7 +493,7 @@ describe('PPOMController', () => { expect(spy).toHaveBeenCalledTimes(6); jest.advanceTimersByTime(REFRESH_TIME_INTERVAL); await flushPromises(); - expect(spy).toHaveBeenCalledTimes(8); + expect(spy).toHaveBeenCalledTimes(10); }); it('should delete network more than a week old from chainStatus', async () => { @@ -638,11 +638,14 @@ describe('PPOMController', () => { jest.useFakeTimers().setSystemTime(new Date('2023-01-04')); callBack({ providerConfig: { chainId: '0x6' } }); - expect(Object.keys(ppomController.state.chainStatus)).toHaveLength(5); + jest.useFakeTimers().setSystemTime(new Date('2023-01-04')); + callBack({ providerConfig: { chainId: '0x8' } }); + + expect(Object.keys(ppomController.state.chainStatus)).toHaveLength(6); jest.useFakeTimers().setSystemTime(new Date('2023-01-06')); callBack({ providerConfig: { chainId: '0x7' } }); - expect(Object.keys(ppomController.state.chainStatus)).toHaveLength(5); + expect(Object.keys(ppomController.state.chainStatus)).toHaveLength(6); expect(ppomController.state.chainStatus['0x1']).toBeUndefined(); }); diff --git a/src/ppom-controller.ts b/src/ppom-controller.ts index f7e513d8..1e537f2a 100644 --- a/src/ppom-controller.ts +++ b/src/ppom-controller.ts @@ -51,7 +51,15 @@ const ALLOWED_PROVIDER_CALLS = [ 'trace_filter', ]; -const ETHEREUM_CHAIN_ID = '0x1'; +export const SUPPORTED_CHAIN_IDS = [ + '0x1', // ethereum mainnet chain id + '0x38', // bnb chain id + '0x89', // polygon chain id + '0xa4b1', // arbitrum chain id + '0xa', // optimism chain id + '0xa86a', // avalanche chain id + '0xe708', // Linea chain id +]; /** * @type PPOMFileVersion @@ -321,7 +329,7 @@ export class PPOMController extends BaseControllerV2< if (securityAlertsEnabled) { this.#updateVersionInfo() .then(async () => { - await this.#getNewFilesForChain(ETHEREUM_CHAIN_ID); + await this.#getNewFilesForChain(this.#chainId); // start scheduled task to fetch data files this.#checkScheduleFileDownloadForAllChains(); }) @@ -361,7 +369,7 @@ export class PPOMController extends BaseControllerV2< throw Error('User has securityAlertsEnabled set to false'); } if (!this.#networkIsSupported(this.#chainId)) { - throw Error('Blockaid validation is available only on ethereum mainnet'); + throw Error('Blockaid validation is not available on selected network'); } await this.#reinitPPOMForNetworkIfRequired(); @@ -407,11 +415,10 @@ export class PPOMController extends BaseControllerV2< } /* - * The function check if ethereum chainId is supported for validation - * Currently it checks for only Ethereum Mainnet but it will include more networks in future. + * The function check if chainId is supported for validation */ #networkIsSupported(chainId: string) { - return chainId === ETHEREUM_CHAIN_ID; + return SUPPORTED_CHAIN_IDS.includes(chainId); } /* @@ -494,7 +501,7 @@ export class PPOMController extends BaseControllerV2< this.#updateVersionInfo() .then(async () => { this.#checkScheduleFileDownloadForAllChains(); - await this.#getNewFilesForChain(ETHEREUM_CHAIN_ID); + await this.#getNewFilesForChain(this.#chainId); }) .catch((error: Error) => { console.error(`Error in initialising: ${error.message}`); @@ -774,8 +781,9 @@ export class PPOMController extends BaseControllerV2< const currentTimestamp = new Date().getTime(); const chainIds = Object.keys(this.state.chainStatus).filter( - (id) => id !== ETHEREUM_CHAIN_ID, + (id) => id !== this.#chainId, ); + const oldChaninIds: any[] = chainIds.filter( (chainId) => (this.state.chainStatus[chainId] as any).lastVisited < @@ -843,8 +851,8 @@ export class PPOMController extends BaseControllerV2< if (isLastFileOfNetwork) { // if this was last file for the chainId set dataFetched for chainId to true await this.#setChainIdDataFetched(fileVersionInfo.chainId); - if (fileVersionInfo.chainId === ETHEREUM_CHAIN_ID) { - await this.#reinitPPOM(ETHEREUM_CHAIN_ID); + if (fileVersionInfo.chainId === this.#chainId) { + await this.#reinitPPOM(this.#chainId); } } }) @@ -1000,9 +1008,10 @@ export class PPOMController extends BaseControllerV2< // thus it is added here to prevent validation from failing. await this.#initialisePPOM(); const { chainStatus } = this.state; - const versionInfo = - chainStatus[chainId]?.versionInfo ?? - this.state.versionInfo.filter(({ chainId: id }) => id === chainId); + const hasVersionInfo = chainStatus[chainId]?.versionInfo?.length; + const versionInfo = hasVersionInfo + ? chainStatus[chainId]?.versionInfo + : this.state.versionInfo.filter(({ chainId: id }) => id === chainId); if (!versionInfo?.length) { this.#ppomInitError = `Aborting validation as no files are found for the network with chainId: ${chainId}`; return undefined; diff --git a/test/test-utils.ts b/test/test-utils.ts index 34c282dd..3a06a949 100644 --- a/test/test-utils.ts +++ b/test/test-utils.ts @@ -1,8 +1,8 @@ import { ControllerMessenger } from '@metamask/base-controller'; import * as ControllerUtils from '@metamask/controller-utils'; -import { PPOMController } from '../src/ppom-controller'; -import { StorageKey } from '../src/ppom-storage'; +import { PPOMController, SUPPORTED_CHAIN_IDS } from '../src/ppom-controller'; +import { FileMetadata, StorageKey } from '../src/ppom-storage'; export const buildDummyResponse = ( resultType = 'DUMMY_RESULT_TYPE', @@ -28,22 +28,25 @@ export const buildStorageBackend = (obj = {}) => { }; }; -export const StorageMetadata = [ - { - name: 'data', - chainId: '0x1', +export const StorageMetadata: FileMetadata[] = []; + +SUPPORTED_CHAIN_IDS.forEach((chainId) => { + const data = { + name: `${chainId}_data`, + chainId, version: '1.0.3', checksum: '409a7f83ac6b31dc8c77e3ec18038f209bd2f545e0f4177c2e2381aa4e067b49', - }, - { - name: 'blob', - chainId: '0x1', + }; + const blob = { + name: `${chainId}_blob`, + chainId, version: '1.0.0', checksum: '409a7f83ac6b31dc8c77e3ec18038f209bd2f545e0f4177c2e2381aa4e067b49', - }, -]; + }; + StorageMetadata.push(data, blob); +}); export const simpleStorageBackend = buildStorageBackend(); @@ -54,28 +57,35 @@ export const storageBackendReturningData = buildStorageBackend({ Promise.resolve(DUMMY_ARRAY_BUFFER_DATA), }); -export const VERSION_INFO = [ - { - name: 'blob', - chainId: '0x1', - version: '1.0.0', - checksum: - '409a7f83ac6b31dc8c77e3ec18038f209bd2f545e0f4177c2e2381aa4e067b49', - signature: - '0x304402206d433e9172960de6717d94ae263e47eefacd3584a3274a452f8f9567b3a797db02201b2e423188fb3f9daa6ce6a8723f69df26bd3ceeee81f77250526b91e093614f', - filePath: 'blob', - }, - { - name: 'data', - chainId: '0x1', - version: '1.0.3', - checksum: - '409a7f83ac6b31dc8c77e3ec18038f209bd2f545e0f4177c2e2381aa4e067b49', - signature: - '0x304402206d433e9172960de6717d94ae263e47eefacd3584a3274a452f8f9567b3a797db02201b2e423188fb3f9daa6ce6a8723f69df26bd3ceeee81f77250526b91e093614f', - filePath: 'data', - }, -]; +export const VERSION_INFO: (FileMetadata & { + signature: string; + filePath: string; +})[] = []; + +SUPPORTED_CHAIN_IDS.forEach((chainId) => { + VERSION_INFO.push( + { + name: `${chainId}_blob`, + chainId, + version: '1.0.0', + checksum: + '409a7f83ac6b31dc8c77e3ec18038f209bd2f545e0f4177c2e2381aa4e067b49', + signature: + '0x304402206d433e9172960de6717d94ae263e47eefacd3584a3274a452f8f9567b3a797db02201b2e423188fb3f9daa6ce6a8723f69df26bd3ceeee81f77250526b91e093614f', + filePath: `${chainId}_blob`, + }, + { + name: `${chainId}_blob`, + chainId, + version: '1.0.3', + checksum: + '409a7f83ac6b31dc8c77e3ec18038f209bd2f545e0f4177c2e2381aa4e067b49', + signature: + '0x304402206d433e9172960de6717d94ae263e47eefacd3584a3274a452f8f9567b3a797db02201b2e423188fb3f9daa6ce6a8723f69df26bd3ceeee81f77250526b91e093614f', + filePath: `${chainId}_data`, + }, + ); +}); const PPOM_VERSION_PATH = 'https://ppom_cdn_base_url/ppom_version.json';