Skip to content

Commit

Permalink
feat: show gas fields on UI (#114)
Browse files Browse the repository at this point in the history
# What ❔

<img width="441" alt="image"
src="https://github.com/matter-labs/block-explorer/assets/6553665/b69c7a82-4f3a-4afa-abc5-8b7385a5079d">

## Why ❔

For better user experience it was requested to show gas fields and
limits on UI.

## Checklist

<!-- Check your PR fulfills the following items. -->
<!-- For draft PRs check the boxes as you complete them. -->

- [X] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [X] Tests for the changes have been added / updated.
  • Loading branch information
vasyl-ivanchuk authored Dec 7, 2023
1 parent 65d0a8d commit b897a78
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 7 deletions.
8 changes: 7 additions & 1 deletion packages/app/mock/transactions/Execute.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,5 +165,11 @@
],
"isL1BatchSealed": false,
"to": "0x4732C03B2CF6eDe46500e799DE79a15Df44929eB",
"value": "0x00"
"value": "0x00",
"gasPrice": "4000",
"gasLimit": "5000",
"gasUsed": "3000",
"gasPerPubdata": "800",
"maxFeePerGas": "7000",
"maxPriorityFeePerGas": "8000"
}
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,48 @@
<FeeData :fee-data="transaction?.feeData" :show-details="transaction?.status !== 'indexing'" />
</TableBodyColumn>
</tr>

<tr class="transaction-table-row">
<TableBodyColumn class="transaction-table-label">
<span class="transaction-info-field-label">{{ t("transactions.table.gasLimitAndUsed") }}</span>
<InfoTooltip class="transaction-info-field-tooltip">{{
t("transactions.table.gasLimitAndUsedTooltip")
}}</InfoTooltip>
</TableBodyColumn>
<TableBodyColumn class="transaction-table-value"
>{{ transaction?.gasLimit }} | {{ transaction?.gasUsed }} ({{ gasUsedPercent }}%)</TableBodyColumn
>
</tr>
<tr class="transaction-table-row" v-if="transaction?.gasPerPubdata">
<TableBodyColumn class="transaction-table-label">
<span class="transaction-info-field-label">{{ t("transactions.table.gasPerPubdata") }}</span>
<InfoTooltip class="transaction-info-field-tooltip">{{
t("transactions.table.gasPerPubdataTooltip")
}}</InfoTooltip>
</TableBodyColumn>
<TableBodyColumn class="transaction-table-value">{{ transaction.gasPerPubdata }}</TableBodyColumn>
</tr>
<tr class="transaction-table-row" v-if="transaction?.maxFeePerGas">
<TableBodyColumn class="transaction-table-label">
<span class="transaction-info-field-label">{{ t("transactions.table.maxFeePerGas") }}</span>
<InfoTooltip class="transaction-info-field-tooltip">
{{ t("transactions.table.maxFeePerGasTooltip") }}
</InfoTooltip>
</TableBodyColumn>
<TableBodyColumn class="transaction-table-value">
<EthAmountPrice :amount="transaction.maxFeePerGas"></EthAmountPrice>
</TableBodyColumn>
</tr>
<tr class="transaction-table-row" v-if="transaction?.maxPriorityFeePerGas">
<TableBodyColumn class="transaction-table-label">
<span class="transaction-info-field-label">{{ t("transactions.table.maxPriorityFeePerGas") }}</span>
<InfoTooltip class="transaction-info-field-tooltip">
{{ t("transactions.table.maxPriorityFeePerGasTooltip") }}
</InfoTooltip>
</TableBodyColumn>
<TableBodyColumn class="transaction-table-value">
<EthAmountPrice :amount="transaction.maxPriorityFeePerGas"></EthAmountPrice>
</TableBodyColumn>
</tr>
<tr class="transaction-table-row">
<TableBodyColumn class="transaction-table-label">
<span class="transaction-info-field-label">{{ t("transactions.table.nonce") }}</span>
Expand Down Expand Up @@ -242,6 +283,15 @@ const tokenTransfers = computed(() => {
// exclude transfers with no amount, such as NFT until we fully support them
return props.transaction?.transfers.filter((transfer) => transfer.amount) || [];
});
const gasUsedPercent = computed(() => {
if (props.transaction) {
const gasLimit = parseInt(props.transaction.gasLimit, 10);
const gasUsed = parseInt(props.transaction.gasUsed, 10);
return parseFloat(((gasUsed / gasLimit) * 100).toFixed(2));
}
return null;
});
</script>

