From 045bedb811e141fa63f56a69ca02031d88a3f9e3 Mon Sep 17 00:00:00 2001 From: cryptodev-2s <109512101+cryptodev-2s@users.noreply.github.com> Date: Sat, 18 Mar 2023 00:41:53 +0100 Subject: [PATCH] Convert the ENS controller to the BaseController v2 API (#1134) Convert the ENS controller to the BaseController v2 API --- .../ens-controller/src/EnsController.test.ts | 104 +++++++++++++++--- packages/ens-controller/src/EnsController.ts | 100 +++++++++++------ 2 files changed, 152 insertions(+), 52 deletions(-) diff --git a/packages/ens-controller/src/EnsController.test.ts b/packages/ens-controller/src/EnsController.test.ts index db1fbdaa51..d21cd37eca 100644 --- a/packages/ens-controller/src/EnsController.test.ts +++ b/packages/ens-controller/src/EnsController.test.ts @@ -1,3 +1,4 @@ +import { ControllerMessenger } from '@metamask/base-controller'; import { toChecksumHexAddress } from '@metamask/controller-utils'; import { EnsController } from './EnsController'; @@ -11,14 +12,33 @@ const address1Checksum = toChecksumHexAddress(address1); const address2Checksum = toChecksumHexAddress(address2); const address3Checksum = toChecksumHexAddress(address3); +const name = 'EnsController'; + +/** + * Constructs a restricted controller messenger. + * + * @returns A restricted controller messenger. + */ +function getMessenger() { + return new ControllerMessenger().getRestricted({ + name, + }); +} + describe('EnsController', () => { it('should set default state', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.state).toStrictEqual({ ensEntries: {} }); }); it('should add a new ENS entry and return true', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, address1)).toStrictEqual(true); expect(controller.state).toStrictEqual({ ensEntries: { @@ -34,7 +54,10 @@ describe('EnsController', () => { }); it('should add a new ENS entry with null address and return true', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, null)).toStrictEqual(true); expect(controller.state).toStrictEqual({ ensEntries: { @@ -50,7 +73,10 @@ describe('EnsController', () => { }); it('should update an ENS entry and return true', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, address1)).toStrictEqual(true); expect(controller.set('1', name1, address2)).toStrictEqual(true); expect(controller.state).toStrictEqual({ @@ -67,7 +93,10 @@ describe('EnsController', () => { }); it('should update an ENS entry with null address and return true', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, address1)).toStrictEqual(true); expect(controller.set('1', name1, null)).toStrictEqual(true); expect(controller.state).toStrictEqual({ @@ -84,7 +113,10 @@ describe('EnsController', () => { }); it('should not update an ENS entry if the address is the same (valid address) and return false', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, address1)).toStrictEqual(true); expect(controller.set('1', name1, address1)).toStrictEqual(false); expect(controller.state).toStrictEqual({ @@ -101,7 +133,10 @@ describe('EnsController', () => { }); it('should not update an ENS entry if the address is the same (null) and return false', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, null)).toStrictEqual(true); expect(controller.set('1', name1, null)).toStrictEqual(false); expect(controller.state).toStrictEqual({ @@ -118,7 +153,10 @@ describe('EnsController', () => { }); it('should add multiple ENS entries and update without side effects', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, address1)).toStrictEqual(true); expect(controller.set('1', name2, address2)).toStrictEqual(true); expect(controller.set('2', name1, address1)).toStrictEqual(true); @@ -149,7 +187,10 @@ describe('EnsController', () => { }); it('should get ENS entry by chainId and ensName', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, address1)).toStrictEqual(true); expect(controller.get('1', name1)).toStrictEqual({ address: address1Checksum, @@ -159,19 +200,28 @@ describe('EnsController', () => { }); it('should return null when getting nonexistent name', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, address1)).toStrictEqual(true); expect(controller.get('1', name2)).toBeNull(); }); it('should return null when getting nonexistent chainId', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, address1)).toStrictEqual(true); expect(controller.get('2', name1)).toBeNull(); }); it('should throw on attempt to set invalid ENS entry: chainId', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(() => { controller.set('a', name1, address1); }).toThrow( @@ -181,7 +231,10 @@ describe('EnsController', () => { }); it('should throw on attempt to set invalid ENS entry: ENS name', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(() => { controller.set('1', 'foo.eth', address1); }).toThrow('Invalid ENS name: foo.eth'); @@ -189,7 +242,10 @@ describe('EnsController', () => { }); it('should throw on attempt to set invalid ENS entry: address', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(() => { controller.set('1', name1, 'foo'); }).toThrow( @@ -199,14 +255,20 @@ describe('EnsController', () => { }); it('should remove an ENS entry and return true', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, address1)).toStrictEqual(true); expect(controller.delete('1', name1)).toStrictEqual(true); expect(controller.state).toStrictEqual({ ensEntries: {} }); }); it('should return false if an ENS entry was NOT deleted', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); controller.set('1', name1, address1); expect(controller.delete('1', 'bar')).toStrictEqual(false); expect(controller.delete('2', 'bar')).toStrictEqual(false); @@ -224,7 +286,10 @@ describe('EnsController', () => { }); it('should add multiple ENS entries and remove without side effects', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, address1)).toStrictEqual(true); expect(controller.set('1', name2, address2)).toStrictEqual(true); expect(controller.set('2', name1, address1)).toStrictEqual(true); @@ -250,7 +315,10 @@ describe('EnsController', () => { }); it('should clear all ENS entries', () => { - const controller = new EnsController(); + const messenger = getMessenger(); + const controller = new EnsController({ + messenger, + }); expect(controller.set('1', name1, address1)).toStrictEqual(true); expect(controller.set('1', name2, address2)).toStrictEqual(true); expect(controller.set('2', name1, address1)).toStrictEqual(true); diff --git a/packages/ens-controller/src/EnsController.ts b/packages/ens-controller/src/EnsController.ts index be98d5751f..937ecac091 100644 --- a/packages/ens-controller/src/EnsController.ts +++ b/packages/ens-controller/src/EnsController.ts @@ -1,7 +1,6 @@ import { - BaseController, - BaseConfig, - BaseState, + BaseControllerV2, + RestrictedControllerMessenger, } from '@metamask/base-controller'; import { normalizeEnsName, @@ -9,6 +8,8 @@ import { toChecksumHexAddress, } from '@metamask/controller-utils'; +const name = 'EnsController'; + /** * @type EnsEntry * @@ -17,51 +18,83 @@ import { * @property ensName - The ENS name * @property address - Hex address with the ENS name, or null */ -export interface EnsEntry { +export type EnsEntry = { chainId: string; ensName: string; address: string | null; -} +}; /** - * @type EnsState + * @type EnsControllerState * * ENS controller state * @property ensEntries - Object of ENS entry objects */ -export interface EnsState extends BaseState { - ensEntries: { [chainId: string]: { [ensName: string]: EnsEntry } }; -} +export type EnsControllerState = { + ensEntries: { + [chainId: string]: { + [ensName: string]: EnsEntry; + }; + }; +}; + +export type EnsControllerMessenger = RestrictedControllerMessenger< + typeof name, + never, + never, + never, + never +>; + +const metadata = { + ensEntries: { persist: true, anonymous: false }, +}; + +const defaultState = { + ensEntries: {}, +}; /** * Controller that manages a list ENS names and their resolved addresses * by chainId. A null address indicates an unresolved ENS name. */ -export class EnsController extends BaseController { - /** - * Name of this controller used during composition - */ - override name = 'EnsController'; - +export class EnsController extends BaseControllerV2< + typeof name, + EnsControllerState, + EnsControllerMessenger +> { /** * Creates an EnsController instance. * - * @param config - Initial options used to configure this controller. - * @param state - Initial state to set on this controller. + * @param options - Constructor options. + * @param options.messenger - A reference to the messaging system. + * @param options.state - Initial state to set on this controller. */ - constructor(config?: Partial, state?: Partial) { - super(config, state); - - this.defaultState = { ensEntries: {} }; - - this.initialize(); + constructor({ + messenger, + state, + }: { + messenger: EnsControllerMessenger; + state?: Partial; + }) { + super({ + name, + metadata, + messenger, + state: { + ...defaultState, + ...state, + }, + }); } /** * Remove all chain Ids and ENS entries from state. */ clear() { - this.update({ ensEntries: {} }); + this.update((state) => { + state.ensEntries = {}; + }); } /** @@ -81,14 +114,13 @@ export class EnsController extends BaseController { return false; } - const ensEntries = Object.assign({}, this.state.ensEntries); - delete ensEntries[chainId][normalizedEnsName]; + this.update((state) => { + delete state.ensEntries[chainId][normalizedEnsName]; - if (Object.keys(ensEntries[chainId]).length === 0) { - delete ensEntries[chainId]; - } - - this.update({ ensEntries }); + if (Object.keys(state.ensEntries[chainId]).length === 0) { + delete state.ensEntries[chainId]; + } + }); return true; } @@ -146,8 +178,8 @@ export class EnsController extends BaseController { return false; } - this.update({ - ensEntries: { + this.update((state) => { + state.ensEntries = { ...this.state.ensEntries, [chainId]: { ...this.state.ensEntries[chainId], @@ -157,7 +189,7 @@ export class EnsController extends BaseController { ensName: normalizedEnsName, }, }, - }, + }; }); return true; }