From b469663fa9bc551874b83996097ff255226ed443 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Wed, 26 Oct 2022 15:53:13 +0200 Subject: [PATCH] Stop including source code in state (#861) * Stop including sourceCode in state * Fix PR comment --- packages/controllers/jest.config.js | 8 +- .../src/snaps/SnapController.test.ts | 126 ++++++------------ .../controllers/src/snaps/SnapController.ts | 108 ++++++++++----- packages/utils/src/snaps.ts | 12 +- packages/utils/src/test-utils/snap.ts | 40 +++++- 5 files changed, 160 insertions(+), 134 deletions(-) diff --git a/packages/controllers/jest.config.js b/packages/controllers/jest.config.js index 8a3d658734..136310f785 100644 --- a/packages/controllers/jest.config.js +++ b/packages/controllers/jest.config.js @@ -8,10 +8,10 @@ module.exports = { coveragePathIgnorePatterns: ['/node_modules/', '/mocks/', '/test/'], coverageThreshold: { global: { - branches: 85.74, - functions: 95.3, - lines: 94.83, - statements: 94.92, + branches: 86, + functions: 95.33, + lines: 94.88, + statements: 94.98, }, }, projects: [ diff --git a/packages/controllers/src/snaps/SnapController.test.ts b/packages/controllers/src/snaps/SnapController.test.ts index e634d353a5..82a973e090 100644 --- a/packages/controllers/src/snaps/SnapController.test.ts +++ b/packages/controllers/src/snaps/SnapController.test.ts @@ -22,6 +22,7 @@ import { createEngineStream } from 'json-rpc-middleware-stream'; import pump from 'pump'; import { getSnapManifest, + getPersistedSnapObject, getSnapObject, MOCK_ORIGIN, MOCK_SNAP_ID, @@ -29,7 +30,6 @@ import { getMockSnapData, DEFAULT_SNAP_BUNDLE, MOCK_LOCAL_SNAP_ID, - DEFAULT_SNAP_SHASUM, } from '@metamask/snap-utils/test-utils'; import { NodeThreadExecutionService, setupMultiplex } from '../services'; import { delay } from '../utils'; @@ -276,7 +276,7 @@ describe('SnapController', () => { getSnapControllerOptions({ state: { snaps: { - 'npm:foo': getSnapObject({ + 'npm:foo': getPersistedSnapObject({ permissionName: 'fooperm', version: '0.0.1', sourceCode: DEFAULT_SNAP_BUNDLE, @@ -666,7 +666,7 @@ describe('SnapController', () => { getSnapControllerOptions({ messenger }), ); - const snap = await controller.add({ + await controller.add({ origin: MOCK_ORIGIN, id: MOCK_SNAP_ID, manifest: getSnapManifest(), @@ -686,8 +686,9 @@ describe('SnapController', () => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const newSnap = controller.get(MOCK_SNAP_ID)!; - // Notice usage of toBe - we're checking if it's actually the same object, not an equal one - expect(newSnap).toBe(snap); + expect(newSnap).toStrictEqual( + getSnapObject({ status: SnapStatus.Installing }), + ); expect(addSpy).not.toHaveBeenCalled(); expect(authorizeSpy).not.toHaveBeenCalled(); expect(messengerCallMock).toHaveBeenCalledTimes(1); @@ -1387,7 +1388,7 @@ describe('SnapController', () => { }); it('handlers throw if the request has an invalid "jsonrpc" property', async () => { - const fakeSnap = getSnapObject({ status: SnapStatus.Running }); + const fakeSnap = getPersistedSnapObject({ status: SnapStatus.Running }); const snapId = fakeSnap.id; const snapController = getSnapController( getSnapControllerOptions({ @@ -1419,7 +1420,7 @@ describe('SnapController', () => { it('handlers will throw if there are too many pending requests before a snap has started', async () => { const messenger = getSnapControllerMessenger(); - const fakeSnap = getSnapObject({ status: SnapStatus.Stopped }); + const fakeSnap = getPersistedSnapObject({ status: SnapStatus.Stopped }); const snapId = fakeSnap.id; const snapController = getSnapController( getSnapControllerOptions({ @@ -1618,7 +1619,7 @@ describe('SnapController', () => { describe('installSnaps', () => { it('returns existing non-local snaps without reinstalling them', async () => { const messenger = getSnapControllerMessenger(); - const snapObject = getSnapObject(); + const snapObject = getPersistedSnapObject(); const truncatedSnap = getTruncatedSnap(); const snapController = getSnapController( @@ -1658,7 +1659,7 @@ describe('SnapController', () => { it('reinstalls local snaps even if they are already installed (already stopped)', async () => { const messenger = getSnapControllerMessenger(); - const snapObject = getSnapObject({ + const snapObject = getPersistedSnapObject({ id: MOCK_LOCAL_SNAP_ID, }); const truncatedSnap = getTruncatedSnap({ @@ -1968,7 +1969,7 @@ describe('SnapController', () => { const fetchSnapMock = jest .spyOn(snapController as any, '_fetchSnap') .mockImplementationOnce(() => { - return getSnapObject({ manifest }); + return getPersistedSnapObject({ manifest }); }); const result = await snapController.installSnaps(MOCK_ORIGIN, { @@ -2057,7 +2058,7 @@ describe('SnapController', () => { jest .spyOn(snapController as any, '_fetchSnap') .mockImplementationOnce(() => { - return getSnapObject({ manifest }); + return getPersistedSnapObject({ manifest }); }); await snapController.installSnaps(MOCK_ORIGIN, { @@ -2130,7 +2131,7 @@ describe('SnapController', () => { jest .spyOn(snapController as any, '_fetchSnap') .mockImplementationOnce(() => { - return getSnapObject({ manifest }); + return getPersistedSnapObject({ manifest }); }); await snapController.installSnaps(MOCK_ORIGIN, { @@ -2203,7 +2204,7 @@ describe('SnapController', () => { messenger, state: { snaps: { - [MOCK_SNAP_ID]: getSnapObject(), + [MOCK_SNAP_ID]: getPersistedSnapObject(), }, }, }), @@ -2225,7 +2226,7 @@ describe('SnapController', () => { jest .spyOn(snapController as any, '_fetchSnap') .mockImplementationOnce(() => { - return getSnapObject({ manifest }); + return getPersistedSnapObject({ manifest }); }); await snapController.updateSnap(MOCK_ORIGIN, MOCK_SNAP_ID); @@ -2536,7 +2537,7 @@ describe('SnapController', () => { getSnapControllerOptions({ state: { snaps: { - [MOCK_SNAP_ID]: getSnapObject(), + [MOCK_SNAP_ID]: getPersistedSnapObject(), }, }, }), @@ -2558,7 +2559,7 @@ describe('SnapController', () => { checkBlockList: checkBlockListSpy, state: { snaps: { - [MOCK_SNAP_ID]: getSnapObject(), + [MOCK_SNAP_ID]: getPersistedSnapObject(), }, }, }), @@ -3188,10 +3189,8 @@ describe('SnapController', () => { id: MOCK_SNAP_ID, }); expect(result).toStrictEqual( - getSnapObject({ - sourceCode: DEFAULT_SNAP_BUNDLE, + getPersistedSnapObject({ status: SnapStatus.Installing, - manifest: getSnapManifest({ shasum: DEFAULT_SNAP_SHASUM }), }), ); }); @@ -3211,11 +3210,9 @@ describe('SnapController', () => { // Fetch is called 3 times, for fetching the manifest, the sourcecode and icon (icon just has the default response for now) expect(fetchMock).toHaveBeenCalledTimes(3); expect(result).toStrictEqual( - getSnapObject({ + getPersistedSnapObject({ id, - sourceCode: DEFAULT_SNAP_BUNDLE, status: SnapStatus.Installing, - manifest: getSnapManifest(), permissionName: 'wallet_snap_local:https://localhost:8081', }), ); @@ -3228,7 +3225,7 @@ describe('SnapController', () => { getSnapControllerOptions({ state: { snaps: { - [MOCK_SNAP_ID]: { ...getSnapObject(), enabled: false }, + [MOCK_SNAP_ID]: getPersistedSnapObject({ enabled: false }), }, }, }), @@ -3252,11 +3249,10 @@ describe('SnapController', () => { getSnapControllerOptions({ state: { snaps: { - [MOCK_SNAP_ID]: { - ...getSnapObject(), - blocked: true, + [MOCK_SNAP_ID]: getPersistedSnapObject({ enabled: false, - }, + blocked: true, + }), }, }, }), @@ -3274,7 +3270,7 @@ describe('SnapController', () => { getSnapControllerOptions({ state: { snaps: { - [MOCK_SNAP_ID]: { ...getSnapObject(), enabled: true }, + [MOCK_SNAP_ID]: getPersistedSnapObject(), }, }, }), @@ -3291,7 +3287,7 @@ describe('SnapController', () => { getSnapControllerOptions({ state: { snaps: { - [MOCK_SNAP_ID]: { ...getSnapObject(), enabled: true }, + [MOCK_SNAP_ID]: getPersistedSnapObject(), }, }, }), @@ -3617,16 +3613,7 @@ describe('SnapController', () => { }), ); - const fooSnapObject = { - initialPermissions: {}, - permissionName: 'wallet_snap_npm:fooSnap', - version: '1.0.0', - sourceCode: DEFAULT_SNAP_BUNDLE, - id: 'npm:fooSnap', - manifest: getSnapManifest(), - enabled: true, - status: SnapStatus.Installing, - }; + const fooSnapObject = getPersistedSnapObject(); const addSpy = jest.spyOn(snapController, 'add'); const fetchSnapMock = jest @@ -3639,14 +3626,14 @@ describe('SnapController', () => { await messenger.call('SnapController:add', { origin: MOCK_ORIGIN, - id: 'npm:fooSnap', + id: MOCK_SNAP_ID, }); expect(addSpy).toHaveBeenCalledTimes(1); expect(fetchSnapMock).toHaveBeenCalledTimes(1); expect(Object.keys(snapController.state.snaps)).toHaveLength(1); - expect(snapController.state.snaps['npm:fooSnap']).toMatchObject( - fooSnapObject, + expect(snapController.state.snaps[MOCK_SNAP_ID]).toMatchObject( + getSnapObject({ status: SnapStatus.Installing }), ); }); }); @@ -3654,55 +3641,36 @@ describe('SnapController', () => { describe('SnapController:get', () => { it('gets a snap', async () => { const messenger = getSnapControllerMessenger(undefined, false); - const fooSnapObject = getSnapObject({ - permissionName: 'fooperm', - version: '0.0.1', - sourceCode: DEFAULT_SNAP_BUNDLE, - id: 'npm:fooSnap', - manifest: getSnapManifest(), - enabled: true, - status: SnapStatus.Installing, - }); const snapController = getSnapController( getSnapControllerOptions({ messenger, state: { snaps: { - 'npm:fooSnap': fooSnapObject, + [MOCK_SNAP_ID]: getPersistedSnapObject(), }, }, }), ); const getSpy = jest.spyOn(snapController, 'get'); - const result = messenger.call('SnapController:get', 'npm:fooSnap'); + const result = messenger.call('SnapController:get', MOCK_SNAP_ID); expect(getSpy).toHaveBeenCalledTimes(1); - expect(result).toMatchObject(fooSnapObject); + expect(result).toMatchObject(getSnapObject()); }); }); describe('SnapController:handleRequest', () => { it('handles a snap RPC request', async () => { const messenger = getSnapControllerMessenger(undefined, false); - const fooSnapObject = getSnapObject({ - initialPermissions: {}, - permissionName: 'fooperm', - version: '0.0.1', - sourceCode: DEFAULT_SNAP_BUNDLE, - id: 'npm:fooSnap', - manifest: getSnapManifest(), - enabled: true, - status: SnapStatus.Running, - }); const snapController = getSnapController( getSnapControllerOptions({ messenger, state: { snaps: { - 'npm:fooSnap': fooSnapObject, + [MOCK_SNAP_ID]: getPersistedSnapObject(), }, }, }), @@ -3714,7 +3682,7 @@ describe('SnapController', () => { expect( await messenger.call('SnapController:handleRequest', { - snapId: 'npm:fooSnap', + snapId: MOCK_SNAP_ID, handler: HandlerType.OnRpcRequest, origin: 'foo', request: {}, @@ -3726,23 +3694,13 @@ describe('SnapController', () => { it('handles a transaction insight request', async () => { const messenger = getSnapControllerMessenger(undefined, false); - const fooSnapObject = getSnapObject({ - initialPermissions: {}, - permissionName: 'fooperm', - version: '0.0.1', - sourceCode: DEFAULT_SNAP_BUNDLE, - id: 'npm:fooSnap', - manifest: getSnapManifest(), - enabled: true, - status: SnapStatus.Running, - }); const snapController = getSnapController( getSnapControllerOptions({ messenger, state: { snaps: { - 'npm:fooSnap': fooSnapObject, + [MOCK_SNAP_ID]: getPersistedSnapObject(), }, }, }), @@ -3754,7 +3712,7 @@ describe('SnapController', () => { expect( await messenger.call('SnapController:handleRequest', { - snapId: 'npm:fooSnap', + snapId: MOCK_SNAP_ID, handler: HandlerType.OnTransaction, origin: 'foo', request: {}, @@ -3805,7 +3763,7 @@ describe('SnapController', () => { state: { snapStates: { [MOCK_SNAP_ID]: 'foo' }, snaps: { - [MOCK_SNAP_ID]: getSnapObject({ + [MOCK_SNAP_ID]: getPersistedSnapObject({ status: SnapStatus.Installing, }), }, @@ -3832,7 +3790,7 @@ describe('SnapController', () => { messenger, state: { snaps: { - 'npm:fooSnap': getSnapObject({ + 'npm:fooSnap': getPersistedSnapObject({ permissionName: 'fooperm', version: '0.0.1', sourceCode: DEFAULT_SNAP_BUNDLE, @@ -3863,7 +3821,7 @@ describe('SnapController', () => { messenger, state: { snaps: { - 'npm:fooSnap': getSnapObject({ + 'npm:fooSnap': getPersistedSnapObject({ permissionName: 'fooperm', version: '0.0.1', sourceCode: DEFAULT_SNAP_BUNDLE, @@ -3904,7 +3862,7 @@ describe('SnapController', () => { messenger, state: { snaps: { - 'npm:fooSnap': getSnapObject({ + 'npm:fooSnap': getPersistedSnapObject({ permissionName: 'fooperm', version: '0.0.1', sourceCode: DEFAULT_SNAP_BUNDLE, @@ -3913,7 +3871,7 @@ describe('SnapController', () => { enabled: true, status: SnapStatus.Installing, }), - 'npm:fooSnap2': getSnapObject({ + 'npm:fooSnap2': getPersistedSnapObject({ permissionName: 'fooperm2', version: '0.0.1', sourceCode: DEFAULT_SNAP_BUNDLE, @@ -3971,7 +3929,7 @@ describe('SnapController', () => { state: { snapStates: { [MOCK_SNAP_ID]: 'foo' }, snaps: { - [MOCK_SNAP_ID]: getSnapObject({ + [MOCK_SNAP_ID]: getPersistedSnapObject({ status: SnapStatus.Installing, }), }, diff --git a/packages/controllers/src/snaps/SnapController.ts b/packages/controllers/src/snaps/SnapController.ts index f4e364f2db..5f938afad6 100644 --- a/packages/controllers/src/snaps/SnapController.ts +++ b/packages/controllers/src/snaps/SnapController.ts @@ -51,6 +51,7 @@ import { SnapStatus, SnapStatusEvents, assertIsSnapManifest, + PersistedSnap, } from '@metamask/snap-utils'; import { Duration, @@ -113,7 +114,7 @@ export interface SnapRuntimeData { /** * A promise that resolves when the Snap has finished installing */ - installPromise: null | Promise; + installPromise: null | Promise; /** * A Unix timestamp for the last time the Snap received an RPC request @@ -148,6 +149,11 @@ export interface SnapRuntimeData { * @see {@link SnapController:constructor} */ interpreter: StateMachine.Service; + + /** + * The snap source code + */ + sourceCode: null | string; } export type SnapError = { @@ -188,6 +194,10 @@ export type SnapControllerState = { }; }; +export type PersistedSnapControllerState = SnapControllerState & { + snaps: Record; +}; + // Controller Messenger Actions /** @@ -520,7 +530,7 @@ type SnapControllerArgs = { /** * Persisted state that will be used for rehydration. */ - state?: SnapControllerState; + state?: PersistedSnapControllerState; }; type AddSnapArgsBase = { @@ -629,6 +639,19 @@ export class SnapController extends BaseController< fetchFunction = globalThis.fetch.bind(globalThis), featureFlags = {}, }: SnapControllerArgs) { + const loadedSourceCode: Record = {}; + const filteredState = { + ...state, + snaps: Object.values(state?.snaps ?? {}).reduce( + (memo: Record, snap) => { + const { sourceCode, ...rest } = snap; + loadedSourceCode[snap.id] = sourceCode; + memo[snap.id] = rest; + return memo; + }, + {}, + ), + }; super({ messenger, metadata: { @@ -646,6 +669,7 @@ export class SnapController extends BaseController< .map((snap) => { return { ...snap, + sourceCode: this.getRuntimeExpect(snap.id).sourceCode, // At the time state is rehydrated, no snap will be running. status: SnapStatus.Stopped, }; @@ -659,7 +683,7 @@ export class SnapController extends BaseController< }, }, name, - state: { ...defaultState, ...state }, + state: { ...defaultState, ...filteredState }, }); this._closeAllConnections = closeAllConnections; @@ -697,6 +721,10 @@ export class SnapController extends BaseController< this.initializeStateMachine(); this.registerMessageHandlers(); + + Object.entries(loadedSourceCode).forEach(([id, sourceCode]) => + this.setupRuntime(id, sourceCode), + ); } /** @@ -1044,7 +1072,7 @@ export class SnapController extends BaseController< snapId: SnapId, event: StatusEvents | StatusEvents['type'], ) { - const { interpreter } = this.getRuntimeOrDefault(snapId); + const { interpreter } = this.getRuntimeExpect(snapId); interpreter.send(event); this.update((state: any) => { state.snaps[snapId].status = interpreter.state.value; @@ -1058,15 +1086,17 @@ export class SnapController extends BaseController< * @param snapId - The id of the Snap to start. */ async startSnap(snapId: SnapId): Promise { - const snap = this.getExpect(snapId); + const runtime = this.getRuntimeExpect(snapId); if (this.state.snaps[snapId].enabled === false) { throw new Error(`Snap "${snapId}" is disabled.`); } + assert(runtime.sourceCode); + await this._startSnap({ snapId, - sourceCode: snap.sourceCode, + sourceCode: runtime.sourceCode, }); } @@ -1423,7 +1453,7 @@ export class SnapController extends BaseController< * @param snapId - The snap id of the snap that was referenced. */ incrementActiveReferences(snapId: SnapId) { - const runtime = this.getRuntimeOrDefault(snapId); + const runtime = this.getRuntimeExpect(snapId); runtime.activeReferences += 1; } @@ -1433,7 +1463,7 @@ export class SnapController extends BaseController< * @param snapId - The snap id of the snap that was referenced.. */ decrementActiveReferences(snapId: SnapId) { - const runtime = this.getRuntimeOrDefault(snapId); + const runtime = this.getRuntimeExpect(snapId); assert( runtime.activeReferences > 0, 'SnapController reference management is in an invalid state.', @@ -1750,7 +1780,7 @@ export class SnapController extends BaseController< * version. * @returns The resulting snap object. */ - async add(args: AddSnapArgs): Promise { + async add(args: AddSnapArgs): Promise { const { id: snapId } = args; validateSnapId(snapId); @@ -1763,8 +1793,8 @@ export class SnapController extends BaseController< ) { throw new Error(`Invalid add snap args for snap "${snapId}".`); } - - const runtime = this.getRuntimeOrDefault(snapId); + this.setupRuntime(snapId, null); + const runtime = this.getRuntimeExpect(snapId); if (!runtime.installPromise) { console.info(`Adding snap: ${snapId}`); @@ -1894,7 +1924,7 @@ export class SnapController extends BaseController< * @param args - The add snap args. * @returns The resulting snap object. */ - private _set(args: SetSnapArgs): Snap { + private _set(args: SetSnapArgs): PersistedSnap { const { id: snapId, origin, @@ -1955,7 +1985,6 @@ export class SnapController extends BaseController< id: snapId, initialPermissions, manifest, - sourceCode, status: this._statusMachine.config.initial as StatusStates['value'], version, versionHistory, @@ -1968,8 +1997,11 @@ export class SnapController extends BaseController< state.snaps[snapId] = snap; }); + const runtime = this.getRuntimeExpect(snapId); + runtime.sourceCode = sourceCode; + this.messagingSystem.publish(`SnapController:snapAdded`, snap, svgIcon); - return snap; + return { ...snap, sourceCode }; } /** @@ -2215,7 +2247,7 @@ export class SnapController extends BaseController< * @returns The RPC handler for the given snap. */ private async getRpcRequestHandler(snapId: SnapId): Promise { - const runtime = this.getRuntimeOrDefault(snapId); + const runtime = this.getRuntimeExpect(snapId); const existingHandler = runtime.rpcHandler; if (existingHandler) { return existingHandler; @@ -2369,30 +2401,32 @@ export class SnapController extends BaseController< return runtime; } - private getRuntimeOrDefault(snapId: SnapId) { - if (!this._snapsRuntimeData.has(snapId)) { - const snap = this.get(snapId); - const interpreter = interpret(this._statusMachine); - interpreter.start({ - context: { snapId }, - value: - snap?.status ?? - (this._statusMachine.config.initial as StatusStates['value']), - }); + private setupRuntime(snapId: SnapId, sourceCode: string | null) { + if (this._snapsRuntimeData.has(snapId)) { + return; + } - forceStrict(interpreter); + const snap = this.get(snapId); + const interpreter = interpret(this._statusMachine); + interpreter.start({ + context: { snapId }, + value: + snap?.status ?? + (this._statusMachine.config.initial as StatusStates['value']), + }); - this._snapsRuntimeData.set(snapId, { - lastRequest: null, - rpcHandler: null, - installPromise: null, - activeReferences: 0, - pendingInboundRequests: [], - pendingOutboundRequests: 0, - interpreter, - }); - } - return this.getRuntimeExpect(snapId); + forceStrict(interpreter); + + this._snapsRuntimeData.set(snapId, { + lastRequest: null, + rpcHandler: null, + installPromise: null, + activeReferences: 0, + pendingInboundRequests: [], + pendingOutboundRequests: 0, + interpreter, + sourceCode, + }); } private async calculatePermissionsChange( diff --git a/packages/utils/src/snaps.ts b/packages/utils/src/snaps.ts index f99752cfb4..861d4237e8 100644 --- a/packages/utils/src/snaps.ts +++ b/packages/utils/src/snaps.ts @@ -62,6 +62,13 @@ export type VersionHistory = { date: number; }; +export type PersistedSnap = Snap & { + /** + * The source code of the Snap. + */ + sourceCode: string; +}; + /** * A Snap as it exists in {@link SnapController} state. */ @@ -102,11 +109,6 @@ export type Snap = { */ permissionName: string; - /** - * The source code of the Snap. - */ - sourceCode: string; - /** * The current status of the Snap, e.g. whether it's running or stopped. */ diff --git a/packages/utils/src/test-utils/snap.ts b/packages/utils/src/test-utils/snap.ts index 1fdc49f13a..603efc078a 100644 --- a/packages/utils/src/test-utils/snap.ts +++ b/packages/utils/src/test-utils/snap.ts @@ -1,4 +1,10 @@ -import { getSnapSourceShasum, Snap, SnapStatus, TruncatedSnap } from '../snaps'; +import { + getSnapSourceShasum, + PersistedSnap, + Snap, + SnapStatus, + TruncatedSnap, +} from '../snaps'; import { getSnapManifest } from './manifest'; /** @@ -21,7 +27,7 @@ export const MOCK_SNAP_ID = 'npm:@metamask/example-snap'; export const MOCK_LOCAL_SNAP_ID = 'local:@metamask/example-snap'; export const MOCK_ORIGIN = 'example.com'; -export const getSnapObject = ({ +export const getPersistedSnapObject = ({ blocked = false, enabled = true, id = MOCK_SNAP_ID, @@ -34,7 +40,7 @@ export const getSnapObject = ({ versionHistory = [ { origin: MOCK_ORIGIN, version: '1.0.0', date: expect.any(Number) }, ], -}: Partial = {}): Snap => { +}: Partial = {}): PersistedSnap => { return { blocked, initialPermissions, @@ -49,6 +55,32 @@ export const getSnapObject = ({ } as const; }; +export const getSnapObject = ({ + blocked = false, + enabled = true, + id = MOCK_SNAP_ID, + initialPermissions = getSnapManifest().initialPermissions, + manifest = getSnapManifest(), + permissionName = `wallet_snap_${id}`, + status = SnapStatus.Stopped, + version = getSnapManifest().version, + versionHistory = [ + { origin: MOCK_ORIGIN, version: '1.0.0', date: expect.any(Number) }, + ], +}: Partial = {}): Snap => { + return { + blocked, + initialPermissions, + id, + permissionName, + version, + manifest, + status, + enabled, + versionHistory, + } as const; +}; + export const getTruncatedSnap = ({ initialPermissions = getSnapManifest().initialPermissions, id = MOCK_SNAP_ID, @@ -110,7 +142,7 @@ export const getMockSnapData = ({ shasum: DEFAULT_SNAP_SHASUM, sourceCode, manifest, - stateObject: getSnapObject({ + stateObject: getPersistedSnapObject({ blocked, enabled, id,