Skip to content
This repository has been archived by the owner on Oct 7, 2024. It is now read-only.

feat: add InternalAccount type and create submodule internal #65

Merged
merged 6 commits into from
Aug 24, 2023
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
4 changes: 2 additions & 2 deletions src/KeyringClient.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
type KeyringAccount,
type KeyringRequest,
type SubmitRequestResponse,
type KeyringResponse,
KeyringClient,
} from '.'; // Import from `index.ts` to test the public API

Expand Down Expand Up @@ -225,7 +225,7 @@ describe('KeyringClient', () => {
params: ['0xe9a74aacd7df8112911ca93260fc5a046f8a64ae', '0x0'],
},
};
const expectedResponse: SubmitRequestResponse = {
const expectedResponse: KeyringResponse = {
pending: true,
};

Expand Down
41 changes: 20 additions & 21 deletions src/KeyringClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import type { Json } from '@metamask/utils';
import { assert } from 'superstruct';
import { v4 as uuid } from 'uuid';

import type { Keyring, KeyringAccount, KeyringRequest } from './api';
import type {
Keyring,
KeyringAccount,
KeyringRequest,
KeyringAccountData,
KeyringResponse,
} from './api';
import {
ApproveRequestResponseStruct,
CreateAccountResponseStruct,
Expand All @@ -15,17 +21,13 @@ import {
ListRequestsResponseStruct,
RejectRequestResponseStruct,
SubmitRequestResponseStruct,
type ExportAccountResponse,
type InternalRequest,
type InternalResponse,
type SubmitRequestResponse,
UpdateAccountResponseStruct,
InternalResponseStruct,
} from './internal-api';
} from './internal/api';
import type { JsonRpcRequest } from './JsonRpcRequest';
import { type OmitUnion, strictMask } from './utils';

export type Sender = {
send(request: InternalRequest): Promise<InternalResponse>;
send(request: JsonRpcRequest): Promise<Json>;
};

export class KeyringClient implements Keyring {
Expand All @@ -43,20 +45,17 @@ export class KeyringClient implements Keyring {
/**
* Send a request to the snap and return the response.
*
* @param partial - Partial internal request (method and params).
* @param partial - A partial JSON-RPC request (method and params).
* @returns A promise that resolves to the response to the request.
*/
async #send(
partial: OmitUnion<InternalRequest, 'jsonrpc' | 'id'>,
): Promise<InternalResponse> {
return strictMask(
await this.#sender.send({
jsonrpc: '2.0',
id: uuid(),
...partial,
}),
InternalResponseStruct,
);
partial: OmitUnion<JsonRpcRequest, 'jsonrpc' | 'id'>,
): Promise<Json> {
return this.#sender.send({
jsonrpc: '2.0',
id: uuid(),
...partial,
});
}

async listAccounts(): Promise<KeyringAccount[]> {
Expand Down Expand Up @@ -120,7 +119,7 @@ export class KeyringClient implements Keyring {
);
}

async exportAccount(id: string): Promise<ExportAccountResponse> {
async exportAccount(id: string): Promise<KeyringAccountData> {
return strictMask(
await this.#send({
method: 'keyring_exportAccount',
Expand Down Expand Up @@ -149,7 +148,7 @@ export class KeyringClient implements Keyring {
);
}

async submitRequest(request: KeyringRequest): Promise<SubmitRequestResponse> {
async submitRequest(request: KeyringRequest): Promise<KeyringResponse> {
return strictMask(
await this.#send({
method: 'keyring_submitRequest',
Expand Down
11 changes: 5 additions & 6 deletions src/KeyringSnapControllerClient.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { SnapController } from '@metamask/snaps-controllers';
import type { HandlerType, ValidatedSnapId } from '@metamask/snaps-utils';
import type { Json } from '@metamask/utils';

import type { InternalRequest, InternalResponse } from './internal-api';
import type { JsonRpcRequest } from './JsonRpcRequest';
import { KeyringClient, type Sender } from './KeyringClient';

/**
Expand Down Expand Up @@ -43,15 +44,13 @@ class SnapControllerSender implements Sender {
* @param request - JSON-RPC request to send to the snap.
* @returns A promise that resolves to the response of the request.
*/
async send(request: InternalRequest): Promise<InternalResponse> {
const response = await this.#controller.handleRequest({
async send(request: JsonRpcRequest): Promise<Json> {
return this.#controller.handleRequest({
snapId: this.#snapId as ValidatedSnapId,
origin: this.#origin,
handler: this.#handler,
request,
});

return response as InternalResponse;
}) as Promise<Json>;
}
}

Expand Down
11 changes: 5 additions & 6 deletions src/KeyringSnapRpcClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { MetaMaskInpageProvider } from '@metamask/providers';
import type { Json } from '@metamask/utils';

import type { InternalRequest, InternalResponse } from './internal-api';
import type { JsonRpcRequest } from './JsonRpcRequest';
import { KeyringClient, type Sender } from './KeyringClient';

/**
Expand Down Expand Up @@ -29,16 +30,14 @@ export class SnapRpcSender implements Sender {
* @param request - The JSON-RPC request to send to the snap.
* @returns A promise that resolves to the response of the request.
*/
async send(request: InternalRequest): Promise<InternalResponse> {
const response = await this.#provider.request({
async send(request: JsonRpcRequest): Promise<Json> {
return this.#provider.request({
method: 'wallet_invokeSnap',
params: {
snapId: this.#origin,
request,
},
});

return response as InternalResponse;
}) as Promise<Json>;
}
}

