Skip to content

Commit

Permalink
wip: Add DeviceController
Browse files Browse the repository at this point in the history
  • Loading branch information
FrederikBolding committed Oct 9, 2024
1 parent 24319a4 commit 54a9165
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 0 deletions.
90 changes: 90 additions & 0 deletions packages/snaps-controllers/src/devices/DeviceController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import type {
RestrictedControllerMessenger,
ControllerGetStateAction,
ControllerStateChangeEvent,
} from '@metamask/base-controller';
import { BaseController } from '@metamask/base-controller';
import type { GetPermissions } from '@metamask/permission-controller';

import type { DeleteInterface } from '../interface';
import type { GetAllSnaps, HandleSnapRequest } from '../snaps';
import type {
TransactionControllerUnapprovedTransactionAddedEvent,
SignatureStateChange,
TransactionControllerTransactionStatusUpdatedEvent,
} from '../types';

const controllerName = 'DeviceController';

export type DeviceControllerAllowedActions =
| HandleSnapRequest
| GetAllSnaps
| GetPermissions
| DeleteInterface;

export type DeviceControllerGetStateAction = ControllerGetStateAction<
typeof controllerName,
DeviceControllerState
>;

export type DeviceControllerActions = DeviceControllerGetStateAction;

export type DeviceControllerStateChangeEvent = ControllerStateChangeEvent<
typeof controllerName,
DeviceControllerState
>;

export type DeviceControllerEvents = DeviceControllerStateChangeEvent;

export type DeviceControllerAllowedEvents =
| TransactionControllerUnapprovedTransactionAddedEvent
| TransactionControllerTransactionStatusUpdatedEvent
| SignatureStateChange;

export type DeviceControllerMessenger = RestrictedControllerMessenger<
typeof controllerName,
DeviceControllerActions | DeviceControllerAllowedActions,
DeviceControllerEvents | DeviceControllerAllowedEvents,
DeviceControllerAllowedActions['type'],
DeviceControllerAllowedEvents['type']
>;

export type Device = {};

export type DeviceControllerState = {
devices: Record<string, Device>;
};

export type DeviceControllerArgs = {
messenger: DeviceControllerMessenger;
state?: DeviceControllerState;
};
/**
* Controller for managing access to devices for Snaps.
*/
export class DeviceController extends BaseController<
typeof controllerName,
DeviceControllerState,
DeviceControllerMessenger
> {
constructor({ messenger, state }: DeviceControllerArgs) {
super({
messenger,
metadata: {
devices: { persist: true, anonymous: false },
},
name: controllerName,
state: { ...state, devices: {} },
});
}

async requestDevices() {
const devices = await (navigator as any).hid.requestDevice({ filters: [] });
return devices;
}

async getDevices() {
const devices = await (navigator as any).hid.getDevices();
return devices;
}
}
1 change: 1 addition & 0 deletions packages/snaps-controllers/src/devices/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './DeviceController';
1 change: 1 addition & 0 deletions packages/snaps-controllers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './utils';
export * from './cronjob';
export * from './interface';
export * from './insights';
export * from './devices';
3 changes: 3 additions & 0 deletions packages/snaps-rpc-methods/src/permitted/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createInterfaceHandler } from './createInterface';
import { providerRequestHandler } from './experimentalProviderRequest';
import { providerRequestHandler as requestDeviceHandler } from './requestDevice';
import { getAllSnapsHandler } from './getAllSnaps';
import { getClientStatusHandler } from './getClientStatus';
import { getCurrencyRateHandler } from './getCurrencyRate';
Expand All @@ -12,6 +13,7 @@ import { requestSnapsHandler } from './requestSnaps';
import { resolveInterfaceHandler } from './resolveInterface';
import { updateInterfaceHandler } from './updateInterface';


/* eslint-disable @typescript-eslint/naming-convention */
export const methodHandlers = {
wallet_getAllSnaps: getAllSnapsHandler,
Expand All @@ -27,6 +29,7 @@ export const methodHandlers = {
snap_resolveInterface: resolveInterfaceHandler,
snap_getCurrencyRate: getCurrencyRateHandler,
snap_experimentalProviderRequest: providerRequestHandler,
snap_requestDevice: requestDeviceHandler,
};
/* eslint-enable @typescript-eslint/naming-convention */

Expand Down
65 changes: 65 additions & 0 deletions packages/snaps-rpc-methods/src/permitted/requestDevice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { JsonRpcEngineEndCallback } from '@metamask/json-rpc-engine';
import type { PermittedHandlerExport } from '@metamask/permission-controller';
import type {
JsonRpcRequest,
ProviderRequestParams,
ProviderRequestResult,
} from '@metamask/snaps-sdk';
import { type InferMatching } from '@metamask/snaps-utils';
import { object, optional, string, type } from '@metamask/superstruct';
import {
type PendingJsonRpcResponse,
CaipChainIdStruct,
JsonRpcParamsStruct,
} from '@metamask/utils';

import type { MethodHooksObject } from '../utils';

const hookNames: MethodHooksObject<ProviderRequestMethodHooks> = {
requestDevices: true,
};

export type ProviderRequestMethodHooks = {
requestDevices: () => any;
};

export const providerRequestHandler: PermittedHandlerExport<
ProviderRequestMethodHooks,
ProviderRequestParameters,
ProviderRequestResult
> = {
methodNames: ['snap_requestDevice'],
implementation: providerRequestImplementation,
hookNames,
};

const ProviderRequestParametersStruct = object({
chainId: CaipChainIdStruct,
request: type({
method: string(),
params: optional(JsonRpcParamsStruct),
}),
});

export type ProviderRequestParameters = InferMatching<
typeof ProviderRequestParametersStruct,
ProviderRequestParams
>;

async function providerRequestImplementation(
req: JsonRpcRequest<ProviderRequestParams>,
res: PendingJsonRpcResponse<ProviderRequestResult>,
_next: unknown,
end: JsonRpcEngineEndCallback,
{ requestDevices }: ProviderRequestMethodHooks,
): Promise<void> {
const { params } = req;

try {
res.result = await requestDevices();
} catch (error) {
return end(error);
}

return end();
}

0 comments on commit 54a9165

Please sign in to comment.