<style lang="scss">
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/composables/common/Api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ declare namespace Api {
nonce: number;
blockNumber: number;
blockHash: string;
gasPrice: string;
gasLimit: string;
gasUsed: string;
gasPerPubdata: string | null;
maxFeePerGas: string | null;
maxPriorityFeePerGas: string | null;
receivedAt: string;
commitTxHash: string | null;
proveTxHash: string | null;
Expand Down
27 changes: 26 additions & 1 deletion packages/app/src/composables/useTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import useContext from "./useContext";

import type { TransactionLogEntry } from "./useEventLog";
import type { Hash, NetworkOrigin } from "@/types";
import type { types } from "zksync-web3";

export type TransactionStatus = "included" | "committed" | "proved" | "verified" | "failed" | "indexing";
type TokenInfo = {
Expand All @@ -31,6 +32,10 @@ export type TokenTransfer = {
tokenInfo?: TokenInfo;
};

export type TransactionDetails = types.TransactionDetails & {
gasPerPubdata: string | null;
};

export type FeeData = {
amountPaid: Hash;
isPaidByPaymaster: boolean;
Expand Down Expand Up @@ -61,6 +66,12 @@ export type TransactionItem = {
nonce: null | number;
receivedAt: string;
feeData: FeeData;
gasPrice: string;
gasLimit: string;
gasUsed: string;
gasPerPubdata: string | null;
maxFeePerGas: string | null;
maxPriorityFeePerGas: string | null;
status: TransactionStatus;
l1BatchNumber: number | null;
isL1BatchSealed: boolean;
Expand Down Expand Up @@ -97,6 +108,7 @@ export default (context = useContext()) => {
if (transactionDetails.status === "pending") {
return null;
}
const gasPerPubdata = (<TransactionDetails>transactionDetails).gasPerPubdata;
return {
hash: transactionData.hash,
blockHash: transactionData.blockHash!,
Expand Down Expand Up @@ -138,8 +150,14 @@ export default (context = useContext()) => {
transactionHash: item.transactionHash,
transactionIndex: item.transactionIndex.toString(16),
})),

transfers: [],

gasPrice: transactionData.gasPrice!.toString(),
gasLimit: transactionData.gasLimit.toString(),
gasUsed: transactionReceipt.gasUsed.toString(),
gasPerPubdata: gasPerPubdata ? BigNumber.from(gasPerPubdata).toString() : null,
maxFeePerGas: transactionData.maxFeePerGas?.toString() ?? null,
maxPriorityFeePerGas: transactionData.maxPriorityFeePerGas?.toString() ?? null,
};
} catch (err) {
return null;
Expand Down Expand Up @@ -238,6 +256,13 @@ export function mapTransaction(
})),

transfers: mapTransfers(filterTransfers(transfers)),

gasPrice: transaction.gasPrice,
gasLimit: transaction.gasLimit,
gasUsed: transaction.gasUsed,
gasPerPubdata: transaction.gasPerPubdata,
maxFeePerGas: transaction.maxFeePerGas,
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas,
};
}

