From 0c2802362c1d0f2f2536a37217a09285d6ec56dd Mon Sep 17 00:00:00 2001 From: Albert Olive Date: Thu, 10 Oct 2024 11:43:32 +0200 Subject: [PATCH 1/5] feat: added export state log feature --- packages/custodyController/src/custody.ts | 38 ++++++++++++++++++- packages/custodyKeyring/src/CustodyKeyring.ts | 8 ++++ .../custodyKeyring/src/constants/index.ts | 1 + packages/custodyKeyring/src/index.ts | 1 + .../src/interfaces/IApiCallLogEntry.ts | 8 ++++ packages/sdk/src/classes/MMISDK.ts | 11 +++++- packages/sdk/src/constants/constants.ts | 1 + .../src/custodianApi/eca3/ECA3CustodianApi.ts | 14 +++++-- .../custodianApi/json-rpc/JsonRpcClient.ts | 23 ++++++++++- .../json-rpc/JsonRpcCustodianApi.ts | 11 +++++- .../json-rpc/util/json-rpc-call.test.ts | 4 +- .../json-rpc/util/json-rpc-call.ts | 23 ++++++++++- packages/sdk/src/index.ts | 1 + 13 files changed, 131 insertions(+), 13 deletions(-) create mode 100644 packages/custodyKeyring/src/interfaces/IApiCallLogEntry.ts diff --git a/packages/custodyController/src/custody.ts b/packages/custodyController/src/custody.ts index 2f110501..d06f2383 100644 --- a/packages/custodyController/src/custody.ts +++ b/packages/custodyController/src/custody.ts @@ -1,4 +1,4 @@ -import { CUSTODIAN_TYPES } from "@metamask-institutional/custody-keyring"; +import { CUSTODIAN_TYPES, IApiCallLogEntry } from "@metamask-institutional/custody-keyring"; import { ITransactionStatusMap } from "@metamask-institutional/types"; import { ObservableStore } from "@metamask/obs-store"; @@ -16,8 +16,9 @@ import { toChecksumHexAddress } from "./utils"; */ export class CustodyController { public store; - + private readonly MAX_LOG_ENTRIES = 500; public captureException: (e: Error) => void; + /** * Creates a new controller instance * @@ -29,12 +30,45 @@ export class CustodyController { this.store = new ObservableStore({ custodyAccountDetails: {} as { [key: string]: CustodyAccountDetails }, custodianConnectRequest: {}, + apiRequestLogs: [], ...initState, }); this.captureException = captureException; } + storeApiCallLog(apiLogEntry: IApiCallLogEntry): void { + const { apiRequestLogs } = this.store.getState(); + + const updatedApiRequestLogs = apiRequestLogs ? [...apiRequestLogs] : []; + + if (updatedApiRequestLogs.length >= this.MAX_LOG_ENTRIES) { + updatedApiRequestLogs.shift(); + } + + updatedApiRequestLogs.push(apiLogEntry); + + this.store.updateState({ apiRequestLogs: updatedApiRequestLogs }); + } + + sanitizeAndLogApiCall(apiLogEntry: IApiCallLogEntry): void { + const { method, endpoint, success, timestamp, errorMessage, responseData } = apiLogEntry; + + const sanitizedEntry: IApiCallLogEntry = { + method, + endpoint, + success, + timestamp, + responseData: success ? responseData : undefined, + }; + + if (!success && errorMessage) { + sanitizedEntry.errorMessage = errorMessage; + } + + this.storeApiCallLog(sanitizedEntry); + } + storeCustodyStatusMap(custody: string, custodyStatusMap: ITransactionStatusMap): void { try { const { custodyStatusMaps } = this.store.getState(); diff --git a/packages/custodyKeyring/src/CustodyKeyring.ts b/packages/custodyKeyring/src/CustodyKeyring.ts index 88ebf5e7..8a00a81d 100644 --- a/packages/custodyKeyring/src/CustodyKeyring.ts +++ b/packages/custodyKeyring/src/CustodyKeyring.ts @@ -25,10 +25,12 @@ import crypto from "crypto"; import { EventEmitter } from "events"; import { + API_REQUEST_LOG_EVENT, DEFAULT_MAX_CACHE_AGE, INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, REFRESH_TOKEN_CHANGE_EVENT, } from "./constants"; +import { IApiCallLogEntry } from "./interfaces/IApiCallLogEntry"; import { ICustodianEnvironment } from "./interfaces/ICustodianEnvironment"; import { ICustodyKeyringOptions } from "./interfaces/ICustodyKeyringOptions"; import { ISerializedKeyring } from "./interfaces/ISerializedKeyring"; @@ -249,6 +251,10 @@ export abstract class CustodyKeyring extends EventEmitter { this.emit(INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, event); // Propagate the event to the extension where it calls for the keyrings to be persisted } + emitApiRequestLogEvent(event: IApiCallLogEntry): void { + this.emit(API_REQUEST_LOG_EVENT, event); + } + createAuthDetails(token: string): AuthDetails { let authDetails: AuthDetails; @@ -287,6 +293,8 @@ export abstract class CustodyKeyring extends EventEmitter { this.handleInteractiveRefreshTokenChangeEvent(event), ); + sdk.on(API_REQUEST_LOG_EVENT, (event: IApiCallLogEntry) => this.emitApiRequestLogEvent(event)); + this.sdkList.push({ sdk, hash, diff --git a/packages/custodyKeyring/src/constants/index.ts b/packages/custodyKeyring/src/constants/index.ts index 29d80bc8..5c1803c6 100644 --- a/packages/custodyKeyring/src/constants/index.ts +++ b/packages/custodyKeyring/src/constants/index.ts @@ -1,3 +1,4 @@ export const DEFAULT_MAX_CACHE_AGE = 60; export const REFRESH_TOKEN_CHANGE_EVENT = "refresh_token_change"; export const INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT = "interactive_replacement_token_change"; +export const API_REQUEST_LOG_EVENT = "API_REQUEST_LOG_EVENT"; diff --git a/packages/custodyKeyring/src/index.ts b/packages/custodyKeyring/src/index.ts index bfa80e97..7291cc81 100644 --- a/packages/custodyKeyring/src/index.ts +++ b/packages/custodyKeyring/src/index.ts @@ -2,6 +2,7 @@ export { CUSTODIAN_TYPES } from "./custodianTypes"; export { CustodyKeyring } from "./CustodyKeyring"; export { MMIConfiguration } from "./types/MMIConfiguration"; export { IJsonRpcCustodian } from "./interfaces/IJsonRpcCustodian"; +export { IApiCallLogEntry } from "./interfaces/IApiCallLogEntry"; export { MmiConfigurationController } from "./MmiConfiguration"; export { IMmiConfigurationControllerOptions } from "./interfaces/IMmiConfigurationControllerOptions"; diff --git a/packages/custodyKeyring/src/interfaces/IApiCallLogEntry.ts b/packages/custodyKeyring/src/interfaces/IApiCallLogEntry.ts new file mode 100644 index 00000000..c6bc9716 --- /dev/null +++ b/packages/custodyKeyring/src/interfaces/IApiCallLogEntry.ts @@ -0,0 +1,8 @@ +export interface IApiCallLogEntry { + method: string; + endpoint: string; + success: boolean; + timestamp: string; + errorMessage?: string; + responseData?: any; +} diff --git a/packages/sdk/src/classes/MMISDK.ts b/packages/sdk/src/classes/MMISDK.ts index 4e108060..b2c2d358 100644 --- a/packages/sdk/src/classes/MMISDK.ts +++ b/packages/sdk/src/classes/MMISDK.ts @@ -1,3 +1,4 @@ +import { IApiCallLogEntry } from "@metamask-institutional/custody-keyring"; import { SimpleCache } from "@metamask-institutional/simplecache"; import { AuthDetails, @@ -16,7 +17,11 @@ import { CustodianApiConstructor, ICustodianApi } from "src/interfaces/ICustodia import { SignedMessageMetadata } from "src/types/SignedMessageMetadata"; import { SignedTypedMessageMetadata } from "src/types/SignedTypedMessageMetadata"; -import { INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, REFRESH_TOKEN_CHANGE_EVENT } from "../constants/constants"; +import { + API_REQUEST_LOG_EVENT, + INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, + REFRESH_TOKEN_CHANGE_EVENT, +} from "../constants/constants"; import { IEthereumAccount } from "../interfaces/IEthereumAccount"; import { IEthereumAccountCustodianDetails } from "../interfaces/IEthereumAccountCustodianDetails"; import { MessageTypes, TypedMessage } from "../interfaces/ITypedMessage"; @@ -49,6 +54,10 @@ export class MMISDK extends EventEmitter { this.custodianApi.on(INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, event => { this.emit(INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, event); }); + + this.custodianApi.on(API_REQUEST_LOG_EVENT, (event: IApiCallLogEntry) => { + this.emit(API_REQUEST_LOG_EVENT, event); + }); } // Do an in-situ replacement of the auth details diff --git a/packages/sdk/src/constants/constants.ts b/packages/sdk/src/constants/constants.ts index d9fb5c24..142258bb 100644 --- a/packages/sdk/src/constants/constants.ts +++ b/packages/sdk/src/constants/constants.ts @@ -1,3 +1,4 @@ export const REFRESH_TOKEN_CHANGE_EVENT = "refresh_token_change"; export const INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT = "interactive_replacement_token_change"; export const DEFAULT_MAX_CACHE_AGE = 60; +export const API_REQUEST_LOG_EVENT = "API_REQUEST_LOG_EVENT"; diff --git a/packages/sdk/src/custodianApi/eca3/ECA3CustodianApi.ts b/packages/sdk/src/custodianApi/eca3/ECA3CustodianApi.ts index 2778853f..66dbfa53 100644 --- a/packages/sdk/src/custodianApi/eca3/ECA3CustodianApi.ts +++ b/packages/sdk/src/custodianApi/eca3/ECA3CustodianApi.ts @@ -1,3 +1,4 @@ +import { IApiCallLogEntry } from "@metamask-institutional/custody-keyring"; import { SimpleCache } from "@metamask-institutional/simplecache"; import { AuthTypes, @@ -11,12 +12,14 @@ import { } from "@metamask-institutional/types"; import { EventEmitter } from "events"; import { SignedMessageMetadata } from "src/types/SignedMessageMetadata"; -import { SignedMessageParams } from "src/types/SignedMessageParams"; import { SignedTypedMessageMetadata } from "src/types/SignedTypedMessageMetadata"; -import { SignedTypedMessageParams } from "src/types/SignedTypedMessageParams"; import { AccountHierarchyNode } from "../../classes/AccountHierarchyNode"; -import { INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, REFRESH_TOKEN_CHANGE_EVENT } from "../../constants/constants"; +import { + API_REQUEST_LOG_EVENT, + INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, + REFRESH_TOKEN_CHANGE_EVENT, +} from "../../constants/constants"; import { ICustodianApi } from "../../interfaces/ICustodianApi"; import { IEthereumAccount } from "../../interfaces/IEthereumAccount"; import { IEthereumAccountCustodianDetails } from "../../interfaces/IEthereumAccountCustodianDetails"; @@ -25,7 +28,6 @@ import { CreateTransactionMetadata } from "../../types/CreateTransactionMetadata import { ECA3Client } from "./ECA3Client"; import { JsonRpcTransactionParams } from "./rpc-payloads/JsonRpcCreateTransactionPayload"; import { JsonRpcReplaceTransactionParams } from "./rpc-payloads/JsonRpcReplaceTransactionPayload"; -import { JsonRpcListAccountsSignedResponse } from "./rpc-responses/JsonRpcListAccountsSignedResponse"; import { hexlify } from "./util/hexlify"; import { mapStatusObjectToStatusText } from "./util/mapStatusObjectToStatusText"; @@ -55,6 +57,10 @@ export class ECA3CustodianApi extends EventEmitter implements ICustodianApi { this.client.on(INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, event => { this.emit(INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, event); }); + + this.client.on(API_REQUEST_LOG_EVENT, (event: IApiCallLogEntry) => { + this.emit(API_REQUEST_LOG_EVENT, event); + }); } getAccountHierarchy(): Promise { diff --git a/packages/sdk/src/custodianApi/json-rpc/JsonRpcClient.ts b/packages/sdk/src/custodianApi/json-rpc/JsonRpcClient.ts index a875e14e..df71a1dd 100644 --- a/packages/sdk/src/custodianApi/json-rpc/JsonRpcClient.ts +++ b/packages/sdk/src/custodianApi/json-rpc/JsonRpcClient.ts @@ -3,7 +3,11 @@ import { IRefreshTokenChangeEvent } from "@metamask-institutional/types"; import crypto from "crypto"; import { EventEmitter } from "events"; -import { INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, REFRESH_TOKEN_CHANGE_EVENT } from "../../constants/constants"; +import { + API_REQUEST_LOG_EVENT, + INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, + REFRESH_TOKEN_CHANGE_EVENT, +} from "../../constants/constants"; import { JsonRpcResult } from "./interfaces/JsonRpcResult"; import { JsonRpcCreateTransactionPayload } from "./rpc-payloads/JsonRpcCreateTransactionPayload"; import { JsonRpcGetSignedMessageByIdPayload } from "./rpc-payloads/JsonRpcGetSignedMessageByIdPayload"; @@ -33,7 +37,7 @@ export class JsonRpcClient extends EventEmitter { constructor(private apiBaseUrl: string, private refreshToken: string, private refreshTokenUrl: string) { super(); - this.call = factory(`${apiBaseUrl}/v1/json-rpc`); + this.call = factory(`${this.apiBaseUrl}/v1/json-rpc`, this.emit.bind(this)); this.cache = new SimpleCache(); } @@ -127,8 +131,23 @@ export class JsonRpcClient extends EventEmitter { this.emit(REFRESH_TOKEN_CHANGE_EVENT, payload); } + this.emit(API_REQUEST_LOG_EVENT, { + method: "POST", + endpoint: this.refreshTokenUrl, + success: response.ok, + timestamp: new Date().toISOString(), + errorMessage: response.ok ? undefined : responseJson.message, + }); + return responseJson.access_token; } catch (error) { + this.emit(API_REQUEST_LOG_EVENT, { + method: "POST", + endpoint: this.refreshTokenUrl, + success: false, + timestamp: new Date().toISOString(), + errorMessage: error.message, + }); throw new Error(`Error getting the Access Token: ${error}`); } } diff --git a/packages/sdk/src/custodianApi/json-rpc/JsonRpcCustodianApi.ts b/packages/sdk/src/custodianApi/json-rpc/JsonRpcCustodianApi.ts index 6d125703..c1456f5f 100644 --- a/packages/sdk/src/custodianApi/json-rpc/JsonRpcCustodianApi.ts +++ b/packages/sdk/src/custodianApi/json-rpc/JsonRpcCustodianApi.ts @@ -1,3 +1,4 @@ +import { IApiCallLogEntry } from "@metamask-institutional/custody-keyring"; import { SimpleCache } from "@metamask-institutional/simplecache"; import { AuthTypes, @@ -12,7 +13,11 @@ import { import { EventEmitter } from "events"; import { AccountHierarchyNode } from "../../classes/AccountHierarchyNode"; -import { INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, REFRESH_TOKEN_CHANGE_EVENT } from "../../constants/constants"; +import { + API_REQUEST_LOG_EVENT, + INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, + REFRESH_TOKEN_CHANGE_EVENT, +} from "../../constants/constants"; import { ICustodianApi } from "../../interfaces/ICustodianApi"; import { IEthereumAccount } from "../../interfaces/IEthereumAccount"; import { IEthereumAccountCustodianDetails } from "../../interfaces/IEthereumAccountCustodianDetails"; @@ -49,6 +54,10 @@ export class JsonRpcCustodianApi extends EventEmitter implements ICustodianApi { this.client.on(INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, event => { this.emit(INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, event); }); + + this.client.on(API_REQUEST_LOG_EVENT, (event: IApiCallLogEntry) => { + this.emit(API_REQUEST_LOG_EVENT, event); + }); } getAccountHierarchy(): Promise { diff --git a/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.test.ts b/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.test.ts index 457713b7..5789de1c 100644 --- a/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.test.ts +++ b/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.test.ts @@ -13,7 +13,7 @@ describe("json-rpc-call", () => { describe("json-rpc-call", () => { it("should call the JSON RPC endpoint with the appropriate method and parameters", async () => { fetchMock.mockResponseOnce(JSON.stringify({ result: "test" })); - const call = factory("http://test/json-rpc"); + const call = factory("http://test/json-rpc", jest.fn()); await call("test", { some: "parameter" }, "access_token"); @@ -37,7 +37,7 @@ describe("json-rpc-call", () => { }), ); - const call = factory("http://test/json-rpc"); + const call = factory("http://test/json-rpc", jest.fn()); await expect(call("test", { some: "parameter" }, "access_token")).rejects.toThrow("Test error"); }); diff --git a/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts b/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts index 39c7b0dc..243cb290 100644 --- a/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts +++ b/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts @@ -1,7 +1,10 @@ +import { IApiCallLogEntry } from "@metamask-institutional/custody-keyring/src/interfaces/IApiCallLogEntry"; + +import { API_REQUEST_LOG_EVENT } from "../../../constants/constants"; import { JsonRpcError } from "../interfaces/JsonRpcError"; import { JsonRpcResult } from "../interfaces/JsonRpcResult"; -export default function (jsonRpcEndpoint: string) { +export default function (jsonRpcEndpoint: string, emit: (eventName: string, eventData: IApiCallLogEntry) => void) { let requestId = 0; return async function jsonRpcCall(method: string, params: T1, accessToken: string): Promise { @@ -30,6 +33,15 @@ export default function (jsonRpcEndpoint: string) { responseJson = await response.json(); + emit(API_REQUEST_LOG_EVENT, { + method, + endpoint: jsonRpcEndpoint, + success: !responseJson.error, + timestamp: new Date().toISOString(), + errorMessage: responseJson.error ? responseJson.error.message : undefined, + responseData: responseJson.result, + }); + if ((responseJson as JsonRpcError).error) { console.log("JSON-RPC <", method, requestId, responseJson, jsonRpcEndpoint); throw new Error((responseJson as JsonRpcError).error.message); @@ -42,6 +54,15 @@ export default function (jsonRpcEndpoint: string) { console.log("JSON-RPC <", method, requestId, e, jsonRpcEndpoint); + emit(API_REQUEST_LOG_EVENT, { + method, + endpoint: jsonRpcEndpoint, + success: false, + timestamp: new Date().toISOString(), + errorMessage: e.message, + responseData: null, + }); + throw e; } diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index 6f8c34a5..346990a4 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -8,6 +8,7 @@ export { ICustodianApi } from "./interfaces/ICustodianApi"; export { REFRESH_TOKEN_CHANGE_EVENT, INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, + API_REQUEST_LOG_EVENT, DEFAULT_MAX_CACHE_AGE, } from "./constants/constants"; From ebcb387161e6972d8d2ad9fec6b46ab50a9f8a30 Mon Sep 17 00:00:00 2001 From: Albert Olive Date: Thu, 10 Oct 2024 14:42:09 +0200 Subject: [PATCH 2/5] feat: added logs to eca3 --- .../sdk/src/custodianApi/eca3/ECA3Client.ts | 23 +++++++++++++++++-- .../custodianApi/eca3/util/json-rpc-call.ts | 23 ++++++++++++++++++- .../json-rpc/util/json-rpc-call.ts | 2 +- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/packages/sdk/src/custodianApi/eca3/ECA3Client.ts b/packages/sdk/src/custodianApi/eca3/ECA3Client.ts index f9470258..eaea5432 100644 --- a/packages/sdk/src/custodianApi/eca3/ECA3Client.ts +++ b/packages/sdk/src/custodianApi/eca3/ECA3Client.ts @@ -3,7 +3,11 @@ import { IRefreshTokenChangeEvent } from "@metamask-institutional/types"; import crypto from "crypto"; import { EventEmitter } from "events"; -import { INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, REFRESH_TOKEN_CHANGE_EVENT } from "../../constants/constants"; +import { + API_REQUEST_LOG_EVENT, + INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, + REFRESH_TOKEN_CHANGE_EVENT, +} from "../../constants/constants"; import { JsonRpcResult } from "./interfaces/JsonRpcResult"; import { JsonRpcCreateTransactionPayload } from "./rpc-payloads/JsonRpcCreateTransactionPayload"; import { JsonRpcGetSignedMessageByIdPayload } from "./rpc-payloads/JsonRpcGetSignedMessageByIdPayload"; @@ -38,7 +42,7 @@ export class ECA3Client extends EventEmitter { constructor(private apiBaseUrl: string, private refreshToken: string, private refreshTokenUrl: string) { super(); - this.call = factory(`${apiBaseUrl}/v3/json-rpc`); + this.call = factory(`${this.apiBaseUrl}/v3/json-rpc`, this.emit.bind(this)); this.cache = new SimpleCache(); } @@ -132,8 +136,23 @@ export class ECA3Client extends EventEmitter { this.emit(REFRESH_TOKEN_CHANGE_EVENT, payload); } + this.emit(API_REQUEST_LOG_EVENT, { + method: "POST", + endpoint: this.refreshTokenUrl, + success: response.ok, + timestamp: new Date().toISOString(), + errorMessage: response.ok ? undefined : responseJson.message, + }); + return responseJson.access_token; } catch (error) { + this.emit(API_REQUEST_LOG_EVENT, { + method: "POST", + endpoint: this.refreshTokenUrl, + success: false, + timestamp: new Date().toISOString(), + errorMessage: error.message, + }); throw new Error(`Error getting the Access Token: ${error}`); } } diff --git a/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts b/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts index 39c7b0dc..6e2ad588 100644 --- a/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts +++ b/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts @@ -1,7 +1,10 @@ +import { IApiCallLogEntry } from "@metamask-institutional/custody-keyring"; +import { API_REQUEST_LOG_EVENT } from "src/constants/constants"; + import { JsonRpcError } from "../interfaces/JsonRpcError"; import { JsonRpcResult } from "../interfaces/JsonRpcResult"; -export default function (jsonRpcEndpoint: string) { +export default function (jsonRpcEndpoint: string, emit: (eventName: string, eventData: IApiCallLogEntry) => void) { let requestId = 0; return async function jsonRpcCall(method: string, params: T1, accessToken: string): Promise { @@ -30,6 +33,15 @@ export default function (jsonRpcEndpoint: string) { responseJson = await response.json(); + emit(API_REQUEST_LOG_EVENT, { + method, + endpoint: jsonRpcEndpoint, + success: !responseJson.error, + timestamp: new Date().toISOString(), + errorMessage: responseJson.error ? responseJson.error.message : undefined, + responseData: responseJson.result, + }); + if ((responseJson as JsonRpcError).error) { console.log("JSON-RPC <", method, requestId, responseJson, jsonRpcEndpoint); throw new Error((responseJson as JsonRpcError).error.message); @@ -42,6 +54,15 @@ export default function (jsonRpcEndpoint: string) { console.log("JSON-RPC <", method, requestId, e, jsonRpcEndpoint); + emit(API_REQUEST_LOG_EVENT, { + method, + endpoint: jsonRpcEndpoint, + success: false, + timestamp: new Date().toISOString(), + errorMessage: e.message, + responseData: null, + }); + throw e; } diff --git a/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts b/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts index 243cb290..bc62ccc0 100644 --- a/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts +++ b/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts @@ -1,4 +1,4 @@ -import { IApiCallLogEntry } from "@metamask-institutional/custody-keyring/src/interfaces/IApiCallLogEntry"; +import { IApiCallLogEntry } from "@metamask-institutional/custody-keyring"; import { API_REQUEST_LOG_EVENT } from "../../../constants/constants"; import { JsonRpcError } from "../interfaces/JsonRpcError"; From 39dfac8456bb45b5111cf1dfd4d07ceb68cd8d3e Mon Sep 17 00:00:00 2001 From: Albert Olive Date: Thu, 10 Oct 2024 14:43:51 +0200 Subject: [PATCH 3/5] fix: tests --- packages/sdk/src/custodianApi/eca3/util/json-rpc-call.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.test.ts b/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.test.ts index 457713b7..5789de1c 100644 --- a/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.test.ts +++ b/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.test.ts @@ -13,7 +13,7 @@ describe("json-rpc-call", () => { describe("json-rpc-call", () => { it("should call the JSON RPC endpoint with the appropriate method and parameters", async () => { fetchMock.mockResponseOnce(JSON.stringify({ result: "test" })); - const call = factory("http://test/json-rpc"); + const call = factory("http://test/json-rpc", jest.fn()); await call("test", { some: "parameter" }, "access_token"); @@ -37,7 +37,7 @@ describe("json-rpc-call", () => { }), ); - const call = factory("http://test/json-rpc"); + const call = factory("http://test/json-rpc", jest.fn()); await expect(call("test", { some: "parameter" }, "access_token")).rejects.toThrow("Test error"); }); From c27a366c657fe4424bf68a3fa585bcd9b797f15d Mon Sep 17 00:00:00 2001 From: Albert Olive Date: Fri, 11 Oct 2024 10:39:14 +0200 Subject: [PATCH 4/5] fix: improved types --- packages/custodyController/src/custody.ts | 4 ++-- packages/custodyKeyring/src/CustodyKeyring.ts | 2 +- packages/custodyKeyring/src/index.ts | 1 - packages/sdk/src/classes/MMISDK.ts | 2 +- packages/sdk/src/custodianApi/eca3/ECA3CustodianApi.ts | 2 +- packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts | 4 ++-- packages/sdk/src/custodianApi/json-rpc/JsonRpcCustodianApi.ts | 2 +- packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts | 2 +- .../src/interfaces => types/src}/IApiCallLogEntry.ts | 0 packages/types/src/index.ts | 1 + 10 files changed, 10 insertions(+), 10 deletions(-) rename packages/{custodyKeyring/src/interfaces => types/src}/IApiCallLogEntry.ts (100%) diff --git a/packages/custodyController/src/custody.ts b/packages/custodyController/src/custody.ts index d06f2383..01827701 100644 --- a/packages/custodyController/src/custody.ts +++ b/packages/custodyController/src/custody.ts @@ -1,5 +1,5 @@ -import { CUSTODIAN_TYPES, IApiCallLogEntry } from "@metamask-institutional/custody-keyring"; -import { ITransactionStatusMap } from "@metamask-institutional/types"; +import { CUSTODIAN_TYPES } from "@metamask-institutional/custody-keyring"; +import { IApiCallLogEntry, ITransactionStatusMap } from "@metamask-institutional/types"; import { ObservableStore } from "@metamask/obs-store"; import { CustodyAccountDetails } from "./types"; diff --git a/packages/custodyKeyring/src/CustodyKeyring.ts b/packages/custodyKeyring/src/CustodyKeyring.ts index 8a00a81d..f8a993ac 100644 --- a/packages/custodyKeyring/src/CustodyKeyring.ts +++ b/packages/custodyKeyring/src/CustodyKeyring.ts @@ -5,6 +5,7 @@ import { AddressType, AuthDetails, AuthTypes, + IApiCallLogEntry, ICustodianAccount, ICustodianTransactionLink, ICustodianType, @@ -30,7 +31,6 @@ import { INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, REFRESH_TOKEN_CHANGE_EVENT, } from "./constants"; -import { IApiCallLogEntry } from "./interfaces/IApiCallLogEntry"; import { ICustodianEnvironment } from "./interfaces/ICustodianEnvironment"; import { ICustodyKeyringOptions } from "./interfaces/ICustodyKeyringOptions"; import { ISerializedKeyring } from "./interfaces/ISerializedKeyring"; diff --git a/packages/custodyKeyring/src/index.ts b/packages/custodyKeyring/src/index.ts index 7291cc81..bfa80e97 100644 --- a/packages/custodyKeyring/src/index.ts +++ b/packages/custodyKeyring/src/index.ts @@ -2,7 +2,6 @@ export { CUSTODIAN_TYPES } from "./custodianTypes"; export { CustodyKeyring } from "./CustodyKeyring"; export { MMIConfiguration } from "./types/MMIConfiguration"; export { IJsonRpcCustodian } from "./interfaces/IJsonRpcCustodian"; -export { IApiCallLogEntry } from "./interfaces/IApiCallLogEntry"; export { MmiConfigurationController } from "./MmiConfiguration"; export { IMmiConfigurationControllerOptions } from "./interfaces/IMmiConfigurationControllerOptions"; diff --git a/packages/sdk/src/classes/MMISDK.ts b/packages/sdk/src/classes/MMISDK.ts index b2c2d358..a3759b9d 100644 --- a/packages/sdk/src/classes/MMISDK.ts +++ b/packages/sdk/src/classes/MMISDK.ts @@ -1,8 +1,8 @@ -import { IApiCallLogEntry } from "@metamask-institutional/custody-keyring"; import { SimpleCache } from "@metamask-institutional/simplecache"; import { AuthDetails, AuthTypes, + IApiCallLogEntry, ICustodianTransactionLink, IEIP1559TxParams, ILegacyTXParams, diff --git a/packages/sdk/src/custodianApi/eca3/ECA3CustodianApi.ts b/packages/sdk/src/custodianApi/eca3/ECA3CustodianApi.ts index 66dbfa53..ffa0471a 100644 --- a/packages/sdk/src/custodianApi/eca3/ECA3CustodianApi.ts +++ b/packages/sdk/src/custodianApi/eca3/ECA3CustodianApi.ts @@ -1,7 +1,7 @@ -import { IApiCallLogEntry } from "@metamask-institutional/custody-keyring"; import { SimpleCache } from "@metamask-institutional/simplecache"; import { AuthTypes, + IApiCallLogEntry, ICustodianTransactionLink, IEIP1559TxParams, ILegacyTXParams, diff --git a/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts b/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts index 6e2ad588..cb151a46 100644 --- a/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts +++ b/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts @@ -1,6 +1,6 @@ -import { IApiCallLogEntry } from "@metamask-institutional/custody-keyring"; -import { API_REQUEST_LOG_EVENT } from "src/constants/constants"; +import { IApiCallLogEntry } from "@metamask-institutional/types"; +import { API_REQUEST_LOG_EVENT } from "../../../constants/constants"; import { JsonRpcError } from "../interfaces/JsonRpcError"; import { JsonRpcResult } from "../interfaces/JsonRpcResult"; diff --git a/packages/sdk/src/custodianApi/json-rpc/JsonRpcCustodianApi.ts b/packages/sdk/src/custodianApi/json-rpc/JsonRpcCustodianApi.ts index c1456f5f..4c479b84 100644 --- a/packages/sdk/src/custodianApi/json-rpc/JsonRpcCustodianApi.ts +++ b/packages/sdk/src/custodianApi/json-rpc/JsonRpcCustodianApi.ts @@ -1,7 +1,7 @@ -import { IApiCallLogEntry } from "@metamask-institutional/custody-keyring"; import { SimpleCache } from "@metamask-institutional/simplecache"; import { AuthTypes, + IApiCallLogEntry, ICustodianTransactionLink, IEIP1559TxParams, ILegacyTXParams, diff --git a/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts b/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts index bc62ccc0..cb151a46 100644 --- a/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts +++ b/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts @@ -1,4 +1,4 @@ -import { IApiCallLogEntry } from "@metamask-institutional/custody-keyring"; +import { IApiCallLogEntry } from "@metamask-institutional/types"; import { API_REQUEST_LOG_EVENT } from "../../../constants/constants"; import { JsonRpcError } from "../interfaces/JsonRpcError"; diff --git a/packages/custodyKeyring/src/interfaces/IApiCallLogEntry.ts b/packages/types/src/IApiCallLogEntry.ts similarity index 100% rename from packages/custodyKeyring/src/interfaces/IApiCallLogEntry.ts rename to packages/types/src/IApiCallLogEntry.ts diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 5051f706..6a8ad88c 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -16,6 +16,7 @@ export { ITransactionStatusMap } from "./ITransactionStatusMap"; export { ICustodianAccount, IExtensionCustodianAccount } from "./ICustodianAccount"; export { IRefreshTokenChangeEvent } from "./IRefreshTokenChangeEvent"; export { IInteractiveRefreshTokenChangeEvent } from "./IInteractiveRefreshTokenChangeEvent"; +export { IApiCallLogEntry } from "./IApiCallLogEntry"; // Enums export { AuthTypes } from "./enum/AuthTypes"; From 4c0462d88d6ccb67a66b29ab018789ed5c9a121d Mon Sep 17 00:00:00 2001 From: Albert Olive Date: Fri, 11 Oct 2024 14:58:57 +0200 Subject: [PATCH 5/5] refactor: added id in the logs --- packages/custodyController/src/custody.ts | 3 ++- packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts | 2 ++ packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts | 2 ++ packages/types/src/IApiCallLogEntry.ts | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/custodyController/src/custody.ts b/packages/custodyController/src/custody.ts index 01827701..42d72a09 100644 --- a/packages/custodyController/src/custody.ts +++ b/packages/custodyController/src/custody.ts @@ -52,9 +52,10 @@ export class CustodyController { } sanitizeAndLogApiCall(apiLogEntry: IApiCallLogEntry): void { - const { method, endpoint, success, timestamp, errorMessage, responseData } = apiLogEntry; + const { id, method, endpoint, success, timestamp, errorMessage, responseData } = apiLogEntry; const sanitizedEntry: IApiCallLogEntry = { + id, method, endpoint, success, diff --git a/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts b/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts index cb151a46..ffe58fff 100644 --- a/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts +++ b/packages/sdk/src/custodianApi/eca3/util/json-rpc-call.ts @@ -34,6 +34,7 @@ export default function (jsonRpcEndpoint: string, emit: (eventName: string, even responseJson = await response.json(); emit(API_REQUEST_LOG_EVENT, { + id: requestId, method, endpoint: jsonRpcEndpoint, success: !responseJson.error, @@ -55,6 +56,7 @@ export default function (jsonRpcEndpoint: string, emit: (eventName: string, even console.log("JSON-RPC <", method, requestId, e, jsonRpcEndpoint); emit(API_REQUEST_LOG_EVENT, { + id: requestId, method, endpoint: jsonRpcEndpoint, success: false, diff --git a/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts b/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts index cb151a46..ffe58fff 100644 --- a/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts +++ b/packages/sdk/src/custodianApi/json-rpc/util/json-rpc-call.ts @@ -34,6 +34,7 @@ export default function (jsonRpcEndpoint: string, emit: (eventName: string, even responseJson = await response.json(); emit(API_REQUEST_LOG_EVENT, { + id: requestId, method, endpoint: jsonRpcEndpoint, success: !responseJson.error, @@ -55,6 +56,7 @@ export default function (jsonRpcEndpoint: string, emit: (eventName: string, even console.log("JSON-RPC <", method, requestId, e, jsonRpcEndpoint); emit(API_REQUEST_LOG_EVENT, { + id: requestId, method, endpoint: jsonRpcEndpoint, success: false, diff --git a/packages/types/src/IApiCallLogEntry.ts b/packages/types/src/IApiCallLogEntry.ts index c6bc9716..1dfe1da0 100644 --- a/packages/types/src/IApiCallLogEntry.ts +++ b/packages/types/src/IApiCallLogEntry.ts @@ -1,4 +1,5 @@ export interface IApiCallLogEntry { + id?: number; method: string; endpoint: string; success: boolean;