From 801b8cae3f6b15c107037f8e47c4b42fcf7bdbba Mon Sep 17 00:00:00 2001 From: MexicanAce Date: Sat, 30 Nov 2024 22:34:38 -0600 Subject: [PATCH] feat: update display of transaction method selectors to human readable names --- .../app/src/components/transactions/Table.vue | 106 +++++++++++++++--- 1 file changed, 91 insertions(+), 15 deletions(-) diff --git a/packages/app/src/components/transactions/Table.vue b/packages/app/src/components/transactions/Table.vue index fab1c6245..bdc2e3891 100644 --- a/packages/app/src/components/transactions/Table.vue +++ b/packages/app/src/components/transactions/Table.vue @@ -58,9 +58,13 @@ -
- {{ item.methodName }} -
+ +
+ {{ item.methodName }} +
+ + +
{ +interface OpenChainMethod { + name: string; + filtered: boolean; +} + +interface OpenChainResponse { + ok: boolean; + result: { + function: Record; + }; +} + +const fetchMethodNames = async (sighashes: string[]): Promise> => { + try { + const response = await $fetch("https://api.openchain.xyz/signature-database/v1/lookup", { + method: "GET", + params: { + function: sighashes.join(","), + filter: true, + }, + headers: { + accept: "application/json", + }, + }); + + const result = response?.result?.function ?? {}; + const methodNames: Record = {}; + + Object.entries(result).forEach(([sighash, methods]) => { + // Ensure methods is an array of the expected shape + if (Array.isArray(methods)) { + methods.forEach((method) => { + if (typeof method === "object" && method.name && method.name.split("(").length > 1) { + methodNames[sighash] = method.name.split("(")[0]; + } + }); + } + }); + + return methodNames; + } catch (error) { + console.error("Error fetching method names:", error); + return {}; + } +}; + +watch( + data, + async (newData) => { + if (!newData) return; + + await loadMethodNames(); + }, + { immediate: true } +); + +const methodNames = ref>({}); + +const loadMethodNames = async () => { + if (!data.value) return; + + const uniqueSighashes = [ + ...new Set( + data.value?.map((transaction) => transaction.data.slice(0, 10)).filter((sighash) => sighash !== "0x") ?? [] + ), + ]; + const fetchedMethodNames = await fetchMethodNames(uniqueSighashes); + methodNames.value = { ...methodNames.value, ...fetchedMethodNames }; +}; + +const getTransactionMethod = (transaction: TransactionListItem, methodNames: Record) => { if (transaction.data === "0x") { return t("transactions.table.transferMethodName"); } const sighash = transaction.data.slice(0, 10); if (props.contractAbi) { - return ( - decodeDataWithABI( - { - calldata: transaction.data, - value: transaction.value, - }, - props.contractAbi - )?.name ?? sighash + const decodedMethod = decodeDataWithABI( + { calldata: transaction.data, value: transaction.value }, + props.contractAbi ); + if (decodedMethod?.name) { + return decodedMethod.name; + } } - return sighash; + + return methodNames[sighash] ?? sighash; }; type TransactionListItemMapped = TransactionListItem & { @@ -301,7 +377,7 @@ type TransactionListItemMapped = TransactionListItem & { const transactions = computed(() => { return data.value?.map((transaction) => ({ ...transaction, - methodName: getTransactionMethod(transaction), + methodName: getTransactionMethod(transaction, methodNames.value), fromNetwork: transaction.isL1Originated ? "L1" : "L2", toNetwork: "L2", // even withdrawals go through L2 addresses (800A or bridge addresses) statusColor: transaction.status === "failed" ? "danger" : "dark-success", @@ -432,7 +508,7 @@ function getDirection(item: TransactionListItem): Direction { } } .transactions-data-method { - @apply w-[200px] truncate sm:w-auto; + @apply w-36 truncate border-slate-200 rounded border py-0.5 px-2 text-center bg-slate-400/10 text-xs text-slate-600 sm:w-28; } .transactions-data-transaction-amount, .transactions-data-age {