From 3493be47c058de26bb636a4878dac84aceb32ed8 Mon Sep 17 00:00:00 2001 From: Nikos Kontakis Date: Tue, 3 Aug 2021 13:10:51 +0300 Subject: [PATCH] Extension - Add/Remove Chains (Smoldot v.0.3.x) (#428) * minor changes on Detector to accept chainspecs * Add implementation concerning adding chain of new app end to end * add code for removing app's chain from smoldot upon disconnection * remove indexing from Appmediator and related chain with it * add more exclusions for IDE's sanity * correct some test cases and remove stray log * Fix circular dependencies issue that was breaking the tests * Keep action without spec; Alter message to include 'spec' and use 'forward' method for propagating it to background --- .../connect-extension-protocol/src/index.ts | 7 ++- packages/connect/src/Detector.test.ts | 10 ++-- packages/connect/src/Detector.ts | 22 ++++----- .../ExtensionProvider.test.ts | 8 ++-- .../ExtensionProvider/ExtensionProvider.ts | 35 ++++++++++---- projects/extension/{ .babelrc => .babelrc} | 7 +-- .../extension/src/background/AppMediator.ts | 48 +++++++++++++++---- .../src/background/ConnectionManager.test.ts | 15 +++--- .../src/background/ConnectionManager.ts | 17 ++++--- projects/extension/src/background/index.ts | 18 ++++--- projects/extension/src/background/types.ts | 2 + .../src/content/ExtensionMessageRouter.ts | 2 +- projects/extension/src/content/index.ts | 2 - projects/extension/src/mocks.ts | 5 ++ projects/extension/src/types/index.ts | 1 - 15 files changed, 121 insertions(+), 78 deletions(-) rename projects/extension/{ .babelrc => .babelrc} (73%) diff --git a/packages/connect-extension-protocol/src/index.ts b/packages/connect-extension-protocol/src/index.ts index 40fa29710..61f51b90f 100644 --- a/packages/connect-extension-protocol/src/index.ts +++ b/packages/connect-extension-protocol/src/index.ts @@ -24,7 +24,7 @@ export interface ExtensionMessageData { /** message is telling the `ExtensionProvider` the port has been closed **/ disconnect?: boolean; /** message is the message from the manager to be forwarded to the app **/ - message?: MessageFromManager + message?: MessageFromManager; } /** @@ -53,7 +53,6 @@ export const extension = { } }; - /** * ProviderMessage represents messages sent via `window.postMessage` from * `ExtensionProvider` to `ExtensionMessageRouter` as received by the extension. @@ -71,7 +70,7 @@ export interface ProviderMessageData { /** What action the `ExtensionMessageRouter` should take **/ action: 'forward' | 'connect' | 'disconnect'; /** The message the `ExtensionMessageRouter` should forward to the background **/ - message?: MessageToManager + message?: MessageToManager; } /** @@ -80,7 +79,7 @@ export interface ProviderMessageData { */ export interface MessageToManager { /** Type of the message. Defines how to interpret the {@link payload} */ - type: 'rpc'; + type: 'rpc' | 'spec'; /** Payload of the message - a JSON encoded RPC request **/ payload: string; /** whether an RPC message is a subscription or not **/ diff --git a/packages/connect/src/Detector.test.ts b/packages/connect/src/Detector.test.ts index 4af02786d..ba9155a1a 100644 --- a/packages/connect/src/Detector.test.ts +++ b/packages/connect/src/Detector.test.ts @@ -15,14 +15,14 @@ describe('Initialize Detector without extension', () => { detect = new Detector('test-uapp'); const api = await detect.connect('westend'); expect(api).toBeTruthy(); - await detect.disconnect('westend'); + detect.disconnect('westend'); }, timeout); test('Should connect with known chain "polkadot".', async () => { detect = new Detector('test-uapp'); const api = await detect.connect('polkadot'); expect(api).toBeTruthy(); - await detect.disconnect('polkadot'); + detect.disconnect('polkadot'); }, extTimeout); test('Should connect with known chain westend, no chainSpecs and options', async () => { @@ -31,14 +31,14 @@ describe('Initialize Detector without extension', () => { const options = {} as ApiOptions; const api = await detect.connect(chainName, undefined, options); expect(api).toBeTruthy(); - await detect.disconnect('westend'); + detect.disconnect('westend'); }, extTimeout); test('Should connect with known chain "kusama".', async () => { detect = new Detector('test-uapp'); const api = await detect.connect('kusama'); expect(api).toBeTruthy(); - await detect.disconnect('kusama'); + detect.disconnect('kusama'); }, extTimeout); test('Should connect with unknown chain westend2 and chainSpecs.', async () => { @@ -47,7 +47,7 @@ describe('Initialize Detector without extension', () => { const detect = new Detector('test-uapp'); const api = await detect.connect(chainName, chainSpec); expect(api).toBeTruthy(); - await detect.disconnect(chainName); + detect.disconnect(chainName); }, extTimeout); test('Should NOT connect with unknown chain westend2 and without chainSpecs.', () => { diff --git a/packages/connect/src/Detector.ts b/packages/connect/src/Detector.ts index 4ea064c5a..218e583b1 100644 --- a/packages/connect/src/Detector.ts +++ b/packages/connect/src/Detector.ts @@ -122,18 +122,16 @@ export class Detector { public provider = (chainName: string, chainSpec?: string): ProviderInterface => { let provider: ProviderInterface = {} as ProviderInterface; - if (Object.keys(this.#chainSpecs).includes(chainName)) { - if (this.#isExtension) { - provider = new ExtensionProvider(this.#name, chainName); - } else if (!this.#isExtension) { - const chainSpec = JSON.stringify(this.#chainSpecs[chainName]); - provider = new SmoldotProvider(chainSpec); - } - } else if (chainSpec) { - provider = new SmoldotProvider(chainSpec); - } else if (!chainSpec) { + if (!chainSpec && !Object.keys(this.#chainSpecs).includes(chainName)) { throw new Error(`No known Chain was detected and no chainSpec was provided. Either give a known chain name ('${Object.keys(this.#chainSpecs).join('\', \'')}') or provide valid chainSpecs.`) } + + if (this.#isExtension) { + provider = new ExtensionProvider(this.#name, chainName, chainSpec) as ProviderInterface; + } else if (!this.#isExtension) { + const spec = JSON.stringify(this.#chainSpecs[chainName]); + provider = new SmoldotProvider(spec); + } return provider; } @@ -142,8 +140,8 @@ export class Detector { * * @param chainName - the name of the blockchain network to disconnect from */ - public disconnect = async (chainName: string): Promise => { - await this.#providers[chainName].disconnect(); + public disconnect = (chainName: string): void => { + void this.#providers[chainName].disconnect(); delete this.#providers[chainName]; }; } diff --git a/packages/connect/src/ExtensionProvider/ExtensionProvider.test.ts b/packages/connect/src/ExtensionProvider/ExtensionProvider.test.ts index b5df6915d..046fe93ca 100644 --- a/packages/connect/src/ExtensionProvider/ExtensionProvider.test.ts +++ b/packages/connect/src/ExtensionProvider/ExtensionProvider.test.ts @@ -48,7 +48,7 @@ test('connect sends connect message and emits connected', async () => { action: 'connect', origin: 'extension-provider' }; - expect(handler).toHaveBeenCalledTimes(1); + expect(handler).toHaveBeenCalledTimes(2); const { data } = handler.mock.calls[0][0] as ProviderMessage; expect(data).toEqual(expectedMessage); expect(ep.isConnected).toBe(true); @@ -61,7 +61,7 @@ test('disconnect sends disconnect message and emits disconnected', async () => { await ep.connect(); ep.on('disconnected', emitted); - await ep.disconnect(); + void ep.disconnect(); await waitForMessageToBePosted(); const expectedMessage: ProviderMessageData = { @@ -70,8 +70,8 @@ test('disconnect sends disconnect message and emits disconnected', async () => { action: 'disconnect', origin: 'extension-provider' }; - expect(handler).toHaveBeenCalledTimes(2); - const { data } = handler.mock.calls[1][0] as ProviderMessage; + expect(handler).toHaveBeenCalledTimes(3); + const { data } = handler.mock.calls[2][0] as ProviderMessage; expect(data).toEqual(expectedMessage); expect(ep.isConnected).toBe(false); expect(emitted).toHaveBeenCalledTimes(1); diff --git a/packages/connect/src/ExtensionProvider/ExtensionProvider.ts b/packages/connect/src/ExtensionProvider/ExtensionProvider.ts index 4194e35fc..eb5d690a4 100644 --- a/packages/connect/src/ExtensionProvider/ExtensionProvider.ts +++ b/packages/connect/src/ExtensionProvider/ExtensionProvider.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import {RpcCoder} from '@polkadot/rpc-provider/coder'; import { JsonRpcResponse, @@ -61,10 +62,12 @@ export class ExtensionProvider implements ProviderInterface { #appName: string; #chainName: string; + #chainSpecs: string | undefined; - public constructor(appName: string, chainName: string) { + public constructor(appName: string, chainName: string, chainSpecs?: string) { this.#appName = appName; this.#chainName = chainName; + this.#chainSpecs = chainSpecs; } /** @@ -105,7 +108,7 @@ export class ExtensionProvider implements ProviderInterface { * @remarks This method is not supported * @throws {@link Error} */ - public clone(): ExtensionProvider { + public clone(): ProviderInterface { throw new Error('clone() is not supported.'); } @@ -210,9 +213,24 @@ export class ExtensionProvider implements ProviderInterface { origin: EXTENSION_PROVIDER_ORIGIN } provider.send(connectMsg); + + // Once connect is sent - send rpc to extension that will contain the chainSpecs + // for the extension to call addChain on smoldot + const someMsg: ProviderMessageData = { + appName: this.#appName, + chainName: this.#chainName, + action: 'forward', + origin: EXTENSION_PROVIDER_ORIGIN, + message: { + type: 'spec', + payload: this.#chainSpecs || '' + } + } + + provider.send(someMsg); + provider.listen(({data}: ExtensionMessage) => { if (data.origin && data.origin === CONTENT_SCRIPT_ORIGIN) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access this.#handleMessage(data); } }); @@ -226,8 +244,7 @@ export class ExtensionProvider implements ProviderInterface { * Manually "disconnect" - sends a message to the `ExtensionMessageRouter` * telling it to disconnect the port with the background manager. */ - // eslint-disable-next-line @typescript-eslint/require-await - public async disconnect(): Promise { + public disconnect(): Promise { const disconnectMsg: ProviderMessageData = { appName: this.#appName, chainName: this.#chainName, @@ -238,6 +255,7 @@ export class ExtensionProvider implements ProviderInterface { provider.send(disconnectMsg); this.#isConnected = false; this.emit('disconnected'); + return Promise.resolve(); } /** @@ -276,10 +294,8 @@ export class ExtensionProvider implements ProviderInterface { */ public async send( method: string, - // eslint-disable-next-line @typescript-eslint/no-explicit-any params: any[], subscription?: SubscriptionHandler - // eslint-disable-next-line @typescript-eslint/no-explicit-any ): Promise { return new Promise((resolve, reject): void => { const json = this.#coder.encodeJson(method, params); @@ -347,7 +363,7 @@ export class ExtensionProvider implements ProviderInterface { callback: ProviderInterfaceCallback ): Promise { // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return await this.send(method, params, { callback, type }); + return await this.send(method, params, { callback, type }) as Promise; } /** @@ -376,8 +392,7 @@ export class ExtensionProvider implements ProviderInterface { return await this.send(method, [id]) as Promise; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - private emit(type: ProviderInterfaceEmitted, ...args: any[]): void { + private emit(type: ProviderInterfaceEmitted, ...args: unknown[]): void { this.#eventemitter.emit(type, ...args); } } diff --git a/projects/extension/ .babelrc b/projects/extension/.babelrc similarity index 73% rename from projects/extension/ .babelrc rename to projects/extension/.babelrc index 6c2eeee11..0247759ee 100644 --- a/projects/extension/ .babelrc +++ b/projects/extension/.babelrc @@ -12,10 +12,5 @@ "babel-plugin-styled-components", "react-hot-loader/babel", "@babel/plugin-proposal-private-methods" - ], - "env": { - "test": { - "plugins": ["transform-es2015-modules-commonjs"] - } - } + ] } diff --git a/projects/extension/src/background/AppMediator.ts b/projects/extension/src/background/AppMediator.ts index 746959b59..7ba6e0102 100644 --- a/projects/extension/src/background/AppMediator.ts +++ b/projects/extension/src/background/AppMediator.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-call */ import EventEmitter from 'eventemitter3'; import { MessageToManager, @@ -14,7 +13,18 @@ import { StateEmitter, SubscriptionMapping } from './types'; - +import { SmoldotChain } from 'smoldot'; +import westend from '../../public/assets/westend.json'; +import kusama from '../../public/assets/kusama.json'; +import polkadot from '../../public/assets/polkadot.json'; + +type RelayType = Map + +export const relayChains: RelayType = new Map([ + ["polkadot", JSON.stringify(polkadot)], + ["kusama", JSON.stringify(kusama)], + ["westend", JSON.stringify(westend)] +]) /** * AppMediator is the class that represents and manages an app's connection to * a blockchain network. N.B. an app that connects to multiple nblockchain @@ -31,6 +41,7 @@ export class AppMediator extends (EventEmitter as { new(): StateEmitter }) { readonly #url: string | undefined; readonly #manager: ConnectionManagerInterface; #chainName: string | undefined = undefined; + #chain: SmoldotChain | undefined; #state: AppState = 'connected'; /** subscriptions is all the active message subscriptions this ap[ has */ readonly subscriptions: SubscriptionMapping[]; @@ -82,13 +93,20 @@ export class AppMediator extends (EventEmitter as { new(): StateEmitter }) { } /** - * chainName is the name of the smoldot client to talk to; this is the + * chainName is the name of the chain to talk to; this is the * name of the blockchain network. */ get chainName(): string { return this.#chainName || ''; } + /** + * returns the chain that the app is connected to + */ + get chain(): SmoldotChain | undefined { + return this.#chain; + } + /** tabId is the tabId of the app in the browser */ get tabId(): number | undefined { return this.#tabId; @@ -216,8 +234,12 @@ export class AppMediator extends (EventEmitter as { new(): StateEmitter }) { return true; } + #addChain = async (chainName: string, chainSpecs: string): Promise => { + this.#chain = await this.#manager.addChain(chainName, chainSpecs); + } + #handleRpcRequest = (msg: MessageToManager): void => { - if (msg.type !== 'rpc') { + if (msg.type !== 'rpc' && msg.type !== 'spec') { console.warn(`Unrecognised message type ${msg.type} received from content script`); return; } @@ -236,11 +258,19 @@ export class AppMediator extends (EventEmitter as { new(): StateEmitter }) { method: parsed.method }); } - - // TODO: what about unsubscriptions requested by the UApp - we need to remove - // the subscription from our subscriptions state - const chainID = this.#manager.sendRpcMessageTo(this.#chainName as string, parsed); - this.requests.push({ appID, chainID }); + const chainName = this.#chainName as string; + + if (msg.type === 'spec' && chainName) { + const chainSpec: string = relayChains.has(chainName) ? + (relayChains.get(chainName) || '') : + msg.payload + this.#addChain(chainName, chainSpec).catch(console.error); + } else { + // TODO: what about unsubscriptions requested by the UApp - we need to remove + // the subscription from our subscriptions state + const chainID = this.#manager.sendRpcMessageTo(chainName, parsed); + this.requests.push({ appID, chainID }); + } } /** diff --git a/projects/extension/src/background/ConnectionManager.test.ts b/projects/extension/src/background/ConnectionManager.test.ts index a72891ef2..1a5429491 100644 --- a/projects/extension/src/background/ConnectionManager.test.ts +++ b/projects/extension/src/background/ConnectionManager.test.ts @@ -14,7 +14,7 @@ const connectApp = (manager: ConnectionManager, tabId: number, name: string, ne } test('adding and removing apps changes state', async () => { - //setup conenection manager with 2 chains + //setup connection manager with 2 chains const manager = new ConnectionManager(); manager.smoldotLogLevel = 1; await manager.initSmoldot(); @@ -84,7 +84,6 @@ test('adding and removing apps changes state', async () => { ] }); - handler.mockClear(); manager.disconnectTab(42); expect(handler).toHaveBeenCalledTimes(2); @@ -177,22 +176,20 @@ describe('Unit tests', () => { }); test('Get networks/chains', () => { - const tmpChains: unknown[] = []; // With this look the "chain" is removed intentionally as "chain" // object cannot be compared with jest - manager.networks.forEach(n => { - tmpChains.push({ - idx: n.idx, + const tmpChains = manager.networks.map(n => ( + { name: n.name, status: n.status, chainspecPath: n.chainspecPath, isKnown: n.isKnown }) - }) + ) expect(tmpChains).toEqual([ - { idx: 1, name: 'westend', status: "connected", chainspecPath: "westend.json", isKnown: true }, - { idx: 2, name: 'kusama', status: "connected", chainspecPath: "kusama.json", isKnown: true } + { name: 'westend', status: "connected", chainspecPath: "westend.json", isKnown: true }, + { name: 'kusama', status: "connected", chainspecPath: "kusama.json", isKnown: true } ]); expect(manager.networks).toHaveLength(2); diff --git a/projects/extension/src/background/ConnectionManager.ts b/projects/extension/src/background/ConnectionManager.ts index 21eb2ba3b..c5fada5fd 100644 --- a/projects/extension/src/background/ConnectionManager.ts +++ b/projects/extension/src/background/ConnectionManager.ts @@ -1,9 +1,7 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import * as smoldot from 'smoldot'; import { AppMediator } from './AppMediator'; import { JsonRpcResponse, JsonRpcRequest, ConnectionManagerInterface } from './types'; @@ -28,7 +26,6 @@ export class ConnectionManager extends (EventEmitter as { new(): StateEmitter }) readonly #networks: Network[] = []; readonly #apps: AppMediator[] = []; smoldotLogLevel = 3; - #chainCounter = 0; #id = 0; /** registeredApps @@ -175,13 +172,15 @@ export class ConnectionManager extends (EventEmitter as { new(): StateEmitter }) /** * unregisterApp is used after an app has finished processing any unsubscribe * messages and disconnected to fully unregister itself. - * + * It also retrieves the chain that app was connected to and calls smoldot for removal + * * @param app - The app */ unregisterApp(app: AppMediator): void { if (!this.#client) { throw new Error('Tried to unregister an app to smoldot client that does not exist.'); } + app.chain && app.chain?.remove(); const idx = this.#apps.findIndex(a => a.name === app.name); this.#apps.splice(idx, 1); this.emit('stateChanged', this.getState()); @@ -196,7 +195,7 @@ export class ConnectionManager extends (EventEmitter as { new(): StateEmitter }) /** * initSmoldot initializes the smoldot client. */ - async initSmoldot () { + async initSmoldot(): Promise { try { this.#client = await (smoldot as any).start({ forbidWs: true, /* suppress console warnings about insecure connections */ @@ -213,7 +212,7 @@ export class ConnectionManager extends (EventEmitter as { new(): StateEmitter }) * @param name - Name of the chain * @param spec - ChainSpec of chain to be added */ - async addChain (name: string, spec: string) { + async addChain (name: string, spec: string): Promise { try { if (!this.#client) { throw new Error('Smoldot client does not exist.'); @@ -229,7 +228,6 @@ export class ConnectionManager extends (EventEmitter as { new(): StateEmitter }) }); this.#networks.push({ - idx: ++this.#chainCounter, name: name, chain: addedChain, status: 'connected', @@ -237,6 +235,7 @@ export class ConnectionManager extends (EventEmitter as { new(): StateEmitter }) chainspecPath: `${name}.json` }); + return addedChain; } catch (err) { l.error(`Error while trying to connect to chain ${name}: ${err}`); } diff --git a/projects/extension/src/background/index.ts b/projects/extension/src/background/index.ts index 299f16264..a2281e1b7 100644 --- a/projects/extension/src/background/index.ts +++ b/projects/extension/src/background/index.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { ConnectionManager } from './ConnectionManager'; import westend from '../../public/assets/westend.json'; import kusama from '../../public/assets/kusama.json'; @@ -14,6 +12,14 @@ declare let window: Background; const manager = window.manager = new ConnectionManager(); +type RelayType = Map + +export const relayChains: RelayType = new Map([ + ["polkadot", JSON.stringify(polkadot)], + ["kusama", JSON.stringify(kusama)], + ["westend", JSON.stringify(westend)] +]) + const l = logger('Extension'); export interface RequestRpcSend { method: string; @@ -23,9 +29,9 @@ export interface RequestRpcSend { const init = async () => { try { await manager.initSmoldot(); - await manager.addChain('polkadot', JSON.stringify(polkadot)).catch(err => l.error('Error', err)); - await manager.addChain('kusama', JSON.stringify(kusama)).catch(err => l.error('Error', err)); - await manager.addChain('westend', JSON.stringify(westend)).catch(err => l.error('Error', err)); + for(const [key, value] of relayChains.entries()) { + await manager.addChain(key, value).catch(err => l.error('Error', err)); + } } catch (e) { l.error(`Error creating smoldot: ${e}`); } @@ -39,7 +45,7 @@ chrome.runtime.onStartup.addListener(() => { init().catch(console.error); }); -chrome.runtime.onConnect.addListener((port) => { +chrome.runtime.onConnect.addListener(port => { manager.addApp(port); }); diff --git a/projects/extension/src/background/types.ts b/projects/extension/src/background/types.ts index 021aca595..e465c81e2 100644 --- a/projects/extension/src/background/types.ts +++ b/projects/extension/src/background/types.ts @@ -1,3 +1,4 @@ +import * as smoldot from 'smoldot'; import { AppMediator } from './AppMediator'; import EventEmitter from 'eventemitter3'; import StrictEventEmitter from 'strict-event-emitter-types'; @@ -48,6 +49,7 @@ export interface ConnectionManagerInterface { sendRpcMessageTo: (name: string, message: JsonRpcRequest) => number; registerApp: (app: AppMediator, name: string) => void; unregisterApp: (app: AppMediator, name: string) => void; + addChain: (name: string, spec: string) => Promise; } export interface JsonRpcObject { diff --git a/projects/extension/src/content/ExtensionMessageRouter.ts b/projects/extension/src/content/ExtensionMessageRouter.ts index 7185bd924..5a74ef62d 100644 --- a/projects/extension/src/content/ExtensionMessageRouter.ts +++ b/projects/extension/src/content/ExtensionMessageRouter.ts @@ -124,7 +124,7 @@ export class ExtensionMessageRouter { return; } - if (innerMessage.type === 'rpc') { + if (innerMessage.type === 'rpc' || innerMessage.type === 'spec') { return this.#forwardRpcMessage(message); } diff --git a/projects/extension/src/content/index.ts b/projects/extension/src/content/index.ts index a27803868..b54b9a23d 100644 --- a/projects/extension/src/content/index.ts +++ b/projects/extension/src/content/index.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { ExtensionMessageRouter } from './ExtensionMessageRouter'; import { ExtensionPageInjector } from './ExtensionPageInjector'; import { debug } from '../utils/debug'; diff --git a/projects/extension/src/mocks.ts b/projects/extension/src/mocks.ts index 5a9b9069e..e9fea481a 100644 --- a/projects/extension/src/mocks.ts +++ b/projects/extension/src/mocks.ts @@ -8,6 +8,7 @@ import { MessageToManager, MessageFromManager } from '@substrate/connect-extension-protocol'; +import { SmoldotChain } from 'smoldot'; export class MockPort implements chrome.runtime.Port { sender: any; @@ -60,6 +61,10 @@ export class MockConnectionManager implements ConnectionManagerInterface { this.#willFindClient = willFindClient; } + addChain (): Promise { + return Promise.resolve({} as SmoldotChain); + } + registerApp(): void { return; } diff --git a/projects/extension/src/types/index.ts b/projects/extension/src/types/index.ts index 4756231f5..c2d2ed712 100644 --- a/projects/extension/src/types/index.ts +++ b/projects/extension/src/types/index.ts @@ -25,7 +25,6 @@ interface ChainSpec { chainspecPath: string; } export interface Network extends ChainSpec { - idx: number; chain: smoldot.SmoldotChain | undefined; parachains?: Parachain[]; }