From ef161c36bad2285f070af549e612593a82913487 Mon Sep 17 00:00:00 2001 From: Nikola Pavlov <144679078+tx-nikola@users.noreply.github.com> Date: Fri, 29 Nov 2024 10:23:34 +0100 Subject: [PATCH] feat: add `evm` badge for evm-like contracts and transactions --- .../src/address/address.controller.spec.ts | 2 + .../api/src/address/address.controller.ts | 1 + packages/api/src/address/address.entity.ts | 3 + packages/api/src/address/dtos/contract.dto.ts | 7 + .../normalizeAddress.transformer.ts | 1 + .../src/transaction/dtos/transaction.dto.ts | 21 +- .../entities/transaction.entity.ts | 10 +- packages/api/test/address.e2e-spec.ts | 5 + packages/api/test/transaction.e2e-spec.ts | 46 +++++ packages/app/src/components/Contract.vue | 1 + .../app/src/components/SolidityEditor.vue | 8 + packages/app/src/components/TheFooter.vue | 2 +- .../app/src/components/common/Dropdown.vue | 8 +- .../app/src/components/common/Pagination.vue | 186 ++++++++++++------ packages/app/src/components/common/Title.vue | 22 ++- .../src/components/event/ContractEvents.vue | 2 +- .../app/src/components/header/TheHeader.vue | 2 +- .../app/src/components/transactions/Table.vue | 86 +++++--- .../transactions/infoTable/GeneralInfo.vue | 46 ++++- .../transactions/infoTable/Logs.vue | 2 +- .../app/src/components/transfers/Table.vue | 2 +- packages/app/src/composables/common/Api.d.ts | 2 + .../composables/common/useFetchCollection.ts | 9 +- packages/app/src/composables/useAddress.ts | 1 + .../src/composables/useContractInteraction.ts | 20 +- packages/app/src/composables/useOpenChain.ts | 42 ++++ .../app/src/composables/useTransaction.ts | 4 +- packages/app/src/locales/en.json | 9 +- packages/app/src/locales/uk.json | 6 +- packages/app/src/views/BatchesView.vue | 14 +- packages/app/src/views/TransactionView.vue | 7 +- packages/app/tailwind.config.js | 3 + packages/app/tests/components/Account.spec.ts | 5 +- .../app/tests/components/TheFooter.spec.ts | 2 +- .../app/tests/components/TheHeader.spec.ts | 2 +- .../components/common/Pagination.spec.ts | 30 ++- .../transactions/GeneralInfo.spec.ts | 2 +- .../components/transactions/Table.spec.ts | 16 +- .../tests/components/transfers/Table.spec.ts | 5 + .../common/useFetchCollection.spec.ts | 2 +- .../useContractInteraction.spec.ts | 4 +- .../tests/composables/useTransactions.spec.ts | 4 +- .../features/artifacts/artifactsSet1.feature | 4 +- .../redirection/redirectionSet1.feature | 4 +- packages/app/tests/e2e/src/pages/base.page.ts | 4 + .../e2e/src/steps/blockexplorer.steps.ts | 5 + packages/app/tests/views/BatchView.spec.ts | 5 +- packages/app/tests/views/BlockView.spec.ts | 5 +- packages/app/tests/views/HomeView.spec.ts | 5 +- .../src/address/address.service.spec.ts | 2 + .../default.handler.ts | 9 +- .../interface/contractAddress.interface.ts | 1 + .../transaction/transaction.service.spec.ts | 9 + .../src/transaction/transaction.service.ts | 16 +- packages/worker/src/dataFetcher/types.ts | 3 + .../worker/src/entities/address.entity.ts | 3 + .../src/entities/addressTransaction.entity.ts | 4 +- .../worker/src/entities/transaction.entity.ts | 10 +- .../src/entities/transactionReceipt.entity.ts | 7 +- .../1732834401560-AddIsEvmLikeField.ts | 17 ++ ...91-AddContractAddressFieldToTransaction.ts | 13 ++ ...53474315-MakeTransactionToFieldOptional.ts | 17 ++ .../transaction/transaction.processor.spec.ts | 3 + .../src/transaction/transaction.processor.ts | 4 + 64 files changed, 633 insertions(+), 169 deletions(-) create mode 100644 packages/app/src/composables/useOpenChain.ts create mode 100644 packages/worker/src/migrations/1732834401560-AddIsEvmLikeField.ts create mode 100644 packages/worker/src/migrations/1733778459691-AddContractAddressFieldToTransaction.ts create mode 100644 packages/worker/src/migrations/1734453474315-MakeTransactionToFieldOptional.ts diff --git a/packages/api/src/address/address.controller.spec.ts b/packages/api/src/address/address.controller.spec.ts index 35586a0f8a..da1a5cae40 100644 --- a/packages/api/src/address/address.controller.spec.ts +++ b/packages/api/src/address/address.controller.spec.ts @@ -142,6 +142,7 @@ describe("AddressController", () => { blockNumber: addressBalances.blockNumber, balances: addressBalances.balances, totalTransactions: totalTxCount, + isEvmLike: addressRecord.isEvmLike, }); }); @@ -163,6 +164,7 @@ describe("AddressController", () => { blockNumber: addressRecord.createdInBlockNumber, balances: defaultBalancesResponse.balances, totalTransactions: totalTxCount, + isEvmLike: addressRecord.isEvmLike, }); }); }); diff --git a/packages/api/src/address/address.controller.ts b/packages/api/src/address/address.controller.ts index 2d7d9839a6..0172c404d0 100644 --- a/packages/api/src/address/address.controller.ts +++ b/packages/api/src/address/address.controller.ts @@ -75,6 +75,7 @@ export class AddressController { creatorTxHash: addressRecord.creatorTxHash, totalTransactions, creatorAddress: addressRecord.creatorAddress, + isEvmLike: addressRecord.isEvmLike, }; } diff --git a/packages/api/src/address/address.entity.ts b/packages/api/src/address/address.entity.ts index 5cd4583010..1f107d39ab 100644 --- a/packages/api/src/address/address.entity.ts +++ b/packages/api/src/address/address.entity.ts @@ -21,4 +21,7 @@ export class Address extends BaseEntity { @Column({ type: "bytea", nullable: true, transformer: normalizeAddressTransformer }) public readonly creatorAddress?: string; + + @Column({ type: "boolean", nullable: true }) + public readonly isEvmLike?: boolean; } diff --git a/packages/api/src/address/dtos/contract.dto.ts b/packages/api/src/address/dtos/contract.dto.ts index cef1b9adb3..e21cc25196 100644 --- a/packages/api/src/address/dtos/contract.dto.ts +++ b/packages/api/src/address/dtos/contract.dto.ts @@ -42,4 +42,11 @@ export class ContractDto extends BaseAddressDto { example: "0xd754Ff5e8a6f257E162F72578A4bB0493c0681d8", }) public readonly creatorAddress: string; + + @ApiProperty({ + type: Boolean, + description: "Is the contract EVM-like", + example: true, + }) + public readonly isEvmLike: boolean; } diff --git a/packages/api/src/common/transformers/normalizeAddress.transformer.ts b/packages/api/src/common/transformers/normalizeAddress.transformer.ts index ec08defd44..010a7aa80c 100644 --- a/packages/api/src/common/transformers/normalizeAddress.transformer.ts +++ b/packages/api/src/common/transformers/normalizeAddress.transformer.ts @@ -10,6 +10,7 @@ export const normalizeAddressTransformer: ValueTransformer = { if (!hex) { return null; } + return getAddress(hexTransformer.from(hex)); }, }; diff --git a/packages/api/src/transaction/dtos/transaction.dto.ts b/packages/api/src/transaction/dtos/transaction.dto.ts index 597ec07753..fefc44049a 100644 --- a/packages/api/src/transaction/dtos/transaction.dto.ts +++ b/packages/api/src/transaction/dtos/transaction.dto.ts @@ -12,9 +12,10 @@ export class TransactionDto { @ApiProperty({ type: String, description: "The address this transaction is to", - example: "0xc7e0220d02d549c4846A6EC31D89C3B670Ebe35C", + example: ["0xc7e0220d02d549c4846A6EC31D89C3B670Ebe35C", null], + nullable: true, }) - public readonly to: string; + public readonly to?: string; @ApiProperty({ type: String, @@ -204,4 +205,20 @@ export class TransactionDto { nullable: true, }) public readonly revertReason?: string; + + @ApiProperty({ + type: Boolean, + description: "Is the transaction EVM-like", + example: true, + nullable: true, + }) + public readonly isEvmLike?: boolean; + + @ApiProperty({ + type: String, + description: "Address of the first deployed EVM contract", + example: ["0xc7e0220d02d549c4846A6EC31D89C3B670Ebe35C", null], + nullable: true, + }) + public readonly contractAddress?: string; } diff --git a/packages/api/src/transaction/entities/transaction.entity.ts b/packages/api/src/transaction/entities/transaction.entity.ts index b907d539c5..a0871358d6 100644 --- a/packages/api/src/transaction/entities/transaction.entity.ts +++ b/packages/api/src/transaction/entities/transaction.entity.ts @@ -31,8 +31,8 @@ export class Transaction extends BaseEntity { @Column({ generated: true, type: "bigint" }) public number: number; - @Column({ type: "bytea", transformer: normalizeAddressTransformer }) - public readonly to: string; + @Column({ type: "bytea", transformer: normalizeAddressTransformer, nullable: true }) + public readonly to?: string; @Index() @Column({ type: "bytea", transformer: normalizeAddressTransformer }) @@ -107,6 +107,12 @@ export class Transaction extends BaseEntity { @Column({ nullable: true }) public readonly revertReason?: string; + @Column({ type: "boolean", nullable: true }) + public readonly isEvmLike?: boolean; + + @Column({ type: "bytea", transformer: normalizeAddressTransformer, nullable: true }) + public readonly contractAddress?: string; + public get status(): TransactionStatus { if (this.receiptStatus === 0) { return TransactionStatus.Failed; diff --git a/packages/api/test/address.e2e-spec.ts b/packages/api/test/address.e2e-spec.ts index 7ffa7f5508..151875c0e0 100644 --- a/packages/api/test/address.e2e-spec.ts +++ b/packages/api/test/address.e2e-spec.ts @@ -790,6 +790,7 @@ describe("AddressController (e2e)", () => { createdInBlockNumber: 10, creatorAddress: "0x91d0a23f34e535e44Df8Ba84c53a0945cf0eEB60", creatorTxHash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e15", + isEvmLike: null, totalTransactions: 4, type: "contract", }) @@ -849,6 +850,7 @@ describe("AddressController (e2e)", () => { createdInBlockNumber: 10, creatorAddress: "0x91d0a23f34e535e44Df8Ba84c53a0945cf0eEB60", creatorTxHash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e15", + isEvmLike: null, totalTransactions: 4, type: "contract", }) @@ -908,6 +910,7 @@ describe("AddressController (e2e)", () => { createdInBlockNumber: 10, creatorAddress: "0x91d0a23f34e535e44Df8Ba84c53a0945cf0eEB60", creatorTxHash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e15", + isEvmLike: null, totalTransactions: 4, type: "contract", }) @@ -967,6 +970,7 @@ describe("AddressController (e2e)", () => { createdInBlockNumber: 10, creatorAddress: "0x91d0a23f34e535e44Df8Ba84c53a0945cf0eEB60", creatorTxHash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e15", + isEvmLike: null, totalTransactions: 4, type: "contract", }) @@ -987,6 +991,7 @@ describe("AddressController (e2e)", () => { createdInBlockNumber: 10, creatorAddress: "0x91d0a23f34e535e44Df8Ba84c53a0945cf0eEB60", creatorTxHash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e15", + isEvmLike: null, totalTransactions: 0, type: "contract", }) diff --git a/packages/api/test/transaction.e2e-spec.ts b/packages/api/test/transaction.e2e-spec.ts index 305933ed74..6b7f225638 100644 --- a/packages/api/test/transaction.e2e-spec.ts +++ b/packages/api/test/transaction.e2e-spec.ts @@ -268,6 +268,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3009", maxPriorityFeePerGas: "4009", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e19", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: false, isL1Originated: true, l1BatchNumber: 9, @@ -296,6 +298,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3008", maxPriorityFeePerGas: "4008", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e18", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 8, @@ -324,6 +328,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3007", maxPriorityFeePerGas: "4007", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e17", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 7, @@ -352,6 +358,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3006", maxPriorityFeePerGas: "4006", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e16", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 6, @@ -380,6 +388,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3005", maxPriorityFeePerGas: "4005", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e15", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 5, @@ -408,6 +418,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3004", maxPriorityFeePerGas: "4004", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e14", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 4, @@ -436,6 +448,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3003", maxPriorityFeePerGas: "4003", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e13", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 3, @@ -464,6 +478,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3002", maxPriorityFeePerGas: "4002", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e12", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: false, isL1Originated: true, l1BatchNumber: 1, @@ -492,6 +508,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3001", maxPriorityFeePerGas: "4001", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e11", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: false, isL1Originated: true, l1BatchNumber: 1, @@ -520,6 +538,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3000", maxPriorityFeePerGas: "4000", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e10", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: false, isL1Originated: true, l1BatchNumber: 1, @@ -558,6 +578,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3008", maxPriorityFeePerGas: "4008", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e18", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 8, @@ -586,6 +608,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3007", maxPriorityFeePerGas: "4007", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e17", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 7, @@ -614,6 +638,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3006", maxPriorityFeePerGas: "4006", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e16", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 6, @@ -698,6 +724,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3001", maxPriorityFeePerGas: "4001", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e11", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: false, isL1Originated: true, l1BatchNumber: 1, @@ -751,6 +779,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3001", maxPriorityFeePerGas: "4001", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e11", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: false, isL1Originated: true, l1BatchNumber: 1, @@ -804,6 +834,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3007", maxPriorityFeePerGas: "4007", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e17", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 7, @@ -832,6 +864,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3006", maxPriorityFeePerGas: "4006", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e16", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 6, @@ -922,6 +956,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3008", maxPriorityFeePerGas: "4008", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e18", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 8, @@ -959,6 +995,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3005", maxPriorityFeePerGas: "4005", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e15", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 5, @@ -996,6 +1034,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3003", maxPriorityFeePerGas: "4003", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e13", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 3, @@ -1033,6 +1073,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3000", maxPriorityFeePerGas: "4000", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e10", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 1, @@ -1070,6 +1112,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3009", maxPriorityFeePerGas: "4009", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e19", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 9, @@ -1107,6 +1151,8 @@ describe("TransactionController (e2e)", () => { maxFeePerGas: "3000", maxPriorityFeePerGas: "4000", hash: "0x8a008b8dbbc18035e56370abb820e736b705d68d6ac12b203603db8d9ea87e10", + isEvmLike: null, + contractAddress: null, isL1BatchSealed: true, isL1Originated: true, l1BatchNumber: 1, diff --git a/packages/app/src/components/Contract.vue b/packages/app/src/components/Contract.vue index c8bf8a58b4..d60707f66b 100644 --- a/packages/app/src/components/Contract.vue +++ b/packages/app/src/components/Contract.vue @@ -8,6 +8,7 @@ :title="contractName ?? t('contract.title')" :value="contractName ? undefined : contract?.address" :is-verified="contract?.verificationInfo != null" + :is-evm-like="contract?.isEvmLike" />
diff --git a/packages/app/src/components/SolidityEditor.vue b/packages/app/src/components/SolidityEditor.vue index 538aa35966..52ad41f04a 100644 --- a/packages/app/src/components/SolidityEditor.vue +++ b/packages/app/src/components/SolidityEditor.vue @@ -116,6 +116,14 @@ function focusEditor() { .prism-editor__line-numbers { @apply h-max; } + + .prism-editor__container { + @apply overflow-x-scroll; + } + + .prism-editor__editor { + @apply text-nowrap; + } } } diff --git a/packages/app/src/components/TheFooter.vue b/packages/app/src/components/TheFooter.vue index 2347db302b..e5577f4bc4 100644 --- a/packages/app/src/components/TheFooter.vue +++ b/packages/app/src/components/TheFooter.vue @@ -24,7 +24,7 @@ const config = useRuntimeConfig(); const navigation = reactive([ { label: computed(() => t("footer.nav.docs")), - url: "https://docs.zksync.io/build/tooling/zksync-block-explorers", + url: "https://docs.zksync.io/zksync-era/tooling/block-explorers", }, { label: computed(() => t("footer.nav.terms")), diff --git a/packages/app/src/components/common/Dropdown.vue b/packages/app/src/components/common/Dropdown.vue index 87b5d6a6f8..9093bb24da 100644 --- a/packages/app/src/components/common/Dropdown.vue +++ b/packages/app/src/components/common/Dropdown.vue @@ -17,7 +17,7 @@ - + - + +
diff --git a/packages/app/src/components/event/ContractEvents.vue b/packages/app/src/components/event/ContractEvents.vue index 2eca89c86f..6e8afd4436 100644 --- a/packages/app/src/components/event/ContractEvents.vue +++ b/packages/app/src/components/event/ContractEvents.vue @@ -159,7 +159,7 @@ watch( @apply block; } .pagination { - @apply flex justify-center p-3; + @apply p-3; } .only-mobile { @apply flex md:hidden; diff --git a/packages/app/src/components/header/TheHeader.vue b/packages/app/src/components/header/TheHeader.vue index a311e4dd0a..f92cc6592e 100644 --- a/packages/app/src/components/header/TheHeader.vue +++ b/packages/app/src/components/header/TheHeader.vue @@ -159,7 +159,7 @@ const { currentNetwork } = useContext(); const navigation = reactive([ { label: computed(() => t("header.nav.documentation")), - url: "https://docs.zksync.io/build/tooling/zksync-block-explorers", + url: "https://docs.zksync.io/zksync-era/tooling/block-explorers", }, ]); diff --git a/packages/app/src/components/transactions/Table.vue b/packages/app/src/components/transactions/Table.vue index 46597e9910..f7814219d9 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 }} +
+ + +