-
-
+
+
{{ t("transactions.table.for") }}
{{ transferAmount }}
@@ -25,6 +35,7 @@ import TokenIconLabel from "@/components/TokenIconLabel.vue";
import TransferInfo from "@/components/transactions/infoTable/TransferInfo.vue";
import type { TokenTransfer } from "@/composables/useTransaction";
+import type { Hash } from "@/types";
import { formatBigNumberish } from "@/utils/formatters";
@@ -35,6 +46,9 @@ const props = defineProps({
type: Object as PropType,
required: true,
},
+ paymasterAddress: {
+ type: String as PropType,
+ },
});
const transferAmount = computed(() =>
diff --git a/packages/app/src/composables/useTransaction.ts b/packages/app/src/composables/useTransaction.ts
index 1fbd4ba858..022df5200b 100644
--- a/packages/app/src/composables/useTransaction.ts
+++ b/packages/app/src/composables/useTransaction.ts
@@ -30,6 +30,8 @@ export type TokenTransfer = {
export type FeeData = {
amountPaid: Hash;
+ isPaidByPaymaster: boolean;
+ paymasterAddress?: Hash;
refunds: TokenTransfer[];
amountRefunded: Hash;
};
@@ -109,6 +111,7 @@ export default (context = useContext()) => {
fee: transactionDetails.fee.toString(),
feeData: {
amountPaid: transactionDetails.fee.toString(),
+ isPaidByPaymaster: false,
refunds: [],
amountRefunded: BigNumber.from(0).toHexString(),
},
@@ -178,6 +181,11 @@ export function mapTransaction(
transfers: Api.Response.Transfer[],
logs: Api.Response.Log[]
): TransactionItem {
+ const fees = mapTransfers(filterFees(transfers));
+ const refunds = mapTransfers(filterRefunds(transfers));
+ const paymasterFee = fees.find((fee) => fee.from !== transaction.from);
+ const paymasterAddress = paymasterFee?.from;
+ const isPaidByPaymaster = !transaction.isL1Originated && !!paymasterFee;
return {
hash: transaction.hash,
blockHash: transaction.blockHash,
@@ -197,7 +205,9 @@ export function mapTransaction(
fee: transaction.fee,
feeData: {
amountPaid: transaction.fee!,
- refunds: mapTransfers(filterRefunds(transfers)),
+ isPaidByPaymaster,
+ paymasterAddress,
+ refunds,
amountRefunded: sumAmounts(mapTransfers(filterRefunds(transfers))),
},
indexInBlock: transaction.transactionIndex,
@@ -248,12 +258,16 @@ function sumAmounts(balanceChanges: TokenTransfer[]) {
return total.toHexString() as Hash;
}
-export function filterRefunds(balanceChanges: Api.Response.Transfer[]) {
- return balanceChanges.filter((item) => item.type === "refund");
+export function filterRefunds(transfers: Api.Response.Transfer[]) {
+ return transfers.filter((item) => item.type === "refund");
}
-export function filterTransfers(balanceChanges: Api.Response.Transfer[]) {
- return balanceChanges.filter((item) => item.type !== "fee" && item.type !== "refund");
+export function filterFees(transfers: Api.Response.Transfer[]) {
+ return transfers.filter((item) => item.type === "fee");
+}
+
+export function filterTransfers(transfers: Api.Response.Transfer[]) {
+ return transfers.filter((item) => item.type !== "fee" && item.type !== "refund");
}
async function all(url: URL): Promise {
diff --git a/packages/app/src/locales/en.json b/packages/app/src/locales/en.json
index 192101c02c..cba7ceff64 100644
--- a/packages/app/src/locales/en.json
+++ b/packages/app/src/locales/en.json
@@ -127,13 +127,17 @@
"value": "Value",
"valueTooltip": "Amount of Ether being transferred from one address to another within a transaction.",
"fee": "Fee",
+ "paidByPaymaster": "Paid by paymaster",
"feeDetails": {
"moreDetails": "More Details",
"closeDetails": "Close Details",
"initial": "Initial:",
"refunded": "Refunded:",
"refunds": "Refunds:",
- "whyRefunded": "Why I'm being refunded?"
+ "whyRefunded": "Why I'm being refunded?",
+ "whyPaymasterRefunded": "Why paymaster is being refunded?",
+ "whatIsPaymaster": "What is Paymaster?",
+ "paymaster": "Paymaster"
},
"feeTooltip": "Fee which sender paid for this transaction, amount in chosen asset & price in USD at the current time",
"direction": "Direction",
diff --git a/packages/app/tests/components/FeeData.spec.ts b/packages/app/tests/components/FeeData.spec.ts
index 3ff9f6ce7d..5f0a7c1d19 100644
--- a/packages/app/tests/components/FeeData.spec.ts
+++ b/packages/app/tests/components/FeeData.spec.ts
@@ -40,6 +40,7 @@ const i18n = createI18n({
const feeData = {
amountPaid: "10000000000000000",
+ isPaidByPaymaster: false,
refunds: [
{
tokenInfo: {
@@ -62,6 +63,12 @@ const feeData = {
amountRefunded: "1000000",
};
+const feeDataPaymaster = {
+ ...feeData,
+ isPaidByPaymaster: true,
+ paymasterAddress: "0x9adEe6D82c003FF2E0F2026A13ae80736CA61163",
+};
+
const global = {
stubs: {
RouterLink: RouterLinkStub,
@@ -139,39 +146,111 @@ describe("FeeToken", () => {
);
});
- it("displays the refunds when expanded", async () => {
- const { container } = render(FeeDataComponent, {
- global,
- props: {
- feeData: feeData as FeeData,
- },
+ describe("when transaction fee is not paid by paymaster", () => {
+ it("does not display paid by paymaster label when fee is not paid by paymaster", async () => {
+ const { container } = render(FeeDataComponent, {
+ global,
+ props: {
+ feeData: feeData as FeeData,
+ },
+ });
+ expect(container.querySelector(".payed-by-paymaster-label")).toBe(null);
});
- await fireEvent.click(container.querySelector(".toggle-button")!);
- const transfers = container.querySelectorAll(".fee-transfers-container .transfer-container");
- expect(transfers.length).toBe(1);
- const transferInfo = transfers[0].querySelectorAll(".transfer-info-container");
- expect(transferInfo[0].querySelector(".address span")?.textContent).toBe("0x00000000000...8001");
- expect(transferInfo[1].querySelector(".address span")?.textContent).toBe("0x9adEe6D82c0...1163");
- expect(container.querySelectorAll(".transfer-amount-container span")[0]?.textContent).toBe("for");
- expect(container.querySelectorAll(".transfer-amount-container span")[1]?.textContent).toBe("0.000000000001");
- expect(container.querySelectorAll(".transfer-amount-container span")[2]?.textContent).toBe("ETH");
+ it("displays the refunds when expanded", async () => {
+ const { container } = render(FeeDataComponent, {
+ global,
+ props: {
+ feeData: feeData as FeeData,
+ },
+ });
+
+ await fireEvent.click(container.querySelector(".toggle-button")!);
+ const transfers = container.querySelectorAll(".fee-transfers-container .transfer-container");
+ expect(transfers.length).toBe(1);
+ const transferInfo = transfers[0].querySelectorAll(".transfer-info-container");
+ expect(transferInfo[0].querySelector(".address span")?.textContent).toBe("0x00000000000...8001");
+ expect(transferInfo[0].querySelector(".paymaster-label")).toBe(null);
+ expect(transferInfo[1].querySelector(".address span")?.textContent).toBe("0x9adEe6D82c0...1163");
+ expect(transferInfo[1].querySelector(".paymaster-label")).toBe(null);
+ expect(container.querySelectorAll(".transfer-amount-container span")[0]?.textContent).toBe("for");
+ expect(container.querySelectorAll(".transfer-amount-container span")[1]?.textContent).toBe("0.000000000001");
+ expect(container.querySelectorAll(".transfer-amount-container span")[2]?.textContent).toBe("ETH");
+ });
+
+ it("displays the 'Why Refunded?' link when expanded", async () => {
+ const { container } = render(FeeDataComponent, {
+ global,
+ props: {
+ feeData: feeData as FeeData,
+ },
+ });
+
+ await fireEvent.click(container.querySelector(".toggle-button")!);
+ const link = container.querySelector(".refunded-link");
+ expect(link?.getAttribute("href")).toBe(
+ "https://era.zksync.io/docs/dev/developer-guides/transactions/fee-model.html#refunds"
+ );
+ expect(link?.getAttribute("target")).toBe("_blank");
+ expect(link?.textContent).toBe("Why I'm being refunded?");
+ });
});
- it("displays the 'Why Refunded?' link when expanded", async () => {
- const { container } = render(FeeDataComponent, {
- global,
- props: {
- feeData: feeData as FeeData,
- },
+ describe("when transaction fee is paid by paymaster", () => {
+ it("display paid by paymaster label when fee is paid by paymaster", async () => {
+ const { container } = render(FeeDataComponent, {
+ global,
+ props: {
+ feeData: feeDataPaymaster as FeeData,
+ },
+ });
+ expect(container.querySelector(".payed-by-paymaster-label")?.textContent).toBe("Paid by paymaster");
});
- await fireEvent.click(container.querySelector(".toggle-button")!);
- const link = container.querySelector(".refunded-link");
- expect(link?.getAttribute("href")).toBe(
- "https://era.zksync.io/docs/dev/developer-guides/transactions/fee-model.html#refunds"
- );
- expect(link?.getAttribute("target")).toBe("_blank");
- expect(link?.textContent).toBe("Why I'm being refunded?");
+ it("displays the refunds when expanded", async () => {
+ const { container } = render(FeeDataComponent, {
+ global,
+ props: {
+ feeData: feeDataPaymaster as FeeData,
+ },
+ });
+
+ await fireEvent.click(container.querySelector(".toggle-button")!);
+ const transfers = container.querySelectorAll(".fee-transfers-container .transfer-container");
+ expect(transfers.length).toBe(1);
+ const transferInfo = transfers[0].querySelectorAll(".transfer-info-container");
+ expect(transferInfo[0].querySelector(".address span")?.textContent).toBe("0x00000000000...8001");
+ expect(transferInfo[0].querySelector(".paymaster-label")).toBe(null);
+ expect(transferInfo[1].querySelector(".address span")?.textContent).toBe("0x9adEe6D82c0...1163");
+ expect(transferInfo[1].querySelector(".paymaster-label")?.textContent).toBe("Paymaster");
+ expect(container.querySelectorAll(".transfer-amount-container span")[0]?.textContent).toBe("for");
+ expect(container.querySelectorAll(".transfer-amount-container span")[1]?.textContent).toBe("0.000000000001");
+ expect(container.querySelectorAll(".transfer-amount-container span")[2]?.textContent).toBe("ETH");
+ });
+
+ it("displays the 'Why Paymaster Refunded?' and 'What is Paymaster' links when expanded", async () => {
+ const { container } = render(FeeDataComponent, {
+ global,
+ props: {
+ feeData: feeDataPaymaster as FeeData,
+ },
+ });
+
+ await fireEvent.click(container.querySelector(".toggle-button")!);
+
+ const refundedLink = container.querySelector(".refunded-link");
+ expect(refundedLink?.getAttribute("href")).toBe(
+ "https://era.zksync.io/docs/dev/developer-guides/transactions/fee-model.html#refunds"
+ );
+ expect(refundedLink?.getAttribute("target")).toBe("_blank");
+ expect(refundedLink?.textContent).toBe("Why paymaster is being refunded?");
+
+ const paymasterLink = container.querySelector(".paymaster-link");
+ expect(paymasterLink?.getAttribute("href")).toBe(
+ "https://era.zksync.io/docs/reference/concepts/account-abstraction.html#paymasters"
+ );
+ expect(paymasterLink?.getAttribute("target")).toBe("_blank");
+ expect(paymasterLink?.textContent).toBe("What is Paymaster?");
+ });
});
});
diff --git a/packages/app/tests/components/transactions/GeneralInfo.spec.ts b/packages/app/tests/components/transactions/GeneralInfo.spec.ts
index 022c223d04..6a153578f0 100644
--- a/packages/app/tests/components/transactions/GeneralInfo.spec.ts
+++ b/packages/app/tests/components/transactions/GeneralInfo.spec.ts
@@ -36,6 +36,7 @@ const transaction: TransactionItem = {
fee: "0x521f303519100",
feeData: {
amountPaid: "0x521f303519100",
+ isPaidByPaymaster: false,
refunds: [
{
amount: "116665569251910",
diff --git a/packages/app/tests/components/transactions/PaymasterLabel.spec.ts b/packages/app/tests/components/transactions/PaymasterLabel.spec.ts
new file mode 100644
index 0000000000..51594b4c10
--- /dev/null
+++ b/packages/app/tests/components/transactions/PaymasterLabel.spec.ts
@@ -0,0 +1,29 @@
+import { createI18n } from "vue-i18n";
+
+import { describe, expect, it } from "vitest";
+
+import { mount } from "@vue/test-utils";
+
+import PaymasterLabel from "@/components/transactions/PaymasterLabel.vue";
+
+import enUS from "@/locales/en.json";
+
+describe("TransactionNetworkSquareBlock:", () => {
+ const i18n = createI18n({
+ locale: "en",
+ allowComposition: true,
+ messages: {
+ en: enUS,
+ },
+ });
+ const global = {
+ plugins: [i18n],
+ };
+
+ it("renders component", () => {
+ const wrapper = mount(PaymasterLabel, {
+ global,
+ });
+ expect(wrapper.find(".paymaster-label").text()).toBe("Paymaster");
+ });
+});
diff --git a/packages/app/tests/components/transactions/TransferInfo.spec.ts b/packages/app/tests/components/transactions/TransferInfo.spec.ts
index f4830ecb21..006443a079 100644
--- a/packages/app/tests/components/transactions/TransferInfo.spec.ts
+++ b/packages/app/tests/components/transactions/TransferInfo.spec.ts
@@ -83,6 +83,24 @@ describe("TransferInfo:", () => {
mock.mockRestore();
wrapper.unmount();
});
+ it("renders paymaster label when transaction fee is paid by paymaster", async () => {
+ /* eslint-disable @typescript-eslint/no-explicit-any */
+ const mock = ($fetch as any).mockResolvedValue({ accountType: "eOA" });
+
+ const wrapper = mount(TransferInfo, {
+ global,
+ props: {
+ label: "From",
+ address: "0x6c10d9c1744f149d4b17660e14faa247964749c7",
+ network: "L2",
+ isPaymaster: true,
+ },
+ });
+ expect(wrapper.find(".paymaster-label")?.text()).toBe("Paymaster");
+
+ mock.mockRestore();
+ wrapper.unmount();
+ });
describe("when L1 explorer url is not set", () => {
let mock1ExplorerUrl: Mock;
beforeEach(() => {
diff --git a/packages/app/tests/composables/useTransaction.spec.ts b/packages/app/tests/composables/useTransaction.spec.ts
index 0c6e3de7c2..0c2ea496f3 100644
--- a/packages/app/tests/composables/useTransaction.spec.ts
+++ b/packages/app/tests/composables/useTransaction.spec.ts
@@ -10,6 +10,9 @@ import type { Context } from "@/composables/useContext";
import { ETH_TOKEN } from "@/utils/constants";
+const hash = "0x011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce";
+const hashPaidByPaymaster = "0x111b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce";
+
const logs = [
{
address: "0x000000000000000000000000000000000000800A",
@@ -20,7 +23,7 @@ const logs = [
],
data: "0x000000000000000000000000000000000000000000000000000314f4b9af9680",
blockNumber: 1162235,
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
transactionIndex: 0,
logIndex: 3,
},
@@ -33,7 +36,7 @@ const logs = [
],
data: "0x000000000000000000000000000000000000000000000000000000000000000c",
blockNumber: 1162235,
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
transactionIndex: 0,
logIndex: 2,
},
@@ -46,7 +49,7 @@ const logs = [
],
data: "0x00000000000000000000000000000000000000000000000000006a1b51d01246",
blockNumber: 1162235,
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
transactionIndex: 0,
logIndex: 1,
},
@@ -59,7 +62,7 @@ const logs = [
],
data: "0x00000000000000000000000000000000000000000000000000058c0e5521a346",
blockNumber: 1162235,
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
transactionIndex: 0,
logIndex: 0,
},
@@ -68,43 +71,40 @@ const logs = [
vi.mock("ohmyfetch", async () => {
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
const mod = await vi.importActual("ohmyfetch");
+ const transactionDetails = {
+ hash: "0x011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce",
+ to: "0x1bAbcaeA2e4BE1f1e1A149c454806F2D21d7f47C",
+ from: "0x08d211E22dB19741FF25838A22e4e696FeE7eD36",
+ data: "0xa9059cbb00000000000000000000000008d211e22db19741ff25838a22e4e696fee7ed36000000000000000000000000000000000000000000000000000000000000000c",
+ value: "0",
+ isL1Originated: false,
+ fee: "0x521f303519100",
+ nonce: 24,
+ blockNumber: 1162235,
+ l1BatchNumber: 11014,
+ isL1BatchSealed: true,
+ blockHash: "0x1fc6a30903866bf91cede9f831e71f2c7ba0dd023ffc044fe469c51b215d950b",
+ transactionIndex: 0,
+ receivedAt: "2023-02-28T08:42:08.198Z",
+ status: "verified",
+ commitTxHash: "0xe6a7ed0b6bf1c49f27feae3a71e5ba2aa4abaa6e372524369529946eb61a6936",
+ executeTxHash: "0xdd70c8c2f59d88b9970c3b48a1230320f051d4502d0277124db481a42ada5c33",
+ proveTxHash: "0x688c20e2106984bb0ccdadecf01e7bf12088b0ba671d888eca8e577ceac0d790",
+ };
return {
...mod,
$fetch: vi.fn((url: string) => {
- if (url.endsWith("/transactions/0x011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce")) {
- return Promise.resolve({
- hash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
- to: "0x1bAbcaeA2e4BE1f1e1A149c454806F2D21d7f47C",
- from: "0x08d211E22dB19741FF25838A22e4e696FeE7eD36",
- data: "0xa9059cbb00000000000000000000000008d211e22db19741ff25838a22e4e696fee7ed36000000000000000000000000000000000000000000000000000000000000000c",
- value: "0",
- isL1Originated: false,
- fee: "0x521f303519100",
- nonce: 24,
- blockNumber: 1162235,
- l1BatchNumber: 11014,
- isL1BatchSealed: true,
- blockHash: "0x1fc6a30903866bf91cede9f831e71f2c7ba0dd023ffc044fe469c51b215d950b",
- transactionIndex: 0,
- receivedAt: "2023-02-28T08:42:08.198Z",
- status: "verified",
- commitTxHash: "0xe6a7ed0b6bf1c49f27feae3a71e5ba2aa4abaa6e372524369529946eb61a6936",
- executeTxHash: "0xdd70c8c2f59d88b9970c3b48a1230320f051d4502d0277124db481a42ada5c33",
- proveTxHash: "0x688c20e2106984bb0ccdadecf01e7bf12088b0ba671d888eca8e577ceac0d790",
- });
+ if (url.endsWith(`/transactions/${hash}`) || url.endsWith(`/transactions/${hashPaidByPaymaster}`)) {
+ return Promise.resolve(transactionDetails);
}
- if (
- url.endsWith(
- "transactions/0x011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce/transfers?limit=100&page=1"
- )
- ) {
+ if (url.endsWith(`transactions/${hash}/transfers?limit=100&page=1`)) {
return Promise.resolve({
items: [
{
from: "0x08d211E22dB19741FF25838A22e4e696FeE7eD36",
to: "0x0000000000000000000000000000000000008001",
blockNumber: 1162235,
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
amount: "1561368069251910",
tokenAddress: ETH_TOKEN.address,
type: "fee",
@@ -115,7 +115,7 @@ vi.mock("ohmyfetch", async () => {
from: "0x0000000000000000000000000000000000008001",
to: "0x08d211E22dB19741FF25838A22e4e696FeE7eD36",
blockNumber: 1162235,
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
amount: "116665569251910",
tokenAddress: ETH_TOKEN.address,
type: "refund",
@@ -126,7 +126,7 @@ vi.mock("ohmyfetch", async () => {
from: "0x08d211E22dB19741FF25838A22e4e696FeE7eD36",
to: "0x08d211E22dB19741FF25838A22e4e696FeE7eD36",
blockNumber: 1162235,
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
amount: "1",
tokenAddress: "0x1bAbcaeA2e4BE1f1e1A149c454806F2D21d7f47D",
type: "transfer",
@@ -137,7 +137,7 @@ vi.mock("ohmyfetch", async () => {
from: "0x08d211E22dB19741FF25838A22e4e696FeE7eD36",
to: "0x08d211E22dB19741FF25838A22e4e696FeE7eD36",
blockNumber: 1162235,
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
amount: "12",
tokenAddress: "0x1bAbcaeA2e4BE1f1e1A149c454806F2D21d7f47C",
type: "transfer",
@@ -154,7 +154,7 @@ vi.mock("ohmyfetch", async () => {
from: "0x0000000000000000000000000000000000008001",
to: "0x08d211E22dB19741FF25838A22e4e696FeE7eD36",
blockNumber: 1162235,
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
amount: "867466250000000",
tokenAddress: ETH_TOKEN.address,
type: "refund",
@@ -170,19 +170,55 @@ vi.mock("ohmyfetch", async () => {
currentPage: 1,
},
links: {
- first:
- "transactions/0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c/transfers?limit=100",
+ first: `transactions/${hash}/transfers?limit=100`,
previous: "",
next: "",
- last: "transactions/0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c/transfers?page=1&limit=100",
+ last: `transactions/${hash}/transfers?page=1&limit=100`,
},
});
}
- if (
- url.endsWith(
- "/transactions/0x011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce/logs?limit=100&page=1"
- )
- ) {
+ if (url.endsWith(`transactions/${hashPaidByPaymaster}/transfers?limit=100&page=1`)) {
+ return Promise.resolve({
+ items: [
+ {
+ from: "0x18d211E22dB19741FF25838A22e4e696FeE7eD36",
+ to: "0x0000000000000000000000000000000000008001",
+ blockNumber: 1162235,
+ transactionHash: hashPaidByPaymaster,
+ amount: "1561368069251910",
+ tokenAddress: ETH_TOKEN.address,
+ type: "fee",
+ fields: null,
+ token: ETH_TOKEN,
+ },
+ {
+ from: "0x0000000000000000000000000000000000008001",
+ to: "0x18d211E22dB19741FF25838A22e4e696FeE7eD36",
+ blockNumber: 1162235,
+ transactionHash: hashPaidByPaymaster,
+ amount: "116665569251910",
+ tokenAddress: ETH_TOKEN.address,
+ type: "refund",
+ fields: null,
+ token: ETH_TOKEN,
+ },
+ ],
+ meta: {
+ totalItems: 2,
+ itemCount: 2,
+ itemsPerPage: 100,
+ totalPages: 1,
+ currentPage: 1,
+ },
+ links: {
+ first: `transactions/${hashPaidByPaymaster}/transfers?limit=100`,
+ previous: "",
+ next: "",
+ last: `transactions/${hashPaidByPaymaster}/transfers?page=1&limit=100`,
+ },
+ });
+ }
+ if (url.includes("/logs?limit=100&page=1")) {
return Promise.resolve({
items: logs,
meta: {
@@ -193,10 +229,10 @@ vi.mock("ohmyfetch", async () => {
currentPage: 1,
},
links: {
- first: "transactions/0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c/logs?limit=100",
+ first: `transactions/${hash}/logs?limit=100`,
previous: "",
next: "",
- last: "transactions/0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c/logs?page=1&limit=100",
+ last: `transactions/${hash}/logs?page=1&limit=100`,
},
});
}
@@ -213,8 +249,6 @@ vi.mock("ohmyfetch", async () => {
};
});
-const hash = "0x011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce";
-
describe("useTransaction:", () => {
let mockContext: SpyInstance;
@@ -347,7 +381,7 @@ describe("useTransaction:", () => {
expect(isRequestFailed.value).toEqual(false);
expect(transaction.value).toEqual({
- hash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ hash,
blockHash: "0x1fc6a30903866bf91cede9f831e71f2c7ba0dd023ffc044fe469c51b215d950b",
blockNumber: 1162235,
data: {
@@ -366,6 +400,7 @@ describe("useTransaction:", () => {
fee: "0x521f303519100",
feeData: {
amountPaid: "0x521f303519100",
+ isPaidByPaymaster: false,
refunds: [
{
amount: "116665569251910",
@@ -420,7 +455,7 @@ describe("useTransaction:", () => {
"0x0000000000000000000000000000000000000000000000000000000000008001",
"0x00000000000000000000000008d211e22db19741ff25838a22e4e696fee7ed36",
],
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
transactionIndex: "0",
},
{
@@ -433,7 +468,7 @@ describe("useTransaction:", () => {
"0x00000000000000000000000008d211e22db19741ff25838a22e4e696fee7ed36",
"0x00000000000000000000000008d211e22db19741ff25838a22e4e696fee7ed36",
],
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
transactionIndex: "0",
},
{
@@ -446,7 +481,7 @@ describe("useTransaction:", () => {
"0x0000000000000000000000000000000000000000000000000000000000008001",
"0x00000000000000000000000008d211e22db19741ff25838a22e4e696fee7ed36",
],
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
transactionIndex: "0",
},
{
@@ -459,7 +494,7 @@ describe("useTransaction:", () => {
"0x00000000000000000000000008d211e22db19741ff25838a22e4e696fee7ed36",
"0x0000000000000000000000000000000000000000000000000000000000008001",
],
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
transactionIndex: "0",
},
],
@@ -499,6 +534,36 @@ describe("useTransaction:", () => {
],
});
});
+ it("adds paymaster fields to fee data when transaction is paid by paymaster", async () => {
+ const { transaction, isRequestFailed, getByHash } = useTransaction();
+ await getByHash(hashPaidByPaymaster);
+
+ expect(isRequestFailed.value).toEqual(false);
+ expect(transaction.value?.feeData).toEqual({
+ amountPaid: "0x521f303519100",
+ isPaidByPaymaster: true,
+ paymasterAddress: "0x18d211E22dB19741FF25838A22e4e696FeE7eD36",
+ refunds: [
+ {
+ amount: "116665569251910",
+ from: "0x0000000000000000000000000000000000008001",
+ to: "0x18d211E22dB19741FF25838A22e4e696FeE7eD36",
+ fromNetwork: "L2",
+ toNetwork: "L2",
+ type: "refund",
+ tokenInfo: {
+ address: "0x000000000000000000000000000000000000800A",
+ l1Address: "0x0000000000000000000000000000000000000000",
+ l2Address: "0x000000000000000000000000000000000000800A",
+ symbol: "ETH",
+ name: "Ether",
+ decimals: 18,
+ },
+ },
+ ],
+ amountRefunded: "0x6a1b51d01246",
+ });
+ });
describe("when transaction request fails with not found error", () => {
it("fetches transaction data directly from blockchain", async () => {
const provider = {
@@ -570,6 +635,7 @@ describe("useTransaction:", () => {
fee: "0x521f303519100",
feeData: {
amountPaid: "0x521f303519100",
+ isPaidByPaymaster: false,
refunds: [],
amountRefunded: "0x00",
},
@@ -591,7 +657,7 @@ describe("useTransaction:", () => {
"0x0000000000000000000000000000000000000000000000000000000000008001",
"0x00000000000000000000000008d211e22db19741ff25838a22e4e696fee7ed36",
],
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
transactionIndex: "0",
},
{
@@ -604,7 +670,7 @@ describe("useTransaction:", () => {
"0x00000000000000000000000008d211e22db19741ff25838a22e4e696fee7ed36",
"0x00000000000000000000000008d211e22db19741ff25838a22e4e696fee7ed36",
],
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
transactionIndex: "0",
},
{
@@ -617,7 +683,7 @@ describe("useTransaction:", () => {
"0x0000000000000000000000000000000000000000000000000000000000008001",
"0x00000000000000000000000008d211e22db19741ff25838a22e4e696fee7ed36",
],
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
transactionIndex: "0",
},
{
@@ -630,7 +696,7 @@ describe("useTransaction:", () => {
"0x00000000000000000000000008d211e22db19741ff25838a22e4e696fee7ed36",
"0x0000000000000000000000000000000000000000000000000000000000008001",
],
- transactionHash: "0x9c526cc47ca2d3f72b7997a61d890d72951a283fa05d08df058ff8a629cffa3c",
+ transactionHash: hash,
transactionIndex: "0",
},
],