Expand Down
10 changes: 9 additions & 1 deletion packages/app/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,15 @@
"unableToLoadMore": "Unable to load more",
"tryAgain": "Try again ->"
},
"unknown": "Unknown"
"unknown": "Unknown",
"gasLimitAndUsed": "Gas limit & used",
"gasLimitAndUsedTooltip": "Maximum amount of gas allocated for the transaction & the amount eventually used.",
"gasPerPubdata": "Gas per pubdata",
"gasPerPubdataTooltip": "Maximum amount of gas the user is willing to pay for a single byte of published data (pubdata).",
"maxFeePerGas": "Max fee",
"maxFeePerGasTooltip": "Maximum amount a user is willing to pay for their tx.",
"maxPriorityFeePerGas": "Max priority fee",
"maxPriorityFeePerGasTooltip": "Maximum amount a user is willing to give to the block producer."
},
"logs": {
"name": "Name",
Expand Down
10 changes: 9 additions & 1 deletion packages/app/src/locales/uk.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,15 @@
"showMore": "Показати більше транзакцій ->",
"unableToLoadMore": "Неможливо завантажити більше",
"tryAgain": "Спробуйте знову ->"
}
},
"gasLimitAndUsed": "Газ ліміт & використано",
"gasLimitAndUsedTooltip": "Максимальна кількість виділеного газу для транзакції та кількість фактично використаного газу.",
"gasPerPubdata": "Газ за pubdata",
"gasPerPubdataTooltip": "Максимальна кількість газу, яку користувач готовий сплатити за один байт опублікованих даних (pubdata).",
"maxFeePerGas": "Макс комісія",
"maxFeePerGasTooltip": "Максимальна комісія, яку користувач готовий заплатити за свою транзакцію.",
"maxPriorityFeePerGas": "Макс пріоритетна комісія",
"maxPriorityFeePerGasTooltip": "Максимальна комісія, яку користувач готовий віддати блок-продюсеру."
},
"logs": {
"address": "Адреса",
Expand Down
43 changes: 41 additions & 2 deletions packages/app/tests/components/transactions/GeneralInfo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ const transaction: TransactionItem = {
},
},
],
gasPrice: "4000",
gasLimit: "5000",
gasUsed: "3000",
gasPerPubdata: "800",
maxFeePerGas: "7000",
maxPriorityFeePerGas: "8000",
};