Expand Down
52 changes: 40 additions & 12 deletions src/api.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { type Json, JsonStruct } from '@metamask/utils';
import { object, string, enums, record, array, type Infer } from 'superstruct';
import {
type Infer,
array,
enums,
literal,
object,
record,
string,
union,
} from 'superstruct';

import type {
ExportAccountResponse,
SubmitRequestResponse,
} from './internal-api';
import { JsonRpcRequestStruct } from './JsonRpcRequest';
import { UuidStruct } from './utils';

export type {
ExportAccountResponse,
SubmitRequestResponse,
} from './internal-api';

/**
* Supported Ethereum methods.
*/
Expand Down Expand Up @@ -104,6 +104,34 @@ export const KeyringRequestStruct = object({
*/
export type KeyringRequest = Infer<typeof KeyringRequestStruct>;

export const KeyringAccountDataStruct = record(string(), JsonStruct);

/**
* Response to a call to `exportAccount`.
*
* The exact response depends on the keyring implementation.
*/
export type KeyringAccountData = Infer<typeof KeyringAccountDataStruct>;

export const KeyringResponseStruct = union([
object({
pending: literal(true),
}),
object({
pending: literal(false),
result: JsonStruct,
}),
]);

/**
* Response to a call to `submitRequest`.
*
* Keyring implementations must return a response with `pending: true` if the
* request will be handled asynchronously. Otherwise, the response must contain
* the result of the request and `pending: false`.
*/
export type KeyringResponse = Infer<typeof KeyringResponseStruct>;

/**
* Keyring interface.
*
Expand Down Expand Up @@ -183,7 +211,7 @@ export type Keyring = {
* @param id - The ID of the account to export.
* @returns A promise that resolves to the exported account.
*/
exportAccount(id: string): Promise<ExportAccountResponse>;
exportAccount(id: string): Promise<KeyringAccountData>;

/**
* List all submitted requests.
Expand Down Expand Up @@ -214,7 +242,7 @@ export type Keyring = {
* @param request - The KeyringRequest object to submit.
* @returns A promise that resolves to the request response.
*/
submitRequest(request: KeyringRequest): Promise<SubmitRequestResponse>;
submitRequest(request: KeyringRequest): Promise<KeyringResponse>;

/**
* Approve a request.
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './KeyringClient';
export * from './rpc-handler';
export * from './KeyringSnapControllerClient';
export * from './KeyringSnapRpcClient';
export * from './internal';
gantunesr marked this conversation as resolved.
Show resolved Hide resolved
62 changes: 9 additions & 53 deletions src/internal-api.ts → src/internal/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import {
object,
record,
string,
union,
type Infer,
} from 'superstruct';

import { KeyringAccountStruct, KeyringRequestStruct } from './api';
import { UuidStruct } from './utils';
import {
KeyringAccountDataStruct,
KeyringAccountStruct,
KeyringRequestStruct,
KeyringResponseStruct,
} from '../api';
import { UuidStruct } from '../utils';

const CommonHeader = {
jsonrpc: literal('2.0'),
Expand Down Expand Up @@ -134,7 +138,7 @@ export const ExportAccountRequestStruct = object({

export type ExportAccountRequest = Infer<typeof ExportAccountRequestStruct>;

export const ExportAccountResponseStruct = record(string(), JsonStruct);
export const ExportAccountResponseStruct = KeyringAccountDataStruct;

export type ExportAccountResponse = Infer<typeof ExportAccountResponseStruct>;

Expand Down Expand Up @@ -180,15 +184,7 @@ export const SubmitRequestRequestStruct = object({

export type SubmitRequestRequest = Infer<typeof SubmitRequestRequestStruct>;

export const SubmitRequestResponseStruct = union([
object({
pending: literal(true),
}),
object({
pending: literal(false),
result: JsonStruct,
}),
]);
export const SubmitRequestResponseStruct = KeyringResponseStruct;

export type SubmitRequestResponse = Infer<typeof SubmitRequestResponseStruct>;

Expand Down Expand Up @@ -226,43 +222,3 @@ export type RejectRequestRequest = Infer<typeof RejectRequestRequestStruct>;
export const RejectRequestResponseStruct = literal(null);

export type RejectRequestResponse = Infer<typeof RejectRequestResponseStruct>;

// ----------------------------------------------------------------------------
// Internal request

export const InternalRequestStruct = union([
ListAccountsRequestStruct,
GetAccountRequestStruct,
CreateAccountRequestStruct,
FilterAccountChainsStruct,
UpdateAccountRequestStruct,
DeleteAccountRequestStruct,
ExportAccountRequestStruct,
ListRequestsRequestStruct,
GetRequestRequestStruct,
SubmitRequestRequestStruct,
ApproveRequestRequestStruct,
RejectRequestRequestStruct,
]);

export type InternalRequest = Infer<typeof InternalRequestStruct>;

// ----------------------------------------------------------------------------
// Internal response

export const InternalResponseStruct = union([
ListAccountsResponseStruct,
GetAccountResponseStruct,
CreateAccountResponseStruct,
FilterAccountChainsResponseStruct,
UpdateAccountResponseStruct,
DeleteAccountResponseStruct,
ExportAccountResponseStruct,
ListRequestsResponseStruct,
GetRequestResponseStruct,
SubmitRequestResponseStruct,
ApproveRequestResponseStruct,
RejectRequestResponseStruct,
]);

export type InternalResponse = Infer<typeof InternalResponseStruct>;
2 changes: 2 additions & 0 deletions src/internal/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './api';
export * from './types';
Loading