Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/snaps-controllers/coverage.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"branches": 93.67,
"functions": 98.16,
"branches": 93.68,
"functions": 98.17,
"lines": 98.51,
"statements": 98.34
"statements": 98.35
}
109 changes: 109 additions & 0 deletions packages/snaps-controllers/src/snaps/SnapController.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11581,4 +11581,113 @@ describe('SnapController', () => {
snapController.destroy();
});
});

describe('SnapController:isMinimumPlatformVersion', () => {
it('returns true if the platform version is equal to the specified version', async () => {
const messenger = getSnapControllerMessenger();

const manifest = getSnapManifest({
platformVersion: '6.0.0' as SemVerVersion,
});

const snapController = getSnapController(
getSnapControllerOptions({
messenger,
state: {
snaps: getPersistedSnapsState(getPersistedSnapObject({ manifest })),
},
}),
);

expect(
messenger.call(
'SnapController:isMinimumPlatformVersion',
MOCK_SNAP_ID,
manifest.platformVersion as SemVerVersion,
),
).toBe(true);

snapController.destroy();
});

it('returns true if the platform version is greater than the specified version', async () => {
const messenger = getSnapControllerMessenger();

const manifest = getSnapManifest({
platformVersion: '6.0.0' as SemVerVersion,
});

const snapController = getSnapController(
getSnapControllerOptions({
messenger,
state: {
snaps: getPersistedSnapsState(getPersistedSnapObject({ manifest })),
},
}),
);

expect(
messenger.call(
'SnapController:isMinimumPlatformVersion',
MOCK_SNAP_ID,
'1.0.0' as SemVerVersion,
),
).toBe(true);

snapController.destroy();
});

it('returns false if the platform version is lesser than the specified version', async () => {
const messenger = getSnapControllerMessenger();

const manifest = getSnapManifest({
platformVersion: '6.0.0' as SemVerVersion,
});

const snapController = getSnapController(
getSnapControllerOptions({
messenger,
state: {
snaps: getPersistedSnapsState(getPersistedSnapObject({ manifest })),
},
}),
);

expect(
messenger.call(
'SnapController:isMinimumPlatformVersion',
MOCK_SNAP_ID,
'7.0.0' as SemVerVersion,
),
).toBe(false);

snapController.destroy();
});

it('returns false if the platformVersion is undefined', async () => {
const messenger = getSnapControllerMessenger();

const manifest = getSnapManifest();
delete manifest.platformVersion;

const snapController = getSnapController(
getSnapControllerOptions({
messenger,
state: {
snaps: getPersistedSnapsState(getPersistedSnapObject({ manifest })),
},
}),
);

expect(
messenger.call(
'SnapController:isMinimumPlatformVersion',
MOCK_SNAP_ID,
'999.0.0' as SemVerVersion,
),
).toBe(false);

snapController.destroy();
});
});
});
36 changes: 34 additions & 2 deletions packages/snaps-controllers/src/snaps/SnapController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ import type {
CaipAssetType,
JsonRpcRequest,
Hex,
SemVerVersion,
} from '@metamask/utils';
import {
hexToNumber,
Expand All @@ -134,7 +135,7 @@ import { createMachine, interpret } from '@xstate/fsm';
import { Mutex } from 'async-mutex';
import type { Patch } from 'immer';
import { nanoid } from 'nanoid';
import { gt } from 'semver';
import { gt, gte } from 'semver';

import {
ALLOWED_PERMISSIONS,
Expand Down Expand Up @@ -462,6 +463,11 @@ export type GetSnapFile = {
handler: SnapController['getSnapFile'];
};

export type IsMinimumPlatformVersion = {
type: `${typeof controllerName}:isMinimumPlatformVersion`;
handler: SnapController['isMinimumPlatformVersion'];
};

export type SnapControllerGetStateAction = ControllerGetStateAction<
typeof controllerName,
SnapControllerState
Expand All @@ -488,7 +494,8 @@ export type SnapControllerActions =
| RevokeDynamicPermissions
| GetSnapFile
| SnapControllerGetStateAction
| StopAllSnaps;
| StopAllSnaps
| IsMinimumPlatformVersion;

// Controller Messenger Events

Expand Down Expand Up @@ -1256,6 +1263,11 @@ export class SnapController extends BaseController<
`${controllerName}:stopAllSnaps`,
async (...args) => this.stopAllSnaps(...args),
);

this.messagingSystem.registerActionHandler(
`${controllerName}:isMinimumPlatformVersion`,
(...args) => this.isMinimumPlatformVersion(...args),
);
}

#handlePreinstalledSnaps(preinstalledSnaps: PreinstalledSnap[]) {
Expand Down Expand Up @@ -2178,6 +2190,26 @@ export class SnapController extends BaseController<
return encoded;
}

/**
* Determine if a given Snap ID supports a given minimum version of the Snaps platform
* by inspecting the platformVersion in the Snap manifest.
*
* @param snapId - The Snap ID.
* @param version - The version.
* @returns True if the platform version is equal or greater to the passed version, false otherwise.
*/
isMinimumPlatformVersion(snapId: SnapId, version: SemVerVersion): boolean {
const snap = this.getExpect(snapId);

const { platformVersion } = snap.manifest;

if (!platformVersion) {
return false;
}

return gte(platformVersion, version);
}

/**
* Completely clear the controller's state: delete all associated data,
* handlers, event listeners, and permissions; tear down all snap providers.
Expand Down
Loading