From 06b350f90a946a57a1118a53ed793732ccca3c7e Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Mon, 28 Oct 2024 20:35:45 +0530 Subject: [PATCH 01/42] Integrating signature decoding api --- .../src/SignatureController.ts | 41 +++++++++++++++++++ packages/signature-controller/src/types.ts | 28 ++++++++++++- .../src/utils/normalize.ts | 10 +++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index 80dc3aa49f1..3e708fc60da 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -43,8 +43,10 @@ import type { TypedSigningOptions, LegacyStateMessage, StateSIWEMessage, + DecodedRequestInfo, } from './types'; import { + convertNumbericValuestoQuotedString, normalizePersonalMessageParams, normalizeTypedMessageParams, } from './utils/normalize'; @@ -331,6 +333,38 @@ export class SignatureController extends BaseController< version as SignTypedDataVersion, ); + // Code below will invoke signature request decoding api for permits + let decodedRequest: DecodedRequestInfo; + try { + const { primaryType } = JSON.parse(request.params[1]); + if (primaryType === 'Permit') { + const { method, origin, params } = request; + const response = await fetch( + `https://qtgdj2huxh.execute-api.us-east-2.amazonaws.com/uat/v1/signature?chainId=${chainId}`, + { + method: 'POST', + body: JSON.stringify({ + method, + origin, + params: [ + params[0], + JSON.parse(convertNumbericValuestoQuotedString(params[1])), + ], + }), + headers: { 'Content-Type': 'application/json' }, + }, + ); + decodedRequest = (await response.json()) as DecodedRequestInfo; + } + } catch (error) { + decodedRequest = { + error: { + message: error as string, + type: 'DECODING_FAILED_WITH_ERROR', + }, + }; + } + return this.#processSignatureRequest({ approvalType: ApprovalType.EthSignTypedData, messageParams: normalizedMessageParams, @@ -339,6 +373,7 @@ export class SignatureController extends BaseController< traceContext: options.traceContext, type: SignatureRequestType.TypedSign, version: version as SignTypedDataVersion, + decodedRequest, }); } @@ -428,6 +463,7 @@ export class SignatureController extends BaseController< version, signingOptions, traceContext, + decodedRequest, }: { chainId?: Hex; messageParams: MessageParams; @@ -437,6 +473,7 @@ export class SignatureController extends BaseController< version?: SignTypedDataVersion; signingOptions?: TypedSigningOptions; traceContext?: TraceContext; + decodedRequest?: DecodedRequestInfo; }): Promise { log('Processing signature request', { messageParams, @@ -456,6 +493,7 @@ export class SignatureController extends BaseController< signingOptions, type, version, + decodedRequest, }); let resultCallbacks: AcceptResultCallbacks | undefined; @@ -528,6 +566,7 @@ export class SignatureController extends BaseController< signingOptions, type, version, + decodedRequest, }: { chainId: Hex; messageParams: MessageParams; @@ -535,6 +574,7 @@ export class SignatureController extends BaseController< signingOptions?: TypedSigningOptions; type: SignatureRequestType; version?: SignTypedDataVersion; + decodedRequest?: DecodedRequestInfo; }): SignatureRequest { const id = random(); const origin = request?.origin ?? messageParams.origin; @@ -561,6 +601,7 @@ export class SignatureController extends BaseController< time: Date.now(), type, version, + decodedRequest, } as SignatureRequest; this.#updateState((state) => { diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index 8465c5844e5..8b500fb5f5b 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -15,6 +15,12 @@ export type OriginalRequest = { /** Response following a security scan of the request. */ securityAlertResponse?: Record; + + /** Method of signature request */ + method?: string; + + /** Parameters in signature request */ + params: string[]; }; /** Options for signing typed data. */ @@ -71,11 +77,28 @@ export type MessageParamsTyped = MessageParams & { primaryType: string; message: Json; }; - + /** Signature method V1, V3 or V4 */ + signatureMethod?: string; /** Version of the signTypedData request. */ version?: string; }; +export type DecodedRequestInfo = + | { + assetType: string; + changeType: string; + address: string; + amount: string; + contractAddress: string; + } + | { + error: { + message: string; + type: string; + }; + } + | undefined; + type SignatureRequestBase = { /** ID of the associated chain. */ chainId: Hex; @@ -109,6 +132,9 @@ type SignatureRequestBase = { /** Version of the signTypedData request. */ version?: SignTypedDataVersion; + + /** Response from message decoding api. */ + decodedRequest?: DecodedRequestInfo; }; /** Legacy messages stored in the state. */ diff --git a/packages/signature-controller/src/utils/normalize.ts b/packages/signature-controller/src/utils/normalize.ts index b39b3931fe5..100a7d76461 100644 --- a/packages/signature-controller/src/utils/normalize.ts +++ b/packages/signature-controller/src/utils/normalize.ts @@ -59,3 +59,13 @@ function normalizePersonalMessageData(data: string) { return bytesToHex(Buffer.from(data, 'utf8')); } + +/** + * Takes a stringified JSON and replaces all numeric values in it with quoted strings. + * + * @param str - String of JSON to be fixed. + * @returns String with all numeric values converted to quoted strings. + */ +export function convertNumbericValuestoQuotedString(str: string) { + return str?.replace(/(?<=:\s*)(-?\d+(\.\d+)?)(?=[,\]}])/gu, '"$1"'); +} From 39cc9accfc349f73341a8eefd0b46c6833e85bbc Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Mon, 28 Oct 2024 20:40:13 +0530 Subject: [PATCH 02/42] Integrating signature decoding api --- .../src/SignatureController.ts | 67 ++++++++++--------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index 3e708fc60da..ad44a3244d9 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -334,36 +334,8 @@ export class SignatureController extends BaseController< ); // Code below will invoke signature request decoding api for permits - let decodedRequest: DecodedRequestInfo; - try { - const { primaryType } = JSON.parse(request.params[1]); - if (primaryType === 'Permit') { - const { method, origin, params } = request; - const response = await fetch( - `https://qtgdj2huxh.execute-api.us-east-2.amazonaws.com/uat/v1/signature?chainId=${chainId}`, - { - method: 'POST', - body: JSON.stringify({ - method, - origin, - params: [ - params[0], - JSON.parse(convertNumbericValuestoQuotedString(params[1])), - ], - }), - headers: { 'Content-Type': 'application/json' }, - }, - ); - decodedRequest = (await response.json()) as DecodedRequestInfo; - } - } catch (error) { - decodedRequest = { - error: { - message: error as string, - type: 'DECODING_FAILED_WITH_ERROR', - }, - }; - } + const decodedRequest: DecodedRequestInfo = + await this.#decodePermitSignatureRequest(request); return this.#processSignatureRequest({ approvalType: ApprovalType.EthSignTypedData, @@ -921,4 +893,39 @@ export class SignatureController extends BaseController< return networkClient.configuration.chainId; } + + async #decodePermitSignatureRequest(request: OriginalRequest) { + // Code below will invoke signature request decoding api for permits + let decodedRequest: DecodedRequestInfo; + try { + const { primaryType } = JSON.parse(request.params[1]); + if (primaryType === 'Permit') { + const { method, origin, params } = request; + const response = await fetch( + `https://qtgdj2huxh.execute-api.us-east-2.amazonaws.com/uat/v1/signature?chainId=${chainId}`, + { + method: 'POST', + body: JSON.stringify({ + method, + origin, + params: [ + params[0], + JSON.parse(convertNumbericValuestoQuotedString(params[1])), + ], + }), + headers: { 'Content-Type': 'application/json' }, + }, + ); + decodedRequest = (await response.json()) as DecodedRequestInfo; + } + } catch (error) { + decodedRequest = { + error: { + message: error as string, + type: 'DECODING_FAILED_WITH_ERROR', + }, + }; + } + return decodedRequest; + } } From 15203de4f945bd631233631250528ce3afa00006 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 29 Oct 2024 15:45:14 +0530 Subject: [PATCH 03/42] update --- .../src/SignatureController.ts | 96 +++++++++++++------ packages/signature-controller/src/types.ts | 1 + 2 files changed, 67 insertions(+), 30 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index ad44a3244d9..52f67e458cc 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -166,6 +166,11 @@ export type SignatureControllerOptions = { * Callback to record the duration of code. */ trace?: TraceCallback; + + /** + * Api used to get decoding data for permits. + */ + decodingApi?: string; }; /** @@ -180,6 +185,8 @@ export class SignatureController extends BaseController< #trace: TraceCallback; + #decodingApi?: string; + /** * Construct a Sign controller. * @@ -187,8 +194,14 @@ export class SignatureController extends BaseController< * @param options.messenger - The restricted controller messenger for the sign controller. * @param options.state - Initial state to set on this controller. * @param options.trace - Callback to generate trace information. + * @param options.decodingApi - Api used to get decoded data for permits. */ - constructor({ messenger, state, trace }: SignatureControllerOptions) { + constructor({ + messenger, + state, + trace, + decodingApi, + }: SignatureControllerOptions) { super({ name: controllerName, metadata: stateMetadata, @@ -201,6 +214,7 @@ export class SignatureController extends BaseController< this.hub = new EventEmitter(); this.#trace = trace ?? (((_request, fn) => fn?.()) as TraceCallback); + this.#decodingApi = decodingApi; } /** @@ -333,10 +347,6 @@ export class SignatureController extends BaseController< version as SignTypedDataVersion, ); - // Code below will invoke signature request decoding api for permits - const decodedRequest: DecodedRequestInfo = - await this.#decodePermitSignatureRequest(request); - return this.#processSignatureRequest({ approvalType: ApprovalType.EthSignTypedData, messageParams: normalizedMessageParams, @@ -345,7 +355,6 @@ export class SignatureController extends BaseController< traceContext: options.traceContext, type: SignatureRequestType.TypedSign, version: version as SignTypedDataVersion, - decodedRequest, }); } @@ -472,6 +481,7 @@ export class SignatureController extends BaseController< let approveOrSignError: unknown; const finalMetadataPromise = this.#waitForFinished(metadata.id); + this.#decodePermitSignatureRequest(metadata.id, request, chainId); try { resultCallbacks = await this.#processApproval({ @@ -894,38 +904,64 @@ export class SignatureController extends BaseController< return networkClient.configuration.chainId; } - async #decodePermitSignatureRequest(request: OriginalRequest) { + #decodePermitSignatureRequest( + signatureRequestId: string, + request: OriginalRequest, + chainId: string, + ) { + if (!this.#decodingApi) { + return; + } // Code below will invoke signature request decoding api for permits let decodedRequest: DecodedRequestInfo; try { const { primaryType } = JSON.parse(request.params[1]); if (primaryType === 'Permit') { + this.#updateMetadata(signatureRequestId, (draftMetadata) => { + draftMetadata.decodedRequest = 'IN_PROGRESS'; + }); const { method, origin, params } = request; - const response = await fetch( - `https://qtgdj2huxh.execute-api.us-east-2.amazonaws.com/uat/v1/signature?chainId=${chainId}`, - { - method: 'POST', - body: JSON.stringify({ - method, - origin, - params: [ - params[0], - JSON.parse(convertNumbericValuestoQuotedString(params[1])), - ], - }), - headers: { 'Content-Type': 'application/json' }, - }, - ); - decodedRequest = (await response.json()) as DecodedRequestInfo; + fetch(`${this.#decodingApi}?chainId=${chainId}`, { + method: 'POST', + body: JSON.stringify({ + method, + origin, + params: [ + params[0], + JSON.parse(convertNumbericValuestoQuotedString(params[1])), + ], + }), + headers: { 'Content-Type': 'application/json' }, + }) + .then((response) => { + return response.json(); + }) + .then((result) => { + decodedRequest = result; + }) + .catch((error) => { + decodedRequest = { + error: { + message: error as string, + type: 'DECODING_FAILED_WITH_ERROR', + }, + }; + }) + .finally(() => { + this.#updateMetadata(signatureRequestId, (draftMetadata) => { + draftMetadata.decodedRequest = decodedRequest; + }); + }); } } catch (error) { - decodedRequest = { - error: { - message: error as string, - type: 'DECODING_FAILED_WITH_ERROR', - }, - }; + this.#updateMetadata(signatureRequestId, (draftMetadata) => { + draftMetadata.decodedRequest = { + error: { + message: error as string, + type: 'DECODING_FAILED_WITH_ERROR', + }, + }; + }); } - return decodedRequest; } } diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index 8b500fb5f5b..6f3c5289f04 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -97,6 +97,7 @@ export type DecodedRequestInfo = type: string; }; } + | 'IN_PROGRESS' | undefined; type SignatureRequestBase = { From b4a1ec5932258c1003195de480060fa21c9e6938 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 29 Oct 2024 16:07:13 +0530 Subject: [PATCH 04/42] Update --- .../src/SignatureController.test.ts | 37 +++++++++++++++++++ .../src/SignatureController.ts | 8 +--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.test.ts b/packages/signature-controller/src/SignatureController.test.ts index eebfca17da0..fff2f1e741d 100644 --- a/packages/signature-controller/src/SignatureController.test.ts +++ b/packages/signature-controller/src/SignatureController.test.ts @@ -64,6 +64,26 @@ const SIGNATURE_REQUEST_MOCK: SignatureRequest = { type: SignatureRequestType.PersonalSign, }; +const PERMIT_PARAMS_MOCK = { + data: '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Permit":[{"name":"owner","type":"address"},{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"}]},"primaryType":"Permit","domain":{"name":"MyToken","version":"1","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","chainId":1},"message":{"owner":"0x935e73edb9ff52e23bac7f7e043a1ecd06d05477","spender":"0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","value":3000,"nonce":0,"deadline":50000000000}}', + from: '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', + version: 'V4', + signatureMethod: 'eth_signTypedData_v4', +}; +const PERMIT_REQUEST_MOCK = { + method: 'eth_signTypedData_v4', + params: [ + '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', + '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Permit":[{"name":"owner","type":"address"},{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"}]},"primaryType":"Permit","domain":{"name":"MyToken","version":"1","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","chainId":1},"message":{"owner":"0x935e73edb9ff52e23bac7f7e043a1ecd06d05477","spender":"0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","value":3000,"nonce":0,"deadline":50000000000}}', + ], + jsonrpc: '2.0', + id: 1680528590, + origin: 'https://metamask.github.io', + networkClientId: 'mainnet', + tabId: 1048807181, + traceContext: null, +}; + /** * Create a mock messenger instance. * @returns The mock messenger instance plus individual mock functions for each action. @@ -890,6 +910,23 @@ describe('SignatureController', () => { ).version, ).toBe(SignTypedDataVersion.V3); }); + + it('invoke decoding api for permits', async () => { + const { controller } = createController(); + + await controller.newUnsignedTypedMessage( + PERMIT_PARAMS_MOCK, + PERMIT_REQUEST_MOCK, + SignTypedDataVersion.V4, + { parseJsonData: false }, + ); + + await flushPromises(); + await Promise.resolve(); + expect(controller.state.signatureRequests[ID_MOCK].decodedRequest).toBe( + 'IN_PROGRESS', + ); + }); }); describe('setDeferredSignSuccess', () => { diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index 52f67e458cc..9a7c7917e99 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -444,7 +444,6 @@ export class SignatureController extends BaseController< version, signingOptions, traceContext, - decodedRequest, }: { chainId?: Hex; messageParams: MessageParams; @@ -454,7 +453,6 @@ export class SignatureController extends BaseController< version?: SignTypedDataVersion; signingOptions?: TypedSigningOptions; traceContext?: TraceContext; - decodedRequest?: DecodedRequestInfo; }): Promise { log('Processing signature request', { messageParams, @@ -474,7 +472,6 @@ export class SignatureController extends BaseController< signingOptions, type, version, - decodedRequest, }); let resultCallbacks: AcceptResultCallbacks | undefined; @@ -548,7 +545,6 @@ export class SignatureController extends BaseController< signingOptions, type, version, - decodedRequest, }: { chainId: Hex; messageParams: MessageParams; @@ -556,7 +552,6 @@ export class SignatureController extends BaseController< signingOptions?: TypedSigningOptions; type: SignatureRequestType; version?: SignTypedDataVersion; - decodedRequest?: DecodedRequestInfo; }): SignatureRequest { const id = random(); const origin = request?.origin ?? messageParams.origin; @@ -583,7 +578,6 @@ export class SignatureController extends BaseController< time: Date.now(), type, version, - decodedRequest, } as SignatureRequest; this.#updateState((state) => { @@ -909,10 +903,10 @@ export class SignatureController extends BaseController< request: OriginalRequest, chainId: string, ) { + // Code below will invoke signature request decoding api for permits if (!this.#decodingApi) { return; } - // Code below will invoke signature request decoding api for permits let decodedRequest: DecodedRequestInfo; try { const { primaryType } = JSON.parse(request.params[1]); From 0cc8436978b6569648f895fbb6708d6a2a1c7e39 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 29 Oct 2024 16:09:50 +0530 Subject: [PATCH 05/42] Update --- .../signature-controller/src/SignatureController.test.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.test.ts b/packages/signature-controller/src/SignatureController.test.ts index fff2f1e741d..41c515ce070 100644 --- a/packages/signature-controller/src/SignatureController.test.ts +++ b/packages/signature-controller/src/SignatureController.test.ts @@ -65,16 +65,17 @@ const SIGNATURE_REQUEST_MOCK: SignatureRequest = { }; const PERMIT_PARAMS_MOCK = { - data: '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Permit":[{"name":"owner","type":"address"},{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"}]},"primaryType":"Permit","domain":{"name":"MyToken","version":"1","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","chainId":1},"message":{"owner":"0x935e73edb9ff52e23bac7f7e043a1ecd06d05477","spender":"0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","value":3000,"nonce":0,"deadline":50000000000}}', - from: '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', + data: '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Permit":[{"name":"owner","type":"address"},{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"}]},"primaryType":"Permit","domain":{"name":"MyToken","version":"1","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","chainId":1},"message":{"owner":"0x975e73efb9ff52e23bac7f7e043a1ecd06d05477","spender":"0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","value":3000,"nonce":0,"deadline":50000000000}}', + from: '0x975e73efb9ff52e23bac7f7e043a1ecd06d05477', version: 'V4', signatureMethod: 'eth_signTypedData_v4', }; + const PERMIT_REQUEST_MOCK = { method: 'eth_signTypedData_v4', params: [ - '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', - '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Permit":[{"name":"owner","type":"address"},{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"}]},"primaryType":"Permit","domain":{"name":"MyToken","version":"1","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","chainId":1},"message":{"owner":"0x935e73edb9ff52e23bac7f7e043a1ecd06d05477","spender":"0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","value":3000,"nonce":0,"deadline":50000000000}}', + '0x975e73efb9ff52e23bac7f7e043a1ecd06d05477', + '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Permit":[{"name":"owner","type":"address"},{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"}]},"primaryType":"Permit","domain":{"name":"MyToken","version":"1","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","chainId":1},"message":{"owner":"0x975e73efb9ff52e23bac7f7e043a1ecd06d05477","spender":"0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","value":3000,"nonce":0,"deadline":50000000000}}', ], jsonrpc: '2.0', id: 1680528590, From 1edf2f8ebc783fcb3716dcbf6441b16013315256 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 29 Oct 2024 16:10:09 +0530 Subject: [PATCH 06/42] Update --- packages/signature-controller/src/SignatureController.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/signature-controller/src/SignatureController.test.ts b/packages/signature-controller/src/SignatureController.test.ts index 41c515ce070..a3600918916 100644 --- a/packages/signature-controller/src/SignatureController.test.ts +++ b/packages/signature-controller/src/SignatureController.test.ts @@ -923,7 +923,6 @@ describe('SignatureController', () => { ); await flushPromises(); - await Promise.resolve(); expect(controller.state.signatureRequests[ID_MOCK].decodedRequest).toBe( 'IN_PROGRESS', ); From fd390342b60175cd58fbce2e69a7f7bf4c688e76 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 29 Oct 2024 16:38:04 +0530 Subject: [PATCH 07/42] Update --- .../signature-controller/src/utils/normalize.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/signature-controller/src/utils/normalize.test.ts b/packages/signature-controller/src/utils/normalize.test.ts index 09b57628d1e..9bcff334f13 100644 --- a/packages/signature-controller/src/utils/normalize.test.ts +++ b/packages/signature-controller/src/utils/normalize.test.ts @@ -2,6 +2,7 @@ import { SignTypedDataVersion } from '@metamask/keyring-controller'; import type { MessageParamsPersonal, MessageParamsTyped } from '../types'; import { + convertNumbericValuestoQuotedString, normalizePersonalMessageParams, normalizeTypedMessageParams, } from './normalize'; @@ -40,4 +41,15 @@ describe('Normalize Utils', () => { }, ); }); + + describe('convertNumbericValuestoQuotedString', () => { + it('wraps numeric value in a json string in quotes', async () => { + expect(convertNumbericValuestoQuotedString('{temp:123}')).toBe( + '{temp:"123"}', + ); + expect(convertNumbericValuestoQuotedString('{temp:{test:123}}')).toBe( + '{temp:{test:"123"}}', + ); + }); + }); }); From 7553a4eae893b9ac32a64c9f9cb03933df20e887 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 29 Oct 2024 16:43:56 +0530 Subject: [PATCH 08/42] Update --- packages/signature-controller/src/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index 6f3c5289f04..909a54fe583 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -20,7 +20,7 @@ export type OriginalRequest = { method?: string; /** Parameters in signature request */ - params: string[]; + params?: string[]; }; /** Options for signing typed data. */ From fcde11b6696c564e0a8496aa991ec562b5f8e020 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 29 Oct 2024 17:07:16 +0530 Subject: [PATCH 09/42] Update --- packages/signature-controller/src/SignatureController.ts | 6 +++--- packages/signature-controller/src/utils/normalize.test.ts | 1 + packages/signature-controller/src/utils/normalize.ts | 5 ++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index 9a7c7917e99..7a247f2bfdf 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -909,7 +909,7 @@ export class SignatureController extends BaseController< } let decodedRequest: DecodedRequestInfo; try { - const { primaryType } = JSON.parse(request.params[1]); + const { primaryType } = JSON.parse(request.params?.[1] ?? ''); if (primaryType === 'Permit') { this.#updateMetadata(signatureRequestId, (draftMetadata) => { draftMetadata.decodedRequest = 'IN_PROGRESS'; @@ -921,8 +921,8 @@ export class SignatureController extends BaseController< method, origin, params: [ - params[0], - JSON.parse(convertNumbericValuestoQuotedString(params[1])), + params?.[0], + JSON.parse(convertNumbericValuestoQuotedString(params?.[1])), ], }), headers: { 'Content-Type': 'application/json' }, diff --git a/packages/signature-controller/src/utils/normalize.test.ts b/packages/signature-controller/src/utils/normalize.test.ts index 9bcff334f13..f0d6cc151a3 100644 --- a/packages/signature-controller/src/utils/normalize.test.ts +++ b/packages/signature-controller/src/utils/normalize.test.ts @@ -50,6 +50,7 @@ describe('Normalize Utils', () => { expect(convertNumbericValuestoQuotedString('{temp:{test:123}}')).toBe( '{temp:{test:"123"}}', ); + expect(convertNumbericValuestoQuotedString('')).toBe(''); }); }); }); diff --git a/packages/signature-controller/src/utils/normalize.ts b/packages/signature-controller/src/utils/normalize.ts index 100a7d76461..16275264f59 100644 --- a/packages/signature-controller/src/utils/normalize.ts +++ b/packages/signature-controller/src/utils/normalize.ts @@ -66,6 +66,9 @@ function normalizePersonalMessageData(data: string) { * @param str - String of JSON to be fixed. * @returns String with all numeric values converted to quoted strings. */ -export function convertNumbericValuestoQuotedString(str: string) { +export function convertNumbericValuestoQuotedString(str?: string) { + if (!str) { + return str; + } return str?.replace(/(?<=:\s*)(-?\d+(\.\d+)?)(?=[,\]}])/gu, '"$1"'); } From 6cd04234ba8a361cbf6d39e4f130fa217ccc5585 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 29 Oct 2024 17:16:58 +0530 Subject: [PATCH 10/42] Update --- packages/signature-controller/src/SignatureController.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index 7a247f2bfdf..6784b7aff05 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -922,7 +922,9 @@ export class SignatureController extends BaseController< origin, params: [ params?.[0], - JSON.parse(convertNumbericValuestoQuotedString(params?.[1])), + JSON.parse( + convertNumbericValuestoQuotedString(params?.[1]) ?? '', + ), ], }), headers: { 'Content-Type': 'application/json' }, From 68dc5ff459eada12a6772d47aa954edec92db3e8 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 29 Oct 2024 17:21:22 +0530 Subject: [PATCH 11/42] Update --- packages/signature-controller/src/SignatureController.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/signature-controller/src/SignatureController.test.ts b/packages/signature-controller/src/SignatureController.test.ts index a3600918916..c5864bc749c 100644 --- a/packages/signature-controller/src/SignatureController.test.ts +++ b/packages/signature-controller/src/SignatureController.test.ts @@ -912,7 +912,8 @@ describe('SignatureController', () => { ).toBe(SignTypedDataVersion.V3); }); - it('invoke decoding api for permits', async () => { + // eslint-disable-next-line jest/no-disabled-tests + it.skip('invoke decoding api for permits', async () => { const { controller } = createController(); await controller.newUnsignedTypedMessage( From 83969e381e9f70aa8b12cd6ebeedac351d03ff92 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 15:20:34 +0530 Subject: [PATCH 12/42] update --- .../src/SignatureController.ts | 98 ++++++------------- packages/signature-controller/src/types.ts | 15 +-- .../src/utils/decoding-api.ts | 47 +++++++++ 3 files changed, 87 insertions(+), 73 deletions(-) create mode 100644 packages/signature-controller/src/utils/decoding-api.ts diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index 6784b7aff05..7a9729e1822 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -43,10 +43,9 @@ import type { TypedSigningOptions, LegacyStateMessage, StateSIWEMessage, - DecodedRequestInfo, } from './types'; +import { getDecodingResult } from './utils/decoding-api'; import { - convertNumbericValuestoQuotedString, normalizePersonalMessageParams, normalizeTypedMessageParams, } from './utils/normalize'; @@ -157,6 +156,11 @@ export type SignatureControllerOptions = { // eslint-disable-next-line @typescript-eslint/no-explicit-any ) => Promise; + /** + * Api used to get decoding data for permits. + */ + decodingApiUrl?: string; + /** * Initial state of the controller. */ @@ -166,11 +170,6 @@ export type SignatureControllerOptions = { * Callback to record the duration of code. */ trace?: TraceCallback; - - /** - * Api used to get decoding data for permits. - */ - decodingApi?: string; }; /** @@ -183,9 +182,9 @@ export class SignatureController extends BaseController< > { hub: EventEmitter; - #trace: TraceCallback; + #decodingApiUrl?: string; - #decodingApi?: string; + #trace: TraceCallback; /** * Construct a Sign controller. @@ -194,13 +193,13 @@ export class SignatureController extends BaseController< * @param options.messenger - The restricted controller messenger for the sign controller. * @param options.state - Initial state to set on this controller. * @param options.trace - Callback to generate trace information. - * @param options.decodingApi - Api used to get decoded data for permits. + * @param options.decodingApiUrl - Api used to get decoded data for permits. */ constructor({ + decodingApiUrl, messenger, state, trace, - decodingApi, }: SignatureControllerOptions) { super({ name: controllerName, @@ -214,7 +213,7 @@ export class SignatureController extends BaseController< this.hub = new EventEmitter(); this.#trace = trace ?? (((_request, fn) => fn?.()) as TraceCallback); - this.#decodingApi = decodingApi; + this.#decodingApiUrl = decodingApiUrl; } /** @@ -903,61 +902,26 @@ export class SignatureController extends BaseController< request: OriginalRequest, chainId: string, ) { - // Code below will invoke signature request decoding api for permits - if (!this.#decodingApi) { - return; - } - let decodedRequest: DecodedRequestInfo; - try { - const { primaryType } = JSON.parse(request.params?.[1] ?? ''); - if (primaryType === 'Permit') { + this.#updateMetadata(signatureRequestId, (draftMetadata) => { + draftMetadata.decodingLoading = true; + }); + getDecodingResult(request, chainId, this.#decodingApiUrl) + .then((decodedRequest) => this.#updateMetadata(signatureRequestId, (draftMetadata) => { - draftMetadata.decodedRequest = 'IN_PROGRESS'; - }); - const { method, origin, params } = request; - fetch(`${this.#decodingApi}?chainId=${chainId}`, { - method: 'POST', - body: JSON.stringify({ - method, - origin, - params: [ - params?.[0], - JSON.parse( - convertNumbericValuestoQuotedString(params?.[1]) ?? '', - ), - ], - }), - headers: { 'Content-Type': 'application/json' }, - }) - .then((response) => { - return response.json(); - }) - .then((result) => { - decodedRequest = result; - }) - .catch((error) => { - decodedRequest = { - error: { - message: error as string, - type: 'DECODING_FAILED_WITH_ERROR', - }, - }; - }) - .finally(() => { - this.#updateMetadata(signatureRequestId, (draftMetadata) => { - draftMetadata.decodedRequest = decodedRequest; - }); - }); - } - } catch (error) { - this.#updateMetadata(signatureRequestId, (draftMetadata) => { - draftMetadata.decodedRequest = { - error: { - message: error as string, - type: 'DECODING_FAILED_WITH_ERROR', - }, - }; - }); - } + draftMetadata.decodedRequest = decodedRequest; + draftMetadata.decodingLoading = false; + }), + ) + .catch((error) => + this.#updateMetadata(signatureRequestId, (draftMetadata) => { + draftMetadata.decodedRequest = { + error: { + message: error as string, + type: 'DECODING_FAILED_WITH_ERROR', + }, + }; + draftMetadata.decodingLoading = false; + }), + ); } } diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index 909a54fe583..2e1e3a6ad96 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -7,20 +7,20 @@ export type OriginalRequest = { /** Unique ID to identify the client request. */ id?: number; + /** Method of signature request */ + method?: string; + /** ID of the network client associated with the request. */ networkClientId?: string; /** Source of the client request. */ origin?: string; - /** Response following a security scan of the request. */ - securityAlertResponse?: Record; - - /** Method of signature request */ - method?: string; - /** Parameters in signature request */ params?: string[]; + + /** Response following a security scan of the request. */ + securityAlertResponse?: Record; }; /** Options for signing typed data. */ @@ -134,6 +134,9 @@ type SignatureRequestBase = { /** Version of the signTypedData request. */ version?: SignTypedDataVersion; + /** Field to know if decoding request is in progress */ + decodingLoading?: boolean; + /** Response from message decoding api. */ decodedRequest?: DecodedRequestInfo; }; diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts new file mode 100644 index 00000000000..f25837dcedd --- /dev/null +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -0,0 +1,47 @@ +import type { DecodedRequestInfo, OriginalRequest } from '../types'; +import { convertNumbericValuestoQuotedString } from './normalize'; + +/** + * The function calls decoding api for typed signature V4 requests and returns the result. + * + * @param request - Signature request. + * @param decodingApiUrl - URL of decoding api. + * @param chainId - chainId of network of signature request. + * @returns Promise that resolved to give decoded data. + */ +export async function getDecodingResult( + request: OriginalRequest, + chainId: string, + decodingApiUrl?: string, +) { + if (!decodingApiUrl) { + return undefined; + } + let decodedRequest: DecodedRequestInfo; + try { + const { method, origin, params } = request; + if (request.method === 'eth_signTypedData_v4') { + const response = await fetch(`${decodingApiUrl}?chainId=${chainId}`, { + method: 'POST', + body: JSON.stringify({ + method, + origin, + params: [ + params?.[0], + JSON.parse(convertNumbericValuestoQuotedString(params?.[1]) ?? ''), + ], + }), + headers: { 'Content-Type': 'application/json' }, + }); + decodedRequest = await response.json(); + } + } catch (error) { + decodedRequest = { + error: { + message: error as string, + type: 'DECODING_FAILED_WITH_ERROR', + }, + }; + } + return decodedRequest; +} From 9e25b9a78041e020b46252edea42676f6110d5f3 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 15:30:04 +0530 Subject: [PATCH 13/42] update --- .../src/SignatureController.ts | 10 ++++---- packages/signature-controller/src/types.ts | 23 +++++++++---------- .../src/utils/decoding-api.ts | 12 +++++----- .../src/utils/normalize.test.ts | 10 ++++---- .../src/utils/normalize.ts | 2 +- 5 files changed, 28 insertions(+), 29 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index 7a9729e1822..93c1f912049 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -44,7 +44,7 @@ import type { LegacyStateMessage, StateSIWEMessage, } from './types'; -import { getDecodingResult } from './utils/decoding-api'; +import { getDecodingData } from './utils/decoding-api'; import { normalizePersonalMessageParams, normalizeTypedMessageParams, @@ -905,16 +905,16 @@ export class SignatureController extends BaseController< this.#updateMetadata(signatureRequestId, (draftMetadata) => { draftMetadata.decodingLoading = true; }); - getDecodingResult(request, chainId, this.#decodingApiUrl) - .then((decodedRequest) => + getDecodingData(request, chainId, this.#decodingApiUrl) + .then((decodedData) => this.#updateMetadata(signatureRequestId, (draftMetadata) => { - draftMetadata.decodedRequest = decodedRequest; + draftMetadata.decodingData = decodedData; draftMetadata.decodingLoading = false; }), ) .catch((error) => this.#updateMetadata(signatureRequestId, (draftMetadata) => { - draftMetadata.decodedRequest = { + draftMetadata.decodingData = { error: { message: error as string, type: 'DECODING_FAILED_WITH_ERROR', diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index 2e1e3a6ad96..3227c0b7172 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -77,13 +77,13 @@ export type MessageParamsTyped = MessageParams & { primaryType: string; message: Json; }; - /** Signature method V1, V3 or V4 */ - signatureMethod?: string; /** Version of the signTypedData request. */ version?: string; }; -export type DecodedRequestInfo = +/** Decoding data about typed sign V4 signature request. */ +export type DecodingData = + /** Information about various state chainged returned by decoding api. */ | { assetType: string; changeType: string; @@ -91,19 +91,24 @@ export type DecodedRequestInfo = amount: string; contractAddress: string; } + /** Error details for unfulfilled the decoding request. */ | { error: { message: string; type: string; }; - } - | 'IN_PROGRESS' - | undefined; + }; type SignatureRequestBase = { /** ID of the associated chain. */ chainId: Hex; + /** Response from message decoding api. */ + decodingData?: DecodingData; + + /** Field to know if decoding request is in progress */ + decodingLoading?: boolean; + /** Error message that occurred during the signing. */ error?: string; @@ -133,12 +138,6 @@ type SignatureRequestBase = { /** Version of the signTypedData request. */ version?: SignTypedDataVersion; - - /** Field to know if decoding request is in progress */ - decodingLoading?: boolean; - - /** Response from message decoding api. */ - decodedRequest?: DecodedRequestInfo; }; /** Legacy messages stored in the state. */ diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index f25837dcedd..39255cb6d20 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -1,4 +1,4 @@ -import type { DecodedRequestInfo, OriginalRequest } from '../types'; +import type { DecodingData, OriginalRequest } from '../types'; import { convertNumbericValuestoQuotedString } from './normalize'; /** @@ -9,7 +9,7 @@ import { convertNumbericValuestoQuotedString } from './normalize'; * @param chainId - chainId of network of signature request. * @returns Promise that resolved to give decoded data. */ -export async function getDecodingResult( +export async function getDecodingData( request: OriginalRequest, chainId: string, decodingApiUrl?: string, @@ -17,7 +17,7 @@ export async function getDecodingResult( if (!decodingApiUrl) { return undefined; } - let decodedRequest: DecodedRequestInfo; + let decodingData: DecodingData; try { const { method, origin, params } = request; if (request.method === 'eth_signTypedData_v4') { @@ -33,15 +33,15 @@ export async function getDecodingResult( }), headers: { 'Content-Type': 'application/json' }, }); - decodedRequest = await response.json(); + decodingData = await response.json(); } } catch (error) { - decodedRequest = { + decodingData = { error: { message: error as string, type: 'DECODING_FAILED_WITH_ERROR', }, }; } - return decodedRequest; + return decodingData; } diff --git a/packages/signature-controller/src/utils/normalize.test.ts b/packages/signature-controller/src/utils/normalize.test.ts index f0d6cc151a3..b8c6d806595 100644 --- a/packages/signature-controller/src/utils/normalize.test.ts +++ b/packages/signature-controller/src/utils/normalize.test.ts @@ -2,7 +2,7 @@ import { SignTypedDataVersion } from '@metamask/keyring-controller'; import type { MessageParamsPersonal, MessageParamsTyped } from '../types'; import { - convertNumbericValuestoQuotedString, + convertNumericValuesToQuotedString, normalizePersonalMessageParams, normalizeTypedMessageParams, } from './normalize'; @@ -42,15 +42,15 @@ describe('Normalize Utils', () => { ); }); - describe('convertNumbericValuestoQuotedString', () => { + describe('convertNumericValuesToQuotedString', () => { it('wraps numeric value in a json string in quotes', async () => { - expect(convertNumbericValuestoQuotedString('{temp:123}')).toBe( + expect(convertNumericValuesToQuotedString('{temp:123}')).toBe( '{temp:"123"}', ); - expect(convertNumbericValuestoQuotedString('{temp:{test:123}}')).toBe( + expect(convertNumericValuesToQuotedString('{temp:{test:123}}')).toBe( '{temp:{test:"123"}}', ); - expect(convertNumbericValuestoQuotedString('')).toBe(''); + expect(convertNumericValuesToQuotedString('')).toBe(''); }); }); }); diff --git a/packages/signature-controller/src/utils/normalize.ts b/packages/signature-controller/src/utils/normalize.ts index 16275264f59..66164c737be 100644 --- a/packages/signature-controller/src/utils/normalize.ts +++ b/packages/signature-controller/src/utils/normalize.ts @@ -66,7 +66,7 @@ function normalizePersonalMessageData(data: string) { * @param str - String of JSON to be fixed. * @returns String with all numeric values converted to quoted strings. */ -export function convertNumbericValuestoQuotedString(str?: string) { +export function convertNumericValuesToQuotedString(str?: string) { if (!str) { return str; } From 1ac68cac75a24f3b58b04f2b435e59eb54523a28 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 15:39:10 +0530 Subject: [PATCH 14/42] update --- .../src/utils/decoding-api.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index 39255cb6d20..aa2a28b630e 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -1,12 +1,12 @@ -import type { DecodingData, OriginalRequest } from '../types'; -import { convertNumbericValuestoQuotedString } from './normalize'; +import type { OriginalRequest } from '../types'; +import { convertNumericValuesToQuotedString } from './normalize'; /** * The function calls decoding api for typed signature V4 requests and returns the result. * * @param request - Signature request. - * @param decodingApiUrl - URL of decoding api. * @param chainId - chainId of network of signature request. + * @param decodingApiUrl - URL of decoding api. * @returns Promise that resolved to give decoded data. */ export async function getDecodingData( @@ -17,7 +17,6 @@ export async function getDecodingData( if (!decodingApiUrl) { return undefined; } - let decodingData: DecodingData; try { const { method, origin, params } = request; if (request.method === 'eth_signTypedData_v4') { @@ -28,20 +27,20 @@ export async function getDecodingData( origin, params: [ params?.[0], - JSON.parse(convertNumbericValuestoQuotedString(params?.[1]) ?? ''), + JSON.parse(convertNumericValuesToQuotedString(params?.[1]) ?? ''), ], }), headers: { 'Content-Type': 'application/json' }, }); - decodingData = await response.json(); + return await response.json(); } } catch (error) { - decodingData = { + return { error: { message: error as string, type: 'DECODING_FAILED_WITH_ERROR', }, }; } - return decodingData; + return undefined; } From 3c9b7b4ad2c48173c4ed9142a12896324eb5b6e2 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 15:42:50 +0530 Subject: [PATCH 15/42] update --- packages/signature-controller/src/SignatureController.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.test.ts b/packages/signature-controller/src/SignatureController.test.ts index c5864bc749c..b5a4d699624 100644 --- a/packages/signature-controller/src/SignatureController.test.ts +++ b/packages/signature-controller/src/SignatureController.test.ts @@ -924,8 +924,8 @@ describe('SignatureController', () => { ); await flushPromises(); - expect(controller.state.signatureRequests[ID_MOCK].decodedRequest).toBe( - 'IN_PROGRESS', + expect(controller.state.signatureRequests[ID_MOCK].decodingData).toBe( + 'DUMMY', ); }); }); From ac2d149e1d6cab100459d006ce8c9ad7a782daf9 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 16:37:18 +0530 Subject: [PATCH 16/42] update --- packages/signature-controller/package.json | 2 + .../src/utils/decoding-api.test.ts | 48 +++++++++++++++++++ .../src/utils/decoding-api.ts | 27 ++++++----- 3 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 packages/signature-controller/src/utils/decoding-api.test.ts diff --git a/packages/signature-controller/package.json b/packages/signature-controller/package.json index c16d8246eab..f6187cec505 100644 --- a/packages/signature-controller/package.json +++ b/packages/signature-controller/package.json @@ -64,6 +64,8 @@ "@types/jest": "^27.4.1", "deepmerge": "^4.2.2", "jest": "^27.5.1", + "nock": "^13.3.1", + "node-fetch": "npm:^2.6.1", "ts-jest": "^27.1.4", "typedoc": "^0.24.8", "typedoc-plugin-missing-exports": "^2.0.0", diff --git a/packages/signature-controller/src/utils/decoding-api.test.ts b/packages/signature-controller/src/utils/decoding-api.test.ts new file mode 100644 index 00000000000..daf0791327c --- /dev/null +++ b/packages/signature-controller/src/utils/decoding-api.test.ts @@ -0,0 +1,48 @@ +import nock from 'nock'; +import fetch from 'node-fetch'; + +import { getDecodingData } from './decoding-api'; + +global.fetch = fetch; + +const PERMIT_REQUEST_MOCK = { + method: 'eth_signTypedData_v4', + params: [ + '0x975e73efb9ff52e23bac7f7e043a1ecd06d05477', + '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Permit":[{"name":"owner","type":"address"},{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"}]},"primaryType":"Permit","domain":{"name":"MyToken","version":"1","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","chainId":1},"message":{"owner":"0x975e73efb9ff52e23bac7f7e043a1ecd06d05477","spender":"0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","value":3000,"nonce":0,"deadline":50000000000}}', + ], + jsonrpc: '2.0', + id: 1680528590, + origin: 'https://metamask.github.io', + networkClientId: 'mainnet', + tabId: 1048807181, + traceContext: null, +}; + +const MOCK_RESULT = { + stateChanges: [ + { + assetType: 'ERC20', + changeType: 'APPROVE', + address: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad', + amount: '1461501637330902918203684832716283019655932542975', + contractAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', + }, + ], +}; + +describe('Decoding api', () => { + it('return the data from api', async () => { + nock('https://testdecodingurl.com') + .post('/signature?chainId=0x1') + .reply(200, JSON.stringify(MOCK_RESULT)); + + const result = await getDecodingData( + PERMIT_REQUEST_MOCK, + '0x1', + 'https://testdecodingurl.com', + ); + + expect(result.stateChanges).toStrictEqual(MOCK_RESULT.stateChanges); + }); +}); diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index aa2a28b630e..3137c69834c 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -20,18 +20,21 @@ export async function getDecodingData( try { const { method, origin, params } = request; if (request.method === 'eth_signTypedData_v4') { - const response = await fetch(`${decodingApiUrl}?chainId=${chainId}`, { - method: 'POST', - body: JSON.stringify({ - method, - origin, - params: [ - params?.[0], - JSON.parse(convertNumericValuesToQuotedString(params?.[1]) ?? ''), - ], - }), - headers: { 'Content-Type': 'application/json' }, - }); + const response = await fetch( + `${decodingApiUrl}/signature?chainId=${chainId}`, + { + method: 'POST', + body: JSON.stringify({ + method, + origin, + params: [ + params?.[0], + JSON.parse(convertNumericValuesToQuotedString(params?.[1]) ?? ''), + ], + }), + headers: { 'Content-Type': 'application/json' }, + }, + ); return await response.json(); } } catch (error) { From dc7fcb7b1a1911d4594f1f4183d7f02d6329a757 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 18:29:38 +0530 Subject: [PATCH 17/42] update --- packages/signature-controller/package.json | 1 + packages/signature-controller/src/types.ts | 38 +++++++++++-------- .../src/utils/decoding-api.test.ts | 20 +++++++++- yarn.lock | 13 +++++++ 4 files changed, 54 insertions(+), 18 deletions(-) diff --git a/packages/signature-controller/package.json b/packages/signature-controller/package.json index f6187cec505..fa32f9e9e1e 100644 --- a/packages/signature-controller/package.json +++ b/packages/signature-controller/package.json @@ -62,6 +62,7 @@ "@metamask/logging-controller": "^6.0.1", "@metamask/network-controller": "^22.0.0", "@types/jest": "^27.4.1", + "@types/node-fetch": "^2.6.11", "deepmerge": "^4.2.2", "jest": "^27.5.1", "nock": "^13.3.1", diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index 3227c0b7172..342ccd8445c 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -81,23 +81,29 @@ export type MessageParamsTyped = MessageParams & { version?: string; }; +/** Information about various state changes returned by decoding api. */ +type DecodingDataStateChanges = { + assetType: string; + changeType: string; + address: string; + amount: string; + contractAddress: string; +}[]; + +/** Error details for unfulfilled the decoding request. */ +type DecodingDataError = { + assetType: string; + changeType: string; + address: string; + amount: string; + contractAddress: string; +}[]; + /** Decoding data about typed sign V4 signature request. */ -export type DecodingData = - /** Information about various state chainged returned by decoding api. */ - | { - assetType: string; - changeType: string; - address: string; - amount: string; - contractAddress: string; - } - /** Error details for unfulfilled the decoding request. */ - | { - error: { - message: string; - type: string; - }; - }; +export type DecodingData = { + stateChanges: DecodingDataStateChanges | null; + error: DecodingDataError; +}; type SignatureRequestBase = { /** ID of the associated chain. */ diff --git a/packages/signature-controller/src/utils/decoding-api.test.ts b/packages/signature-controller/src/utils/decoding-api.test.ts index daf0791327c..a282cb60664 100644 --- a/packages/signature-controller/src/utils/decoding-api.test.ts +++ b/packages/signature-controller/src/utils/decoding-api.test.ts @@ -1,9 +1,11 @@ import nock from 'nock'; -import fetch from 'node-fetch'; +import nodeFetch from 'node-fetch'; import { getDecodingData } from './decoding-api'; -global.fetch = fetch; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore-next-line +global.fetch = nodeFetch; const PERMIT_REQUEST_MOCK = { method: 'eth_signTypedData_v4', @@ -45,4 +47,18 @@ describe('Decoding api', () => { expect(result.stateChanges).toStrictEqual(MOCK_RESULT.stateChanges); }); + + it('return error from the api as it is', async () => { + nock('https://testdecodingurl.com') + .post('/signature?chainId=0x1') + .reply(200, JSON.stringify(MOCK_RESULT)); + + const result = await getDecodingData( + PERMIT_REQUEST_MOCK, + '0x1', + 'https://testdecodingurl.com', + ); + + expect(result.stateChanges).toStrictEqual(MOCK_RESULT.stateChanges); + }); }); diff --git a/yarn.lock b/yarn.lock index e878214ed62..2ac953fb286 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3492,10 +3492,13 @@ __metadata: "@metamask/network-controller": "npm:^22.0.0" "@metamask/utils": "npm:^10.0.0" "@types/jest": "npm:^27.4.1" + "@types/node-fetch": "npm:^2.6.11" deepmerge: "npm:^4.2.2" jest: "npm:^27.5.1" jsonschema: "npm:^1.2.4" lodash: "npm:^4.17.21" + nock: "npm:^13.3.1" + node-fetch: "npm:^2.6.1" ts-jest: "npm:^27.1.4" typedoc: "npm:^0.24.8" typedoc-plugin-missing-exports: "npm:^2.0.0" @@ -4463,6 +4466,16 @@ __metadata: languageName: node linkType: hard +"@types/node-fetch@npm:^2.6.11": + version: 2.6.11 + resolution: "@types/node-fetch@npm:2.6.11" + dependencies: + "@types/node": "npm:*" + form-data: "npm:^4.0.0" + checksum: 10/c416df8f182ec3826278ea42557fda08f169a48a05e60722d9c8edd4e5b2076ae281c6b6601ad406035b7201f885b0257983b61c26b3f9eb0f41192a807b5de5 + languageName: node + linkType: hard + "@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0": version: 22.5.0 resolution: "@types/node@npm:22.5.0" From dfd539b0d8d1f641e3544e93c71cececef479ac3 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 18:32:29 +0530 Subject: [PATCH 18/42] update --- packages/signature-controller/src/SignatureController.ts | 5 +++-- packages/signature-controller/src/types.ts | 9 +++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index 93c1f912049..9cf44fe155f 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -906,15 +906,16 @@ export class SignatureController extends BaseController< draftMetadata.decodingLoading = true; }); getDecodingData(request, chainId, this.#decodingApiUrl) - .then((decodedData) => + .then((decodingData) => this.#updateMetadata(signatureRequestId, (draftMetadata) => { - draftMetadata.decodingData = decodedData; + draftMetadata.decodingData = decodingData; draftMetadata.decodingLoading = false; }), ) .catch((error) => this.#updateMetadata(signatureRequestId, (draftMetadata) => { draftMetadata.decodingData = { + stateChanges: null, error: { message: error as string, type: 'DECODING_FAILED_WITH_ERROR', diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index 342ccd8445c..57dcb6d53a1 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -92,12 +92,9 @@ type DecodingDataStateChanges = { /** Error details for unfulfilled the decoding request. */ type DecodingDataError = { - assetType: string; - changeType: string; - address: string; - amount: string; - contractAddress: string; -}[]; + message: string; + type: string; +}; /** Decoding data about typed sign V4 signature request. */ export type DecodingData = { From d5df2c43b1a8d7ec5aab8da80836f47cca0fed5f Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 18:56:39 +0530 Subject: [PATCH 19/42] update --- .../src/utils/decoding-api.test.ts | 22 +++++++++++++++++-- .../src/utils/decoding-api.ts | 4 ++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/signature-controller/src/utils/decoding-api.test.ts b/packages/signature-controller/src/utils/decoding-api.test.ts index a282cb60664..c45183ee304 100644 --- a/packages/signature-controller/src/utils/decoding-api.test.ts +++ b/packages/signature-controller/src/utils/decoding-api.test.ts @@ -33,6 +33,14 @@ const MOCK_RESULT = { ], }; +const MOCK_ERROR = { + error: { + message: + 'Unsupported signature. Please contact our team about adding support.', + type: 'UNSUPPORTED_SIGNATURE', + }, +}; + describe('Decoding api', () => { it('return the data from api', async () => { nock('https://testdecodingurl.com') @@ -51,7 +59,7 @@ describe('Decoding api', () => { it('return error from the api as it is', async () => { nock('https://testdecodingurl.com') .post('/signature?chainId=0x1') - .reply(200, JSON.stringify(MOCK_RESULT)); + .reply(200, JSON.stringify(MOCK_ERROR)); const result = await getDecodingData( PERMIT_REQUEST_MOCK, @@ -59,6 +67,16 @@ describe('Decoding api', () => { 'https://testdecodingurl.com', ); - expect(result.stateChanges).toStrictEqual(MOCK_RESULT.stateChanges); + expect(result.error).toStrictEqual(MOCK_ERROR.error); + }); + + it('return failure error if there is an exception while validating', async () => { + const result = await getDecodingData( + PERMIT_REQUEST_MOCK, + '0x1', + 'https://testdecodingurl.com', + ); + + expect(result.error.type).toBe('DECODING_FAILED_WITH_ERROR'); }); }); diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index 3137c69834c..7b940c88ed5 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -37,10 +37,10 @@ export async function getDecodingData( ); return await response.json(); } - } catch (error) { + } catch (error: unknown) { return { error: { - message: error as string, + message: (error as unknown as Error).message, type: 'DECODING_FAILED_WITH_ERROR', }, }; From 2cc2d7c765cf5952f669d09bd710a08c313087d8 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 18:59:19 +0530 Subject: [PATCH 20/42] update --- .../signature-controller/src/SignatureController.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.test.ts b/packages/signature-controller/src/SignatureController.test.ts index b5a4d699624..243d7b09ea2 100644 --- a/packages/signature-controller/src/SignatureController.test.ts +++ b/packages/signature-controller/src/SignatureController.test.ts @@ -913,7 +913,7 @@ describe('SignatureController', () => { }); // eslint-disable-next-line jest/no-disabled-tests - it.skip('invoke decoding api for permits', async () => { + it('invoke decoding api for permits', async () => { const { controller } = createController(); await controller.newUnsignedTypedMessage( @@ -924,8 +924,8 @@ describe('SignatureController', () => { ); await flushPromises(); - expect(controller.state.signatureRequests[ID_MOCK].decodingData).toBe( - 'DUMMY', + expect(controller.state.signatureRequests[ID_MOCK].decodingLoading).toBe( + false, ); }); }); From 8ed4da632e926f9f199f425ac57d25c5fce3e66e Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 19:09:00 +0530 Subject: [PATCH 21/42] update --- .../src/utils/decoding-api.test.ts | 16 ++++++++++++++++ .../src/utils/decoding-api.ts | 7 ++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/signature-controller/src/utils/decoding-api.test.ts b/packages/signature-controller/src/utils/decoding-api.test.ts index c45183ee304..dc77de8cdc6 100644 --- a/packages/signature-controller/src/utils/decoding-api.test.ts +++ b/packages/signature-controller/src/utils/decoding-api.test.ts @@ -1,6 +1,7 @@ import nock from 'nock'; import nodeFetch from 'node-fetch'; +import type { OriginalRequest } from '../types'; import { getDecodingData } from './decoding-api'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -79,4 +80,19 @@ describe('Decoding api', () => { expect(result.error.type).toBe('DECODING_FAILED_WITH_ERROR'); }); + + it('return undefined for request not of method eth_signTypedData_v4', async () => { + const result = await getDecodingData( + { method: 'eth_signTypedData_v3' } as OriginalRequest, + '0x1', + 'https://testdecodingurl.com', + ); + + expect(result.error).toStrictEqual({ + error: { + message: 'Unsupported signature.', + type: 'UNSUPPORTED_SIGNATURE', + }, + }); + }); }); diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index 7b940c88ed5..37d19c734c0 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -37,6 +37,12 @@ export async function getDecodingData( ); return await response.json(); } + return { + error: { + message: 'Unsupported signature.', + type: 'UNSUPPORTED_SIGNATURE', + }, + }; } catch (error: unknown) { return { error: { @@ -45,5 +51,4 @@ export async function getDecodingData( }, }; } - return undefined; } From 92e752f0426a79edcb664bdd8996d779197c767c Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 19:11:21 +0530 Subject: [PATCH 22/42] update --- packages/signature-controller/src/utils/decoding-api.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index 37d19c734c0..2fa08152a91 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -1,6 +1,11 @@ import type { OriginalRequest } from '../types'; import { convertNumericValuesToQuotedString } from './normalize'; +const API_ERRORS = { + UNSUPPORTED_SIGNATURE: 'UNSUPPORTED_SIGNATURE', + DECODING_FAILED_WITH_ERROR: 'DECODING_FAILED_WITH_ERROR', +}; + /** * The function calls decoding api for typed signature V4 requests and returns the result. * @@ -40,14 +45,14 @@ export async function getDecodingData( return { error: { message: 'Unsupported signature.', - type: 'UNSUPPORTED_SIGNATURE', + type: API_ERRORS.UNSUPPORTED_SIGNATURE, }, }; } catch (error: unknown) { return { error: { message: (error as unknown as Error).message, - type: 'DECODING_FAILED_WITH_ERROR', + type: API_ERRORS.DECODING_FAILED_WITH_ERROR, }, }; } From 964dd73e28d4ca56d9059e454924e1c1415cf39d Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 19:15:53 +0530 Subject: [PATCH 23/42] update --- .../src/utils/decoding-api.test.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/signature-controller/src/utils/decoding-api.test.ts b/packages/signature-controller/src/utils/decoding-api.test.ts index dc77de8cdc6..207f3a1fa25 100644 --- a/packages/signature-controller/src/utils/decoding-api.test.ts +++ b/packages/signature-controller/src/utils/decoding-api.test.ts @@ -42,6 +42,13 @@ const MOCK_ERROR = { }, }; +const UNSUPPORTED_SIGNATURE_ERROR = { + error: { + message: 'Unsupported signature.', + type: 'UNSUPPORTED_SIGNATURE', + }, +}; + describe('Decoding api', () => { it('return the data from api', async () => { nock('https://testdecodingurl.com') @@ -88,11 +95,6 @@ describe('Decoding api', () => { 'https://testdecodingurl.com', ); - expect(result.error).toStrictEqual({ - error: { - message: 'Unsupported signature.', - type: 'UNSUPPORTED_SIGNATURE', - }, - }); + expect(result.error.type).toBe('UNSUPPORTED_SIGNATURE'); }); }); From 329b097ed5a345c5b1c8bea4edb77fa10fb78768 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 19:16:11 +0530 Subject: [PATCH 24/42] update --- .../signature-controller/src/utils/decoding-api.test.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/signature-controller/src/utils/decoding-api.test.ts b/packages/signature-controller/src/utils/decoding-api.test.ts index 207f3a1fa25..3e8ae3dc1e7 100644 --- a/packages/signature-controller/src/utils/decoding-api.test.ts +++ b/packages/signature-controller/src/utils/decoding-api.test.ts @@ -42,13 +42,6 @@ const MOCK_ERROR = { }, }; -const UNSUPPORTED_SIGNATURE_ERROR = { - error: { - message: 'Unsupported signature.', - type: 'UNSUPPORTED_SIGNATURE', - }, -}; - describe('Decoding api', () => { it('return the data from api', async () => { nock('https://testdecodingurl.com') From 83f4ede0a8b4f1092840f78c432c240e59e5598a Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 19:38:19 +0530 Subject: [PATCH 25/42] update --- .../src/SignatureController.test.ts | 24 ++++++++++++++++++- .../src/SignatureController.ts | 6 ++--- .../src/utils/decoding-api.ts | 2 +- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.test.ts b/packages/signature-controller/src/SignatureController.test.ts index 243d7b09ea2..167117a23dc 100644 --- a/packages/signature-controller/src/SignatureController.test.ts +++ b/packages/signature-controller/src/SignatureController.test.ts @@ -18,6 +18,7 @@ import type { SignatureRequest, } from './types'; import { SignatureRequestStatus, SignatureRequestType } from './types'; +import * as DecodingDataUtils from './utils/decoding-api'; import { normalizePersonalMessageParams, normalizeTypedMessageParams, @@ -914,8 +915,23 @@ describe('SignatureController', () => { // eslint-disable-next-line jest/no-disabled-tests it('invoke decoding api for permits', async () => { + const MOCK_STATE_CHANGES = { + stateChanges: [ + { + assetType: 'ERC20', + changeType: 'APPROVE', + address: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad', + amount: '1461501637330902918203684832716283019655932542975', + contractAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', + }, + ], + }; const { controller } = createController(); + jest + .spyOn(DecodingDataUtils, 'getDecodingData') + .mockResolvedValue(MOCK_STATE_CHANGES); + await controller.newUnsignedTypedMessage( PERMIT_PARAMS_MOCK, PERMIT_REQUEST_MOCK, @@ -923,10 +939,12 @@ describe('SignatureController', () => { { parseJsonData: false }, ); - await flushPromises(); expect(controller.state.signatureRequests[ID_MOCK].decodingLoading).toBe( false, ); + expect( + controller.state.signatureRequests[ID_MOCK].decodingData, + ).toStrictEqual(MOCK_STATE_CHANGES); }); }); @@ -958,6 +976,8 @@ describe('SignatureController', () => { const { controller } = createController(); let resolved = false; + jest.spyOn(DecodingDataUtils, 'getDecodingData').mockResolvedValue({}); + const signaturePromise = controller .newUnsignedPersonalMessage( { @@ -1036,6 +1056,8 @@ describe('SignatureController', () => { const { controller } = createController(); let rejectedError; + jest.spyOn(DecodingDataUtils, 'getDecodingData').mockResolvedValue({}); + controller .newUnsignedPersonalMessage( { diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index 9cf44fe155f..3fec221f252 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -44,7 +44,7 @@ import type { LegacyStateMessage, StateSIWEMessage, } from './types'; -import { getDecodingData } from './utils/decoding-api'; +import { API_ERRORS, getDecodingData } from './utils/decoding-api'; import { normalizePersonalMessageParams, normalizeTypedMessageParams, @@ -917,8 +917,8 @@ export class SignatureController extends BaseController< draftMetadata.decodingData = { stateChanges: null, error: { - message: error as string, - type: 'DECODING_FAILED_WITH_ERROR', + message: (error as unknown as Error).message, + type: API_ERRORS.DECODING_FAILED_WITH_ERROR, }, }; draftMetadata.decodingLoading = false; diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index 2fa08152a91..0209f25f92f 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -1,7 +1,7 @@ import type { OriginalRequest } from '../types'; import { convertNumericValuesToQuotedString } from './normalize'; -const API_ERRORS = { +export const API_ERRORS = { UNSUPPORTED_SIGNATURE: 'UNSUPPORTED_SIGNATURE', DECODING_FAILED_WITH_ERROR: 'DECODING_FAILED_WITH_ERROR', }; From 9927cca8818e3db3d410a81bde0e5bb07e9ddc84 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 19:38:22 +0530 Subject: [PATCH 26/42] update --- .../src/SignatureController.test.ts | 26 ++++++++++++++++++- .../src/SignatureController.ts | 4 +-- .../src/utils/decoding-api.ts | 6 ++--- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.test.ts b/packages/signature-controller/src/SignatureController.test.ts index 167117a23dc..93848564dfc 100644 --- a/packages/signature-controller/src/SignatureController.test.ts +++ b/packages/signature-controller/src/SignatureController.test.ts @@ -914,7 +914,7 @@ describe('SignatureController', () => { }); // eslint-disable-next-line jest/no-disabled-tests - it('invoke decoding api for permits', async () => { + it('invoke getDecodingData to get decoding data', async () => { const MOCK_STATE_CHANGES = { stateChanges: [ { @@ -946,6 +946,30 @@ describe('SignatureController', () => { controller.state.signatureRequests[ID_MOCK].decodingData, ).toStrictEqual(MOCK_STATE_CHANGES); }); + + it('correctly set decoding data if getDecodingData fails', async () => { + const { controller } = createController(); + + jest + .spyOn(DecodingDataUtils, 'getDecodingData') + .mockRejectedValue(new Error('some error')); + + await controller.newUnsignedTypedMessage( + PERMIT_PARAMS_MOCK, + PERMIT_REQUEST_MOCK, + SignTypedDataVersion.V4, + { parseJsonData: false }, + ); + + expect(controller.state.signatureRequests[ID_MOCK].decodingLoading).toBe( + false, + ); + expect( + controller.state.signatureRequests[ID_MOCK].decodingData?.error.type, + ).toStrictEqual( + DecodingDataUtils.DECODING_API_ERRORS.DECODING_FAILED_WITH_ERROR, + ); + }); }); describe('setDeferredSignSuccess', () => { diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index 3fec221f252..f750e8f40ed 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -44,7 +44,7 @@ import type { LegacyStateMessage, StateSIWEMessage, } from './types'; -import { API_ERRORS, getDecodingData } from './utils/decoding-api'; +import { DECODING_API_ERRORS, getDecodingData } from './utils/decoding-api'; import { normalizePersonalMessageParams, normalizeTypedMessageParams, @@ -918,7 +918,7 @@ export class SignatureController extends BaseController< stateChanges: null, error: { message: (error as unknown as Error).message, - type: API_ERRORS.DECODING_FAILED_WITH_ERROR, + type: DECODING_API_ERRORS.DECODING_FAILED_WITH_ERROR, }, }; draftMetadata.decodingLoading = false; diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index 0209f25f92f..8dd632b298a 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -1,7 +1,7 @@ import type { OriginalRequest } from '../types'; import { convertNumericValuesToQuotedString } from './normalize'; -export const API_ERRORS = { +export const DECODING_API_ERRORS = { UNSUPPORTED_SIGNATURE: 'UNSUPPORTED_SIGNATURE', DECODING_FAILED_WITH_ERROR: 'DECODING_FAILED_WITH_ERROR', }; @@ -45,14 +45,14 @@ export async function getDecodingData( return { error: { message: 'Unsupported signature.', - type: API_ERRORS.UNSUPPORTED_SIGNATURE, + type: DECODING_API_ERRORS.UNSUPPORTED_SIGNATURE, }, }; } catch (error: unknown) { return { error: { message: (error as unknown as Error).message, - type: API_ERRORS.DECODING_FAILED_WITH_ERROR, + type: DECODING_API_ERRORS.DECODING_FAILED_WITH_ERROR, }, }; } From deb925d65d945a06bbb39e7c8ad4492b8caf87cc Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 30 Oct 2024 20:11:42 +0530 Subject: [PATCH 27/42] update --- packages/signature-controller/src/SignatureController.test.ts | 1 + packages/signature-controller/src/types.ts | 2 +- packages/signature-controller/src/utils/decoding-api.ts | 4 ++-- packages/signature-controller/src/utils/normalize.ts | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.test.ts b/packages/signature-controller/src/SignatureController.test.ts index 93848564dfc..178494d49ec 100644 --- a/packages/signature-controller/src/SignatureController.test.ts +++ b/packages/signature-controller/src/SignatureController.test.ts @@ -53,6 +53,7 @@ const PARAMS_MOCK = { const REQUEST_MOCK = { networkClientId: NETWORK_CLIENT_ID_MOCK, + params: [], }; const SIGNATURE_REQUEST_MOCK: SignatureRequest = { diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index 57dcb6d53a1..9b7e219558a 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -17,7 +17,7 @@ export type OriginalRequest = { origin?: string; /** Parameters in signature request */ - params?: string[]; + params: string[]; /** Response following a security scan of the request. */ securityAlertResponse?: Record; diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index 8dd632b298a..6431244ff42 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -33,8 +33,8 @@ export async function getDecodingData( method, origin, params: [ - params?.[0], - JSON.parse(convertNumericValuesToQuotedString(params?.[1]) ?? ''), + params[0], + JSON.parse(convertNumericValuesToQuotedString(params[1])), ], }), headers: { 'Content-Type': 'application/json' }, diff --git a/packages/signature-controller/src/utils/normalize.ts b/packages/signature-controller/src/utils/normalize.ts index 66164c737be..74e95b88f81 100644 --- a/packages/signature-controller/src/utils/normalize.ts +++ b/packages/signature-controller/src/utils/normalize.ts @@ -66,9 +66,9 @@ function normalizePersonalMessageData(data: string) { * @param str - String of JSON to be fixed. * @returns String with all numeric values converted to quoted strings. */ -export function convertNumericValuesToQuotedString(str?: string) { +export function convertNumericValuesToQuotedString(str: string) { if (!str) { - return str; + return ''; } return str?.replace(/(?<=:\s*)(-?\d+(\.\d+)?)(?=[,\]}])/gu, '"$1"'); } From e7cf0cf3285cd80dc380598c0ca5f2007e7eb5ae Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Mon, 4 Nov 2024 10:23:08 +0530 Subject: [PATCH 28/42] Update packages/signature-controller/src/SignatureController.ts Co-authored-by: Matthew Walsh --- packages/signature-controller/src/SignatureController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index f750e8f40ed..b0292d7f07f 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -157,7 +157,7 @@ export type SignatureControllerOptions = { ) => Promise; /** - * Api used to get decoding data for permits. + * URL of API to retrieve decoding data for typed requests. */ decodingApiUrl?: string; From 0d9818d19cc9f5faf70f219746966dd018cd1f92 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Mon, 4 Nov 2024 13:24:51 +0530 Subject: [PATCH 29/42] update --- .../src/SignatureController.test.ts | 107 +++++++++--------- .../src/SignatureController.ts | 4 +- packages/signature-controller/src/types.ts | 17 ++- .../src/utils/decoding-api.test.ts | 10 +- .../src/utils/decoding-api.ts | 2 +- 5 files changed, 75 insertions(+), 65 deletions(-) diff --git a/packages/signature-controller/src/SignatureController.test.ts b/packages/signature-controller/src/SignatureController.test.ts index 178494d49ec..37a20c844f9 100644 --- a/packages/signature-controller/src/SignatureController.test.ts +++ b/packages/signature-controller/src/SignatureController.test.ts @@ -914,62 +914,63 @@ describe('SignatureController', () => { ).toBe(SignTypedDataVersion.V3); }); - // eslint-disable-next-line jest/no-disabled-tests - it('invoke getDecodingData to get decoding data', async () => { - const MOCK_STATE_CHANGES = { - stateChanges: [ - { - assetType: 'ERC20', - changeType: 'APPROVE', - address: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad', - amount: '1461501637330902918203684832716283019655932542975', - contractAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', - }, - ], - }; - const { controller } = createController(); - - jest - .spyOn(DecodingDataUtils, 'getDecodingData') - .mockResolvedValue(MOCK_STATE_CHANGES); - - await controller.newUnsignedTypedMessage( - PERMIT_PARAMS_MOCK, - PERMIT_REQUEST_MOCK, - SignTypedDataVersion.V4, - { parseJsonData: false }, - ); + describe('decodeSignature', () => { + it('invoke decodeSignature to get decoding data', async () => { + const MOCK_STATE_CHANGES = { + stateChanges: [ + { + assetType: 'ERC20', + changeType: 'APPROVE', + address: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad', + amount: '1461501637330902918203684832716283019655932542975', + contractAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', + }, + ], + }; + const { controller } = createController(); + + jest + .spyOn(DecodingDataUtils, 'decodeSignature') + .mockResolvedValue(MOCK_STATE_CHANGES); + + await controller.newUnsignedTypedMessage( + PERMIT_PARAMS_MOCK, + PERMIT_REQUEST_MOCK, + SignTypedDataVersion.V4, + { parseJsonData: false }, + ); - expect(controller.state.signatureRequests[ID_MOCK].decodingLoading).toBe( - false, - ); - expect( - controller.state.signatureRequests[ID_MOCK].decodingData, - ).toStrictEqual(MOCK_STATE_CHANGES); - }); + expect( + controller.state.signatureRequests[ID_MOCK].decodingLoading, + ).toBe(false); + expect( + controller.state.signatureRequests[ID_MOCK].decodingData, + ).toStrictEqual(MOCK_STATE_CHANGES); + }); - it('correctly set decoding data if getDecodingData fails', async () => { - const { controller } = createController(); + it('correctly set decoding data if decodeSignature fails', async () => { + const { controller } = createController(); - jest - .spyOn(DecodingDataUtils, 'getDecodingData') - .mockRejectedValue(new Error('some error')); + jest + .spyOn(DecodingDataUtils, 'decodeSignature') + .mockRejectedValue(new Error('some error')); - await controller.newUnsignedTypedMessage( - PERMIT_PARAMS_MOCK, - PERMIT_REQUEST_MOCK, - SignTypedDataVersion.V4, - { parseJsonData: false }, - ); + await controller.newUnsignedTypedMessage( + PERMIT_PARAMS_MOCK, + PERMIT_REQUEST_MOCK, + SignTypedDataVersion.V4, + { parseJsonData: false }, + ); - expect(controller.state.signatureRequests[ID_MOCK].decodingLoading).toBe( - false, - ); - expect( - controller.state.signatureRequests[ID_MOCK].decodingData?.error.type, - ).toStrictEqual( - DecodingDataUtils.DECODING_API_ERRORS.DECODING_FAILED_WITH_ERROR, - ); + expect( + controller.state.signatureRequests[ID_MOCK].decodingLoading, + ).toBe(false); + expect( + controller.state.signatureRequests[ID_MOCK].decodingData?.error.type, + ).toStrictEqual( + DecodingDataUtils.DECODING_API_ERRORS.DECODING_FAILED_WITH_ERROR, + ); + }); }); }); @@ -1001,7 +1002,7 @@ describe('SignatureController', () => { const { controller } = createController(); let resolved = false; - jest.spyOn(DecodingDataUtils, 'getDecodingData').mockResolvedValue({}); + jest.spyOn(DecodingDataUtils, 'decodeSignature').mockResolvedValue({}); const signaturePromise = controller .newUnsignedPersonalMessage( @@ -1081,7 +1082,7 @@ describe('SignatureController', () => { const { controller } = createController(); let rejectedError; - jest.spyOn(DecodingDataUtils, 'getDecodingData').mockResolvedValue({}); + jest.spyOn(DecodingDataUtils, 'decodeSignature').mockResolvedValue({}); controller .newUnsignedPersonalMessage( diff --git a/packages/signature-controller/src/SignatureController.ts b/packages/signature-controller/src/SignatureController.ts index f750e8f40ed..dc84d808079 100644 --- a/packages/signature-controller/src/SignatureController.ts +++ b/packages/signature-controller/src/SignatureController.ts @@ -44,7 +44,7 @@ import type { LegacyStateMessage, StateSIWEMessage, } from './types'; -import { DECODING_API_ERRORS, getDecodingData } from './utils/decoding-api'; +import { DECODING_API_ERRORS, decodeSignature } from './utils/decoding-api'; import { normalizePersonalMessageParams, normalizeTypedMessageParams, @@ -905,7 +905,7 @@ export class SignatureController extends BaseController< this.#updateMetadata(signatureRequestId, (draftMetadata) => { draftMetadata.decodingLoading = true; }); - getDecodingData(request, chainId, this.#decodingApiUrl) + decodeSignature(request, chainId, this.#decodingApiUrl) .then((decodingData) => this.#updateMetadata(signatureRequestId, (draftMetadata) => { draftMetadata.decodingData = decodingData; diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index 9b7e219558a..ec82858dba8 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -81,14 +81,23 @@ export type MessageParamsTyped = MessageParams & { version?: string; }; -/** Information about various state changes returned by decoding api. */ -type DecodingDataStateChanges = { +/** Information about a single state change returned by decoding api. */ +type DecodingDataStateChange = { assetType: string; - changeType: string; + changeType: + | 'RECEIVE' + | 'TRANSFER' + | 'APPROVE' + | 'REVOKE_APPROVE' + | 'BIDDING' + | 'LISTING'; address: string; amount: string; contractAddress: string; -}[]; +}; + +/** Array of the various state changes returned by decoding api. */ +type DecodingDataStateChanges = DecodingDataStateChange[]; /** Error details for unfulfilled the decoding request. */ type DecodingDataError = { diff --git a/packages/signature-controller/src/utils/decoding-api.test.ts b/packages/signature-controller/src/utils/decoding-api.test.ts index 3e8ae3dc1e7..c5f41086785 100644 --- a/packages/signature-controller/src/utils/decoding-api.test.ts +++ b/packages/signature-controller/src/utils/decoding-api.test.ts @@ -2,7 +2,7 @@ import nock from 'nock'; import nodeFetch from 'node-fetch'; import type { OriginalRequest } from '../types'; -import { getDecodingData } from './decoding-api'; +import { decodeSignature } from './decoding-api'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore-next-line @@ -48,7 +48,7 @@ describe('Decoding api', () => { .post('/signature?chainId=0x1') .reply(200, JSON.stringify(MOCK_RESULT)); - const result = await getDecodingData( + const result = await decodeSignature( PERMIT_REQUEST_MOCK, '0x1', 'https://testdecodingurl.com', @@ -62,7 +62,7 @@ describe('Decoding api', () => { .post('/signature?chainId=0x1') .reply(200, JSON.stringify(MOCK_ERROR)); - const result = await getDecodingData( + const result = await decodeSignature( PERMIT_REQUEST_MOCK, '0x1', 'https://testdecodingurl.com', @@ -72,7 +72,7 @@ describe('Decoding api', () => { }); it('return failure error if there is an exception while validating', async () => { - const result = await getDecodingData( + const result = await decodeSignature( PERMIT_REQUEST_MOCK, '0x1', 'https://testdecodingurl.com', @@ -82,7 +82,7 @@ describe('Decoding api', () => { }); it('return undefined for request not of method eth_signTypedData_v4', async () => { - const result = await getDecodingData( + const result = await decodeSignature( { method: 'eth_signTypedData_v3' } as OriginalRequest, '0x1', 'https://testdecodingurl.com', diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index 6431244ff42..b1079f6dbb6 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -14,7 +14,7 @@ export const DECODING_API_ERRORS = { * @param decodingApiUrl - URL of decoding api. * @returns Promise that resolved to give decoded data. */ -export async function getDecodingData( +export async function decodeSignature( request: OriginalRequest, chainId: string, decodingApiUrl?: string, From 33cb319960f1e9339731c0f85abf67f5e44c0f14 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Mon, 4 Nov 2024 13:33:13 +0530 Subject: [PATCH 30/42] Update packages/signature-controller/src/types.ts Co-authored-by: Matthew Walsh --- packages/signature-controller/src/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index ec82858dba8..f833951f674 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -118,7 +118,7 @@ type SignatureRequestBase = { /** Response from message decoding api. */ decodingData?: DecodingData; - /** Field to know if decoding request is in progress */ + /** Whether decoding is in progress. */ decodingLoading?: boolean; /** Error message that occurred during the signing. */ From 4ae4551748a3cefcb260b1a0454c97059c1d4c87 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Mon, 4 Nov 2024 14:57:40 +0530 Subject: [PATCH 31/42] update --- packages/signature-controller/package.json | 2 +- .../src/utils/decoding-api.test.ts | 27 ++++++++++++++----- .../src/utils/decoding-api.ts | 4 ++- yarn.lock | 2 +- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/packages/signature-controller/package.json b/packages/signature-controller/package.json index fa32f9e9e1e..25577fc3c5b 100644 --- a/packages/signature-controller/package.json +++ b/packages/signature-controller/package.json @@ -58,6 +58,7 @@ "devDependencies": { "@metamask/approval-controller": "^7.1.1", "@metamask/auto-changelog": "^3.4.4", + "@metamask/keyring-api": "^8.1.3", "@metamask/keyring-controller": "^17.3.0", "@metamask/logging-controller": "^6.0.1", "@metamask/network-controller": "^22.0.0", @@ -65,7 +66,6 @@ "@types/node-fetch": "^2.6.11", "deepmerge": "^4.2.2", "jest": "^27.5.1", - "nock": "^13.3.1", "node-fetch": "npm:^2.6.1", "ts-jest": "^27.1.4", "typedoc": "^0.24.8", diff --git a/packages/signature-controller/src/utils/decoding-api.test.ts b/packages/signature-controller/src/utils/decoding-api.test.ts index c5f41086785..7d41d1e7de4 100644 --- a/packages/signature-controller/src/utils/decoding-api.test.ts +++ b/packages/signature-controller/src/utils/decoding-api.test.ts @@ -1,4 +1,3 @@ -import nock from 'nock'; import nodeFetch from 'node-fetch'; import type { OriginalRequest } from '../types'; @@ -43,10 +42,23 @@ const MOCK_ERROR = { }; describe('Decoding api', () => { + let fetchMock: jest.MockedFunction; + + /** + * Mock a JSON response from fetch. + * @param jsonResponse - The response body to return. + */ + function mockFetchResponse(jsonResponse: unknown) { + fetchMock.mockResolvedValueOnce({ + json: jest.fn().mockResolvedValue(jsonResponse), + } as unknown as Response); + } + it('return the data from api', async () => { - nock('https://testdecodingurl.com') - .post('/signature?chainId=0x1') - .reply(200, JSON.stringify(MOCK_RESULT)); + fetchMock = jest.spyOn(global, 'fetch') as jest.MockedFunction< + typeof fetch + >; + mockFetchResponse(MOCK_RESULT); const result = await decodeSignature( PERMIT_REQUEST_MOCK, @@ -58,9 +70,10 @@ describe('Decoding api', () => { }); it('return error from the api as it is', async () => { - nock('https://testdecodingurl.com') - .post('/signature?chainId=0x1') - .reply(200, JSON.stringify(MOCK_ERROR)); + fetchMock = jest.spyOn(global, 'fetch') as jest.MockedFunction< + typeof fetch + >; + mockFetchResponse(MOCK_ERROR); const result = await decodeSignature( PERMIT_REQUEST_MOCK, diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index b1079f6dbb6..144ca0cd941 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -1,3 +1,5 @@ +import { EthMethod } from '@metamask/keyring-api'; + import type { OriginalRequest } from '../types'; import { convertNumericValuesToQuotedString } from './normalize'; @@ -24,7 +26,7 @@ export async function decodeSignature( } try { const { method, origin, params } = request; - if (request.method === 'eth_signTypedData_v4') { + if (request.method === EthMethod.SignTypedDataV4) { const response = await fetch( `${decodingApiUrl}/signature?chainId=${chainId}`, { diff --git a/yarn.lock b/yarn.lock index 2ac953fb286..4ff2d962c23 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3487,6 +3487,7 @@ __metadata: "@metamask/base-controller": "npm:^7.0.2" "@metamask/controller-utils": "npm:^11.4.1" "@metamask/eth-sig-util": "npm:^8.0.0" + "@metamask/keyring-api": "npm:^8.1.3" "@metamask/keyring-controller": "npm:^17.3.0" "@metamask/logging-controller": "npm:^6.0.1" "@metamask/network-controller": "npm:^22.0.0" @@ -3497,7 +3498,6 @@ __metadata: jest: "npm:^27.5.1" jsonschema: "npm:^1.2.4" lodash: "npm:^4.17.21" - nock: "npm:^13.3.1" node-fetch: "npm:^2.6.1" ts-jest: "npm:^27.1.4" typedoc: "npm:^0.24.8" From 80ff99b9801daed37b2bc172bcb7c57751db99ce Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Mon, 4 Nov 2024 15:39:48 +0530 Subject: [PATCH 32/42] update --- .../src/SignatureController.test.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/signature-controller/src/SignatureController.test.ts b/packages/signature-controller/src/SignatureController.test.ts index 37a20c844f9..40176a9711e 100644 --- a/packages/signature-controller/src/SignatureController.test.ts +++ b/packages/signature-controller/src/SignatureController.test.ts @@ -971,6 +971,31 @@ describe('SignatureController', () => { DecodingDataUtils.DECODING_API_ERRORS.DECODING_FAILED_WITH_ERROR, ); }); + + it('set decodingLoading to true while api request is in progress', async () => { + const { controller } = createController(); + + jest + .spyOn(DecodingDataUtils, 'decodeSignature') + .mockImplementation(() => { + return new Promise((resolve) => { + setTimeout(() => { + resolve({}); + }, 300); + }); + }); + + await controller.newUnsignedTypedMessage( + PERMIT_PARAMS_MOCK, + PERMIT_REQUEST_MOCK, + SignTypedDataVersion.V4, + { parseJsonData: false }, + ); + + expect( + controller.state.signatureRequests[ID_MOCK].decodingLoading, + ).toBe(true); + }); }); }); From 6b100c0b6d3ef618d8419b111040de46c8fa502b Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Mon, 4 Nov 2024 20:31:49 +0530 Subject: [PATCH 33/42] update --- packages/signature-controller/package.json | 2 -- .../signature-controller/src/utils/decoding-api.test.ts | 6 ------ 2 files changed, 8 deletions(-) diff --git a/packages/signature-controller/package.json b/packages/signature-controller/package.json index 27093d97c34..2c05bf2bcde 100644 --- a/packages/signature-controller/package.json +++ b/packages/signature-controller/package.json @@ -63,10 +63,8 @@ "@metamask/logging-controller": "^6.0.1", "@metamask/network-controller": "^22.0.1", "@types/jest": "^27.4.1", - "@types/node-fetch": "^2.6.11", "deepmerge": "^4.2.2", "jest": "^27.5.1", - "node-fetch": "npm:^2.6.1", "ts-jest": "^27.1.4", "typedoc": "^0.24.8", "typedoc-plugin-missing-exports": "^2.0.0", diff --git a/packages/signature-controller/src/utils/decoding-api.test.ts b/packages/signature-controller/src/utils/decoding-api.test.ts index 7d41d1e7de4..84f62bde47c 100644 --- a/packages/signature-controller/src/utils/decoding-api.test.ts +++ b/packages/signature-controller/src/utils/decoding-api.test.ts @@ -1,12 +1,6 @@ -import nodeFetch from 'node-fetch'; - import type { OriginalRequest } from '../types'; import { decodeSignature } from './decoding-api'; -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore-next-line -global.fetch = nodeFetch; - const PERMIT_REQUEST_MOCK = { method: 'eth_signTypedData_v4', params: [ From 82e307636ab675ec9828b0ea2f3ab2a27bf10d06 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Mon, 4 Nov 2024 20:34:45 +0530 Subject: [PATCH 34/42] update --- yarn.lock | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/yarn.lock b/yarn.lock index d33ee4d3ba4..6141313927e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3494,12 +3494,10 @@ __metadata: "@metamask/network-controller": "npm:^22.0.1" "@metamask/utils": "npm:^10.0.0" "@types/jest": "npm:^27.4.1" - "@types/node-fetch": "npm:^2.6.11" deepmerge: "npm:^4.2.2" jest: "npm:^27.5.1" jsonschema: "npm:^1.2.4" lodash: "npm:^4.17.21" - node-fetch: "npm:^2.6.1" ts-jest: "npm:^27.1.4" typedoc: "npm:^0.24.8" typedoc-plugin-missing-exports: "npm:^2.0.0" @@ -4467,16 +4465,6 @@ __metadata: languageName: node linkType: hard -"@types/node-fetch@npm:^2.6.11": - version: 2.6.11 - resolution: "@types/node-fetch@npm:2.6.11" - dependencies: - "@types/node": "npm:*" - form-data: "npm:^4.0.0" - checksum: 10/c416df8f182ec3826278ea42557fda08f169a48a05e60722d9c8edd4e5b2076ae281c6b6601ad406035b7201f885b0257983b61c26b3f9eb0f41192a807b5de5 - languageName: node - linkType: hard - "@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0": version: 22.5.0 resolution: "@types/node@npm:22.5.0" From 94caf4c2ea7e51252535681a888c9cae1b3e79eb Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 5 Nov 2024 20:19:30 +0530 Subject: [PATCH 35/42] update --- packages/signature-controller/src/types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index f833951f674..c0aacefe90b 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -82,7 +82,7 @@ export type MessageParamsTyped = MessageParams & { }; /** Information about a single state change returned by decoding api. */ -type DecodingDataStateChange = { +export type DecodingDataStateChange = { assetType: string; changeType: | 'RECEIVE' @@ -97,10 +97,10 @@ type DecodingDataStateChange = { }; /** Array of the various state changes returned by decoding api. */ -type DecodingDataStateChanges = DecodingDataStateChange[]; +export type DecodingDataStateChanges = DecodingDataStateChange[]; /** Error details for unfulfilled the decoding request. */ -type DecodingDataError = { +export type DecodingDataError = { message: string; type: string; }; From 3edc64d27d3c0865366591541995348230cbad13 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 6 Nov 2024 09:22:02 +0530 Subject: [PATCH 36/42] update --- .../signature-controller/src/constants.ts | 8 ++++++++ packages/signature-controller/src/types.ts | 19 +++++++++++-------- .../src/utils/decoding-api.ts | 3 +-- 3 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 packages/signature-controller/src/constants.ts diff --git a/packages/signature-controller/src/constants.ts b/packages/signature-controller/src/constants.ts new file mode 100644 index 00000000000..d54589e757a --- /dev/null +++ b/packages/signature-controller/src/constants.ts @@ -0,0 +1,8 @@ +export declare enum EthMethod { + PersonalSign = 'personal_sign', + Sign = 'eth_sign', + SignTransaction = 'eth_signTransaction', + SignTypedDataV1 = 'eth_signTypedData_v1', + SignTypedDataV3 = 'eth_signTypedData_v3', + SignTypedDataV4 = 'eth_signTypedData_v4', +} diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index c0aacefe90b..1b1b6c2953c 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -81,16 +81,19 @@ export type MessageParamsTyped = MessageParams & { version?: string; }; +/** Different decoding data state change types */ +export type DecodingDataChangeType = + | 'RECEIVE' + | 'TRANSFER' + | 'APPROVE' + | 'REVOKE_APPROVE' + | 'BIDDING' + | 'LISTING'; + /** Information about a single state change returned by decoding api. */ export type DecodingDataStateChange = { assetType: string; - changeType: - | 'RECEIVE' - | 'TRANSFER' - | 'APPROVE' - | 'REVOKE_APPROVE' - | 'BIDDING' - | 'LISTING'; + changeType: DecodingDataChangeType; address: string; amount: string; contractAddress: string; @@ -108,7 +111,7 @@ export type DecodingDataError = { /** Decoding data about typed sign V4 signature request. */ export type DecodingData = { stateChanges: DecodingDataStateChanges | null; - error: DecodingDataError; + error?: DecodingDataError; }; type SignatureRequestBase = { diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index 144ca0cd941..d3a52f9bbf6 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -1,5 +1,4 @@ -import { EthMethod } from '@metamask/keyring-api'; - +import { EthMethod } from '../constants'; import type { OriginalRequest } from '../types'; import { convertNumericValuesToQuotedString } from './normalize'; From 4b165e1f63066e81712ddddd4818bbc9d92da270 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 6 Nov 2024 09:28:03 +0530 Subject: [PATCH 37/42] update --- packages/signature-controller/src/SignatureController.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/signature-controller/src/SignatureController.test.ts b/packages/signature-controller/src/SignatureController.test.ts index 40176a9711e..cbe2eb5772c 100644 --- a/packages/signature-controller/src/SignatureController.test.ts +++ b/packages/signature-controller/src/SignatureController.test.ts @@ -966,7 +966,7 @@ describe('SignatureController', () => { controller.state.signatureRequests[ID_MOCK].decodingLoading, ).toBe(false); expect( - controller.state.signatureRequests[ID_MOCK].decodingData?.error.type, + controller.state.signatureRequests[ID_MOCK].decodingData?.error?.type, ).toStrictEqual( DecodingDataUtils.DECODING_API_ERRORS.DECODING_FAILED_WITH_ERROR, ); From cdefae99c655f539ddec8088d4b43e8247b43b03 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 6 Nov 2024 09:33:44 +0530 Subject: [PATCH 38/42] update --- packages/signature-controller/src/constants.ts | 16 ++++++++-------- .../src/utils/decoding-api.test.ts | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/signature-controller/src/constants.ts b/packages/signature-controller/src/constants.ts index d54589e757a..9ef5c192ae5 100644 --- a/packages/signature-controller/src/constants.ts +++ b/packages/signature-controller/src/constants.ts @@ -1,8 +1,8 @@ -export declare enum EthMethod { - PersonalSign = 'personal_sign', - Sign = 'eth_sign', - SignTransaction = 'eth_signTransaction', - SignTypedDataV1 = 'eth_signTypedData_v1', - SignTypedDataV3 = 'eth_signTypedData_v3', - SignTypedDataV4 = 'eth_signTypedData_v4', -} +export const EthMethod = { + PersonalSign: 'personal_sign', + Sign: 'eth_sign', + SignTransaction: 'eth_signTransaction', + SignTypedDataV1: 'eth_signTypedData_v1', + SignTypedDataV3: 'eth_signTypedData_v3', + SignTypedDataV4: 'eth_signTypedData_v4', +}; diff --git a/packages/signature-controller/src/utils/decoding-api.test.ts b/packages/signature-controller/src/utils/decoding-api.test.ts index 84f62bde47c..4e6a567c838 100644 --- a/packages/signature-controller/src/utils/decoding-api.test.ts +++ b/packages/signature-controller/src/utils/decoding-api.test.ts @@ -1,8 +1,9 @@ +import { EthMethod } from '../constants'; import type { OriginalRequest } from '../types'; import { decodeSignature } from './decoding-api'; const PERMIT_REQUEST_MOCK = { - method: 'eth_signTypedData_v4', + method: EthMethod.SignTypedDataV4, params: [ '0x975e73efb9ff52e23bac7f7e043a1ecd06d05477', '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Permit":[{"name":"owner","type":"address"},{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"}]},"primaryType":"Permit","domain":{"name":"MyToken","version":"1","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","chainId":1},"message":{"owner":"0x975e73efb9ff52e23bac7f7e043a1ecd06d05477","spender":"0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","value":3000,"nonce":0,"deadline":50000000000}}', From f1d7dc8199f53092dddfa3ea7b1d89a3a9426d66 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 6 Nov 2024 10:37:17 +0530 Subject: [PATCH 39/42] update --- packages/signature-controller/src/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index 1b1b6c2953c..c6e8b7c48ca 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -97,6 +97,7 @@ export type DecodingDataStateChange = { address: string; amount: string; contractAddress: string; + tokenID?: string; }; /** Array of the various state changes returned by decoding api. */ From 108749f357385188b88ef408c09f5c940a428486 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 6 Nov 2024 21:31:01 +0530 Subject: [PATCH 40/42] update --- packages/signature-controller/package.json | 1 - packages/signature-controller/src/constants.ts | 8 -------- packages/signature-controller/src/types.ts | 11 +++++++++++ .../signature-controller/src/utils/decoding-api.ts | 3 +-- yarn.lock | 1 - 5 files changed, 12 insertions(+), 12 deletions(-) delete mode 100644 packages/signature-controller/src/constants.ts diff --git a/packages/signature-controller/package.json b/packages/signature-controller/package.json index 2c05bf2bcde..bfa14109ba0 100644 --- a/packages/signature-controller/package.json +++ b/packages/signature-controller/package.json @@ -58,7 +58,6 @@ "devDependencies": { "@metamask/approval-controller": "^7.1.1", "@metamask/auto-changelog": "^3.4.4", - "@metamask/keyring-api": "^8.1.3", "@metamask/keyring-controller": "^17.3.1", "@metamask/logging-controller": "^6.0.1", "@metamask/network-controller": "^22.0.1", diff --git a/packages/signature-controller/src/constants.ts b/packages/signature-controller/src/constants.ts deleted file mode 100644 index 9ef5c192ae5..00000000000 --- a/packages/signature-controller/src/constants.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const EthMethod = { - PersonalSign: 'personal_sign', - Sign: 'eth_sign', - SignTransaction: 'eth_signTransaction', - SignTypedDataV1: 'eth_signTypedData_v1', - SignTypedDataV3: 'eth_signTypedData_v3', - SignTypedDataV4: 'eth_signTypedData_v4', -}; diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index c6e8b7c48ca..ee701b62aa2 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -193,3 +193,14 @@ export enum SignatureRequestType { PersonalSign = 'personal_sign', TypedSign = 'eth_signTypedData', } + +/** + * Supported signature methods. + */ +export declare enum EthMethod { + PersonalSign = 'personal_sign', + SignTransaction = 'eth_signTransaction', + SignTypedDataV1 = 'eth_signTypedData_v1', + SignTypedDataV3 = 'eth_signTypedData_v3', + SignTypedDataV4 = 'eth_signTypedData_v4', +} diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index d3a52f9bbf6..21d4b24ea95 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -1,5 +1,4 @@ -import { EthMethod } from '../constants'; -import type { OriginalRequest } from '../types'; +import { EthMethod, type OriginalRequest } from '../types'; import { convertNumericValuesToQuotedString } from './normalize'; export const DECODING_API_ERRORS = { diff --git a/yarn.lock b/yarn.lock index 6141313927e..310ad33debe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3488,7 +3488,6 @@ __metadata: "@metamask/base-controller": "npm:^7.0.2" "@metamask/controller-utils": "npm:^11.4.2" "@metamask/eth-sig-util": "npm:^8.0.0" - "@metamask/keyring-api": "npm:^8.1.3" "@metamask/keyring-controller": "npm:^17.3.1" "@metamask/logging-controller": "npm:^6.0.1" "@metamask/network-controller": "npm:^22.0.1" From 64395a3fe80ff021b03c993d6e306450f00c5add Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 6 Nov 2024 21:38:08 +0530 Subject: [PATCH 41/42] update --- packages/signature-controller/src/utils/decoding-api.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/signature-controller/src/utils/decoding-api.test.ts b/packages/signature-controller/src/utils/decoding-api.test.ts index 4e6a567c838..e8ee61d31cc 100644 --- a/packages/signature-controller/src/utils/decoding-api.test.ts +++ b/packages/signature-controller/src/utils/decoding-api.test.ts @@ -1,5 +1,4 @@ -import { EthMethod } from '../constants'; -import type { OriginalRequest } from '../types'; +import { EthMethod, type OriginalRequest } from '../types'; import { decodeSignature } from './decoding-api'; const PERMIT_REQUEST_MOCK = { From fae20c716bf3d1c4fd30b4fa6ab7555d262fbc60 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 6 Nov 2024 21:44:13 +0530 Subject: [PATCH 42/42] update --- packages/signature-controller/src/constants.ts | 10 ++++++++++ packages/signature-controller/src/types.ts | 11 ----------- .../src/utils/decoding-api.test.ts | 3 ++- .../signature-controller/src/utils/decoding-api.ts | 3 ++- 4 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 packages/signature-controller/src/constants.ts diff --git a/packages/signature-controller/src/constants.ts b/packages/signature-controller/src/constants.ts new file mode 100644 index 00000000000..93cbf22f8c8 --- /dev/null +++ b/packages/signature-controller/src/constants.ts @@ -0,0 +1,10 @@ +/** + * Supported signature methods. + */ +export const EthMethod = { + PersonalSign: 'personal_sign', + SignTransaction: 'eth_signTransaction', + SignTypedDataV1: 'eth_signTypedData_v1', + SignTypedDataV3: 'eth_signTypedData_v3', + SignTypedDataV4: 'eth_signTypedData_v4', +}; diff --git a/packages/signature-controller/src/types.ts b/packages/signature-controller/src/types.ts index ee701b62aa2..c6e8b7c48ca 100644 --- a/packages/signature-controller/src/types.ts +++ b/packages/signature-controller/src/types.ts @@ -193,14 +193,3 @@ export enum SignatureRequestType { PersonalSign = 'personal_sign', TypedSign = 'eth_signTypedData', } - -/** - * Supported signature methods. - */ -export declare enum EthMethod { - PersonalSign = 'personal_sign', - SignTransaction = 'eth_signTransaction', - SignTypedDataV1 = 'eth_signTypedData_v1', - SignTypedDataV3 = 'eth_signTypedData_v3', - SignTypedDataV4 = 'eth_signTypedData_v4', -} diff --git a/packages/signature-controller/src/utils/decoding-api.test.ts b/packages/signature-controller/src/utils/decoding-api.test.ts index e8ee61d31cc..67f66bc0cc3 100644 --- a/packages/signature-controller/src/utils/decoding-api.test.ts +++ b/packages/signature-controller/src/utils/decoding-api.test.ts @@ -1,4 +1,5 @@ -import { EthMethod, type OriginalRequest } from '../types'; +import { EthMethod } from '../constants'; +import { type OriginalRequest } from '../types'; import { decodeSignature } from './decoding-api'; const PERMIT_REQUEST_MOCK = { diff --git a/packages/signature-controller/src/utils/decoding-api.ts b/packages/signature-controller/src/utils/decoding-api.ts index 21d4b24ea95..b4baddab242 100644 --- a/packages/signature-controller/src/utils/decoding-api.ts +++ b/packages/signature-controller/src/utils/decoding-api.ts @@ -1,4 +1,5 @@ -import { EthMethod, type OriginalRequest } from '../types'; +import { EthMethod } from '../constants'; +import { type OriginalRequest } from '../types'; import { convertNumericValuesToQuotedString } from './normalize'; export const DECODING_API_ERRORS = {