diff --git a/packages/tx-categorize/src/txCategorize.test.ts b/packages/tx-categorize/src/txCategorize.test.ts index c00af53..2174069 100644 --- a/packages/tx-categorize/src/txCategorize.test.ts +++ b/packages/tx-categorize/src/txCategorize.test.ts @@ -344,6 +344,23 @@ describe('#txCategorizeV6', () => { ) expect(categorizedTxV5['readable']).toMatch(/^Sent/) }) + it('categorizes a contract call with methodId but no logs as GENERIC_CONTRACT_CALL, not STANDARD', async () => { + // ENS commit() tx: has a methodId (0xf14fcbc8) and targets a known contract, but emits no logs + const txHash = '0xf877a64271e53923c7138e87d8fc7c9dddadb14051ffc396e205d0951e94e171' + const { data, chainId } = await getTxWithLogsFromPrimitives(txHash) + const result = determineTransactionMetadataV6( + { + transaction: data, + subjectAddress: createAccountId(data.from, chainId), + }, + Language.en, + false, + 49, + ) + expect(result['transactionType']).toBe('GENERIC_CONTRACT_CALL') + expect(result['transactionCategory']).toBe('CONTRACT_CALL') + expect(result['readable']).toBe('Unidentified Transaction') + }) it('properly attaches a spam label to a dust native transfer', async () => { const txHash = '0xeda92a5cf7dc7e329ed123d85df969c075707758a853e0c5f0f77c1cf772b3bc' const { data, chainId } = await getTxWithLogsFromPrimitives(txHash) diff --git a/packages/tx-categorize/src/txCategorizeV6.ts b/packages/tx-categorize/src/txCategorizeV6.ts index 88c7a1e..5ca2c54 100644 --- a/packages/tx-categorize/src/txCategorizeV6.ts +++ b/packages/tx-categorize/src/txCategorizeV6.ts @@ -320,7 +320,7 @@ export const determineTransactionMetadataV6 = ( readable: tV2(Action.CONTRACT_CALL), } - if (!transaction.logs || !transaction.logs.length || !transaction.methodId) { + if ((!transaction.logs || !transaction.logs.length) && !transaction.methodId) { fallbackMetadata.transactionType = 'STANDARD' fallbackMetadata.transactionCategory = Action.STANDARD } diff --git a/packages/tx-categorize/test-fixtures/nock/1-0xf877a64271e53923c7138e87d8fc7c9dddadb14051ffc396e205d0951e94e171.json b/packages/tx-categorize/test-fixtures/nock/1-0xf877a64271e53923c7138e87d8fc7c9dddadb14051ffc396e205d0951e94e171.json new file mode 100644 index 0000000..49a60d9 --- /dev/null +++ b/packages/tx-categorize/test-fixtures/nock/1-0xf877a64271e53923c7138e87d8fc7c9dddadb14051ffc396e205d0951e94e171.json @@ -0,0 +1,61 @@ +[ + { + "scope": "https://primitives.api.cx.metamask.io:443", + "method": "GET", + "path": "/v1/networks/1/transactions/0xf877a64271e53923c7138e87d8fc7c9dddadb14051ffc396e205d0951e94e171?includeLogs=true&includeValueTransfers=true", + "body": "", + "status": 200, + "response": "1b880200649bbffaaa4fcddd2401efbf9840807deba6930397b61492cf53cf5bad791c659649eec4e78a55b19fa77e85dde979de0e90004f3d789f9d614fcdeac85a3ce9d082afa18b97586bcdb590414bbd8b8eae31da8ad1528ba691275020431e2f5e5448a44096fbc50e1229a87997215d61c8db0112201beff80948c0c8f601f503c7cf4c49bb64fc2322fe0451b9325bcaf4ed7e5eda06123359cb214010c4ea166b0c85a8a1732c2ee458503a7309120cb37345bae8688ace46478fc13a9b5d419743abce808251de4232ce99a86094b75fb6ad42328e9dc74bef37636990401b328690342898a3e2594d62b15c4883a44d5020fbf97e961b8820401823a28b0ae66d372ceb8beac720d3a5480005e7cb4a4880a060b774dbcd41e78e858338168c2cd1b3efd41a464196ecd8b7e2bb05057db39c27346729fa620b3ae6104ae91c1183442e18903047aed5792f15148cb74f369be50652cfb36d53810f46ba7adb6c21fdfaa360b61c6d21fdfa73bf03", + "rawHeaders": [ + "Date", + "Tue, 21 Apr 2026 19:04:22 GMT", + "Content-Type", + "application/json; charset=utf-8", + "Transfer-Encoding", + "chunked", + "Connection", + "keep-alive", + "content-security-policy", + "default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests", + "cross-origin-opener-policy", + "same-origin", + "cross-origin-resource-policy", + "same-origin", + "origin-agent-cluster", + "?1", + "referrer-policy", + "no-referrer", + "strict-transport-security", + "max-age=15552000; includeSubDomains", + "x-content-type-options", + "nosniff", + "x-dns-prefetch-control", + "off", + "x-download-options", + "noopen", + "x-frame-options", + "SAMEORIGIN", + "x-permitted-cross-domain-policies", + "none", + "x-xss-protection", + "0", + "vary", + "Origin", + "Cache-Control", + "max-age=15", + "x-cache", + "MISS", + "cf-cache-status", + "DYNAMIC", + "set-cookie", + "__cf_bm=cCbZMoXe_0mJLPXuCyo8YSUPPGfpqwGedyy6ouxbXRo-1776798262.507317-1.0.1.1-8KIQFPb1p1gnojhEI5iK3NeQNfuH9D_Agf6jm91eh_6E9k2BqO2Ve2l91tsUWUIZwdYjYCStVnPa.boZZmd6Q_vnYMV96OPO2q7dBIz6braZK97c4agK6S2zkEsRloyU; HttpOnly; Secure; Path=/; Domain=api.cx.metamask.io; Expires=Tue, 21 Apr 2026 19:34:22 GMT", + "Content-Encoding", + "br", + "Server", + "cloudflare", + "CF-RAY", + "9efea774ae23760a-SEA" + ], + "responseIsBinary": true + } +] \ No newline at end of file