vi.mock("@/composables/useToken", () => {
Expand Down Expand Up @@ -206,8 +212,24 @@ describe("Transaction info table", () => {
},
});
await nextTick();
const [txHash, status, block, batch, from, to, tokensTransferred, inputData, value, fee, nonce, createdAt] =
wrapper.findAll("tbody tr td:nth-child(2)");
const [
txHash,
status,
block,
batch,
from,
to,
tokensTransferred,
inputData,
value,
fee,
gasLimitAndUsed,
gasPerPubdata,
maxFee,
maxFeePriority,
nonce,
createdAt,
] = wrapper.findAll("tbody tr td:nth-child(2)");
expect(txHash.find(".displayed-string").text()).toBe("0x9c526cc47ca...ff8a629cffa3c");

const badges = status.findAllComponents(Badge);
Expand Down Expand Up @@ -248,6 +270,15 @@ describe("Transaction info table", () => {
expect(inputData.find(".displayed-string").text()).toBe("0xa9059cbb000...000000000000c");
expect(`${value.find(".token-amount").text()} ${fee.find(".token-symbol").text()}`).toBe("0 ETH");
expect(`${fee.find(".token-amount").text()} ${fee.find(".token-symbol").text()}`).toBe("0.0014447025 ETH");

expect(gasLimitAndUsed.text()).toBe("5000 | 3000 (60%)");
expect(gasPerPubdata.text()).toBe("800");
expect(`${maxFee.find(".token-amount").text()} ${maxFee.find(".token-symbol").text()}`).toBe(
"0.000000000000007 ETH"
);
expect(`${maxFeePriority.find(".token-amount").text()} ${maxFeePriority.find(".token-symbol").text()}`).toBe(
"0.000000000000008 ETH"
);
expect(nonce.text()).toBe("24");
expect(createdAt.find(".full-date").text()).toBe("2023-02-28 11:42");

Expand All @@ -262,6 +293,10 @@ describe("Transaction info table", () => {
inputDataTooltip,
valueTooltip,
feeTooltip,
gasLimitAndUsedTooltip,
gasPerPubdataTooltip,
maxFeeTooltip,
maxPriorityFeeTooltip,
nonceTooltip,
createdAtTooltip,
] = wrapper.findAll("tbody .transaction-info-field-tooltip").map((e) => e.text());
Expand All @@ -275,6 +310,10 @@ describe("Transaction info table", () => {
expect(inputDataTooltip).toBe(i18n.global.t("transactions.table.inputDataTooltip"));
expect(valueTooltip).toBe(i18n.global.t("transactions.table.valueTooltip"));
expect(feeTooltip).toBe(i18n.global.t("transactions.table.feeTooltip"));
expect(gasLimitAndUsedTooltip).toBe(i18n.global.t("transactions.table.gasLimitAndUsedTooltip"));
expect(gasPerPubdataTooltip).toBe(i18n.global.t("transactions.table.gasPerPubdataTooltip"));
expect(maxFeeTooltip).toBe(i18n.global.t("transactions.table.maxFeePerGasTooltip"));
expect(maxPriorityFeeTooltip).toBe(i18n.global.t("transactions.table.maxPriorityFeePerGasTooltip"));
expect(nonceTooltip).toBe(i18n.global.t("transactions.table.nonceTooltip"));
expect(createdAtTooltip).toBe(i18n.global.t("transactions.table.createdTooltip"));
});
Expand Down
6 changes: 6 additions & 0 deletions packages/app/tests/components/transactions/Table.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ const transaction: TransactionListItem = {
executeTxHash: null,
proveTxHash: null,
isL1BatchSealed: false,
gasPrice: "4000",
gasLimit: "5000",
gasUsed: "3000",
gasPerPubdata: "800",
maxFeePerGas: "7000",
maxPriorityFeePerGas: "8000",
error: null,
revertReason: null,
};
Expand Down
24 changes: 24 additions & 0 deletions packages/app/tests/composables/useTransaction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ vi.mock("ohmyfetch", async () => {
commitTxHash: "0xe6a7ed0b6bf1c49f27feae3a71e5ba2aa4abaa6e372524369529946eb61a6936",
executeTxHash: "0xdd70c8c2f59d88b9970c3b48a1230320f051d4502d0277124db481a42ada5c33",
proveTxHash: "0x688c20e2106984bb0ccdadecf01e7bf12088b0ba671d888eca8e577ceac0d790",
gasPrice: "4000",
gasLimit: "5000",
gasUsed: "3000",
gasPerPubdata: "800",
maxFeePerGas: "7000",
maxPriorityFeePerGas: "8000",
error: null,
revertReason: null,
};
Expand Down Expand Up @@ -538,6 +544,12 @@ describe("useTransaction:", () => {
},
},
],
gasPrice: "4000",
gasLimit: "5000",
gasUsed: "3000",
gasPerPubdata: "800",
maxFeePerGas: "7000",
maxPriorityFeePerGas: "8000",
});
});
it("adds paymaster fields to fee data when transaction is paid by paymaster", async () => {
Expand Down Expand Up @@ -586,6 +598,10 @@ describe("useTransaction:", () => {
value: "0",
nonce: 24,
l1BatchNumber: 11014,
gasPrice: "4000",
gasLimit: "5000",
maxFeePerGas: "7000",
maxPriorityFeePerGas: "8000",
}),
getTransactionDetails: vi.fn().mockResolvedValue({
status: "verified",
Expand All @@ -595,10 +611,12 @@ describe("useTransaction:", () => {
fee: "0x521f303519100",
isL1Originated: false,
receivedAt: "2023-02-28T08:42:08.198Z",
gasPerPubdata: "0x320",
}),
getTransactionReceipt: vi.fn().mockResolvedValue({
transactionIndex: 0,
logs,
gasUsed: "3000",
}),
};
const { transaction, isRequestFailed, getByHash } = useTransaction({
Expand Down Expand Up @@ -709,6 +727,12 @@ describe("useTransaction:", () => {
},
],
transfers: [],
gasPrice: "4000",
gasLimit: "5000",
gasUsed: "3000",
gasPerPubdata: "800",
maxFeePerGas: "7000",
maxPriorityFeePerGas: "8000",
});
});
});
Expand Down
6 changes: 6 additions & 0 deletions packages/app/tests/composables/useTransactions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ const transaction: TransactionListItem = {
executeTxHash: null,
proveTxHash: null,
isL1BatchSealed: false,
gasPrice: "4000",
gasLimit: "5000",
gasUsed: "3000",
gasPerPubdata: "800",
maxFeePerGas: "7000",
maxPriorityFeePerGas: "8000",
error: null,
revertReason: null,
};
Expand Down

0 comments on commit b897a78

Please sign in to comment.