Skip to content

Commit

Permalink
feat: migrate to zksync-ethers (#299)
Browse files Browse the repository at this point in the history
# What ❔

Migrate the Explorer from the deprecated `zksync-web3` to
`zksync-ethers`.

## Why ❔

Some explorer changes require SDK to be modified, in such cases the use
of a deprecated version becomes a problem.

## 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 Oct 29, 2024
1 parent 305401c commit 8085be9
Show file tree
Hide file tree
Showing 187 changed files with 2,393 additions and 4,257 deletions.
1,679 changes: 297 additions & 1,382 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"axios": "^1.4.0",
"class-transformer": "^0.5.1",
"class-validator": "0.14.0",
"ethers": "^5.7.2",
"ethers": "6.13.4",
"helmet": "^6.0.0",
"jest-mock-extended": "^3.0.1",
"nest-winston": "^1.7.0",
Expand Down
6 changes: 3 additions & 3 deletions packages/api/src/address/address.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
ApiExcludeController,
} from "@nestjs/swagger";
import { Pagination } from "nestjs-typeorm-paginate";
import { utils } from "ethers";
import { getAddress as ethersGetAddress } from "ethers";
import { PagingOptionsWithMaxItemsLimitDto, ListFiltersDto } from "../common/dtos";
import { ApiListPageOkResponse } from "../common/decorators/apiListPageOkResponse";
import { formatHexAddress, buildDateFilter } from "../common/utils";
Expand Down Expand Up @@ -85,7 +85,7 @@ export class AddressController {

return {
type: AddressType.Account,
address: utils.getAddress(address),
address: ethersGetAddress(address),
blockNumber: addressBalance.blockNumber,
balances: addressBalance.balances,
sealedNonce,
Expand All @@ -95,7 +95,7 @@ export class AddressController {

return {
type: AddressType.Account,
address: utils.getAddress(address),
address: ethersGetAddress(address),
blockNumber: await this.blockService.getLastBlockNumber(),
balances: {},
sealedNonce: 0,
Expand Down
3 changes: 1 addition & 2 deletions packages/api/src/api/mappers/internalTransactionMapper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { BigNumber } from "ethers";
import { Transfer } from "../../transfer/transfer.entity";
import { TransactionStatus } from "../../transaction/entities/transaction.entity";

Expand All @@ -14,7 +13,7 @@ export const mapInternalTransactionListItem = (transfer: Transfer) => ({
type: "call",
contractAddress: transfer.transaction?.transactionReceipt.contractAddress,
gasUsed: transfer.transaction?.transactionReceipt.gasUsed,
fee: transfer.transaction?.fee ? BigNumber.from(transfer.transaction.fee).toString() : undefined,
fee: transfer.transaction?.fee ? BigInt(transfer.transaction.fee).toString() : undefined,
l1BatchNumber: transfer.transaction?.l1BatchNumber.toString(),
traceId: "0",
transactionType: transfer.transaction?.type.toString(),
Expand Down
3 changes: 1 addition & 2 deletions packages/api/src/api/mappers/transactionMapper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { BigNumber } from "ethers";
import { getMethodId } from "../../common/utils";
import { AddressTransaction } from "../../transaction/entities/addressTransaction.entity";
import { TransactionStatus } from "../../transaction/entities/transaction.entity";
Expand All @@ -23,7 +22,7 @@ export const mapTransactionListItem = (addressTransaction: AddressTransaction, l
cumulativeGasUsed: addressTransaction.transaction.transactionReceipt.cumulativeGasUsed,
gasUsed: addressTransaction.transaction.transactionReceipt.gasUsed,
confirmations: (lastBlockNumber - addressTransaction.transaction.blockNumber).toString(),
fee: BigNumber.from(addressTransaction.transaction.fee).toString(),
fee: BigInt(addressTransaction.transaction.fee).toString(),
commitTxHash: addressTransaction.transaction.commitTxHash,
proveTxHash: addressTransaction.transaction.proveTxHash,
executeTxHash: addressTransaction.transaction.executeTxHash,
Expand Down
3 changes: 1 addition & 2 deletions packages/api/src/api/mappers/transferMapper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { BigNumber } from "ethers";
import { Transfer } from "../../transfer/transfer.entity";

export const mapTransferListItem = (transfer: Transfer, lastBlockNumber: number) => ({
Expand All @@ -22,7 +21,7 @@ export const mapTransferListItem = (transfer: Transfer, lastBlockNumber: number)
cumulativeGasUsed: transfer.transaction?.transactionReceipt.cumulativeGasUsed,
gasUsed: transfer.transaction?.transactionReceipt.gasUsed,
confirmations: (lastBlockNumber - transfer.blockNumber).toString(),
fee: transfer.transaction?.fee ? BigNumber.from(transfer.transaction.fee).toString() : undefined,
fee: transfer.transaction?.fee ? BigInt(transfer.transaction.fee).toString() : undefined,
l1BatchNumber: transfer.transaction?.l1BatchNumber.toString(),
transactionType: transfer.transaction?.type.toString(),
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe("hexToDecimalNumberTransformer", () => {

it("returns hex representation of the decimal number string", () => {
const result = hexToDecimalNumberTransformer.to("800");
expect(result).toBe("0x0320");
expect(result).toBe("0x320");
});
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { BigNumber } from "ethers";
import { ValueTransformer } from "typeorm";
import { numberToHex } from "../utils";

export const hexToDecimalNumberTransformer: ValueTransformer = {
to(decimalNumberStr: string | null): string | null {
if (!decimalNumberStr) {
return null;
}
return BigNumber.from(decimalNumberStr).toHexString();
return numberToHex(BigInt(decimalNumberStr));
},
from(hexNumberStr: string | null): string | null {
if (!hexNumberStr) {
return null;
}
return BigNumber.from(hexNumberStr).toString();
return BigInt(hexNumberStr).toString();
},
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { utils } from "ethers";
import { getAddress } from "ethers";
import { ValueTransformer } from "typeorm";
import { hexTransformer } from "./hex.transformer";

Expand All @@ -10,6 +10,6 @@ export const normalizeAddressTransformer: ValueTransformer = {
if (!hex) {
return null;
}
return utils.getAddress(hexTransformer.from(hex));
return getAddress(hexTransformer.from(hex));
},
};
12 changes: 12 additions & 0 deletions packages/api/src/common/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,18 @@ describe("utils", () => {
it("returns 0x if the specified number is undefined", () => {
expect(numberToHex(undefined)).toBe("0x");
});

it("returns hex str for the specified bigint", () => {
expect(numberToHex(BigInt("1000000000000000000000000"))).toBe("0xd3c21bcecceda1000000");
});

it("returns 0x if the specified bigint is null", () => {
expect(numberToHex(null)).toBe("0x");
});

it("returns 0x if the specified bigint is undefined", () => {
expect(numberToHex(undefined)).toBe("0x");
});
});

describe("parseIntToHex", () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export const getMethodId = (data: string) => (data.length > 10 ? data.substring(

export const dateToTimestamp = (date: Date) => Math.floor(date.getTime() / 1000);

export const numberToHex = (num: number) => (num != null ? `0x${num.toString(16)}` : "0x");
export const numberToHex = (num: number | bigint) => (num != null ? `0x${num.toString(16)}` : "0x");

export const parseIntToHex = (numStr: string) => {
if (numStr != null) {
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/dbMetrics.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe("DbMetricsService", () => {
beforeEach(() => {
jest.spyOn(global, "setInterval").mockImplementation((callback: () => void) => {
callback();
return timer;
return timer as unknown as NodeJS.Timeout;
});
jest.spyOn(global, "clearInterval");

Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/dbMetrics.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ export class DbMetricsService implements OnModuleInit, OnModuleDestroy {
}

public onModuleDestroy() {
clearInterval(this.collectDbConnectionPoolMetricsTimer);
clearInterval(this.collectDbConnectionPoolMetricsTimer as unknown as number);
}
}
12 changes: 6 additions & 6 deletions packages/api/test/transaction.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Test, TestingModule } from "@nestjs/testing";
import { INestApplication } from "@nestjs/common";
import * as request from "supertest";
import { Repository } from "typeorm";
import { BigNumber } from "ethers";
import { getRepositoryToken } from "@nestjs/typeorm";
import { AppModule } from "../src/app.module";
import { configureApp } from "../src/configureApp";
Expand All @@ -15,6 +14,7 @@ import { Transfer, TransferType } from "../src/transfer/transfer.entity";
import { Log } from "../src/log/log.entity";
import { BatchDetails } from "../src/batch/batchDetails.entity";
import { baseToken } from "../src/config";
import { numberToHex } from "../src/common/utils";

describe("TransactionController (e2e)", () => {
let ETH_TOKEN;
Expand Down Expand Up @@ -130,11 +130,11 @@ describe("TransactionController (e2e)", () => {
receivedAt: `2022-11-21T18:16:0${i}.000Z`,
l1BatchNumber: i < 3 ? 1 : i,
receiptStatus: i < 9 ? 1 : 0,
gasPrice: BigNumber.from(1000 + i).toString(),
gasLimit: BigNumber.from(2000 + i).toString(),
maxFeePerGas: BigNumber.from(3000 + i).toString(),
maxPriorityFeePerGas: BigNumber.from(4000 + i).toString(),
gasPerPubdata: BigNumber.from(5000 + i).toHexString(),
gasPrice: BigInt(1000 + i).toString(),
gasLimit: BigInt(2000 + i).toString(),
maxFeePerGas: BigInt(3000 + i).toString(),
maxPriorityFeePerGas: BigInt(4000 + i).toString(),
gasPerPubdata: numberToHex(BigInt(5000 + i)),
};
await transactionRepository.insert(transactionSpec);

Expand Down
3 changes: 3 additions & 0 deletions packages/app/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ module.exports = {
env: {
"vue/setup-compiler-macros": true,
},
globals: {
BigInt: true,
},
};
7 changes: 4 additions & 3 deletions packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"*.{vue,js,ts}": "npm run lint"
},
"dependencies": {
"@matterlabs/composables": "1.1.7",
"@metamask/detect-provider": "^2.0.0",
"@metamask/providers": "^10.2.1",
"@vueuse/components": "8.9.2",
"@vueuse/core": "8.9.2",
"date-fns": "2.28.0",
Expand All @@ -37,7 +38,7 @@
"vue-prism-editor": "2.0.0-alpha.2",
"vue-router": "4.0.14",
"vue-tippy": "6.0.0",
"zksync-web3": "0.13.1"
"zksync-ethers": "6.14.0"
},
"devDependencies": {
"@babel/core": "7.17.8",
Expand Down Expand Up @@ -82,7 +83,7 @@
"c8": "7.11.2",
"eslint-plugin-storybook": "^0.5.7",
"eslint-plugin-vue": "^8.2.0",
"ethers": "5.7.0",
"ethers": "6.13.4",
"jsdom": "19.0.0",
"playwright": "1.27.0",
"postcss": "^8.4.12",
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/components/ConnectMetamaskButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ import { useI18n } from "vue-i18n";
import { Listbox, ListboxButton, ListboxOption, ListboxOptions } from "@headlessui/vue";
import { DotsVerticalIcon } from "@heroicons/vue/outline";
import { useWallet } from "@matterlabs/composables";
import HashLabel from "@/components/common/HashLabel.vue";
import useContext from "@/composables/useContext";
import { default as useWallet } from "@/composables/useWallet";
const { t } = useI18n();
Expand Down
6 changes: 3 additions & 3 deletions packages/app/src/components/FeeData.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@
import { computed, type PropType, ref } from "vue";
import { useI18n } from "vue-i18n";
import { BigNumber } from "ethers";
import TokenAmountPrice from "@/components/TokenAmountPrice.vue";
import TransferTableCell from "@/components/transactions/infoTable/TransferTableCell.vue";
Expand All @@ -63,6 +61,8 @@ import useToken from "@/composables/useToken";
import type { Token } from "@/composables/useToken";
import type { FeeData } from "@/composables/useTransaction";
import { numberToHexString } from "@/utils/formatters";
const { currentNetwork } = useContext();
const props = defineProps({
Expand All @@ -86,7 +86,7 @@ getTokenInfo(currentNetwork.value.baseTokenAddress);
const initialFee = computed(() => {
if (props.feeData) {
return BigNumber.from(props.feeData.amountPaid).add(props.feeData.amountRefunded).toHexString();
return numberToHexString(BigInt(props.feeData.amountPaid) + BigInt(props.feeData.amountRefunded));
}
return null;
});
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/components/IndexerDelayAlert.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import SystemAlert from "@/components/common/SystemAlert.vue";
import useBlocks from "@/composables/useBlocks";
import useContext from "@/composables/useContext";
import type { types } from "zksync-web3";
import type { types } from "zksync-ethers";
const { t } = useI18n();
const context = useContext();
Expand Down
4 changes: 1 addition & 3 deletions packages/app/src/components/balances/Table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@
import { computed, type PropType, ref } from "vue";
import { useI18n } from "vue-i18n";
import { BigNumber } from "ethers";
import TokenIconLabel from "@/components/TokenIconLabel.vue";
import BalanceValue from "@/components/balances/BalanceValue.vue";
import ContentLoader from "@/components/common/loaders/ContentLoader.vue";
Expand Down Expand Up @@ -91,7 +89,7 @@ function showAllBalances() {
}
const validBalances = computed(() =>
Object.values(props.balances).filter((e) => !BigNumber.from(e.balance).isZero() && e.token)
Object.values(props.balances).filter((e) => BigInt(e.balance) != BigInt(0) && e.token)
);
const displayedBalances = computed(() => {
return [...validBalances.value]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { useI18n } from "vue-i18n";
import { useVuelidate } from "@vuelidate/core";
import { createI18nMessage, helpers, required } from "@vuelidate/validators";
import { ethers } from "ethers";
import { parseEther } from "ethers";
import Input from "@/components/common/Input.vue";
import FunctionArrayParameter from "@/components/contract/interaction/FunctionArrayParameter.vue";
Expand Down Expand Up @@ -144,7 +144,7 @@ const v$ = useVuelidate(
(value: string) => {
if (input.type === "ether") {
try {
ethers.utils.parseEther(value as string); // will throw an error in case if the value is invalid
parseEther(value as string); // will throw an error in case if the value is invalid
return true;
} catch {
return false;
Expand Down
30 changes: 14 additions & 16 deletions packages/app/src/composables/useAddress.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { ref } from "vue";

import { BigNumber } from "@ethersproject/bignumber";
import { keccak256 } from "@ethersproject/keccak256";
import { constants, ethers, utils } from "ethers";
import { Contract as EthersContract, isAddress, keccak256, toUtf8Bytes, ZeroAddress } from "ethers";
import { $fetch, FetchError } from "ohmyfetch";

import useContext from "./useContext";

import { PROXY_CONTRACT_IMPLEMENTATION_ABI } from "@/utils/constants";
import { numberToHexString } from "@/utils/formatters";

const EIP1967_PROXY_IMPLEMENTATION_SLOT = BigNumber.from(keccak256(utils.toUtf8Bytes("eip1967.proxy.implementation")))
.sub(1)
.toHexString();
const EIP1967_PROXY_BEACON_SLOT = BigNumber.from(keccak256(utils.toUtf8Bytes("eip1967.proxy.beacon")))
.sub(1)
.toHexString();
const EIP1822_PROXY_IMPLEMENTATION_SLOT = keccak256(utils.toUtf8Bytes("PROXIABLE"));
const oneBigInt = BigInt(1);
const EIP1967_PROXY_IMPLEMENTATION_SLOT = numberToHexString(
BigInt(keccak256(toUtf8Bytes("eip1967.proxy.implementation"))) - oneBigInt
);
const EIP1967_PROXY_BEACON_SLOT = numberToHexString(BigInt(keccak256(toUtf8Bytes("eip1967.proxy.beacon"))) - oneBigInt);
const EIP1822_PROXY_IMPLEMENTATION_SLOT = keccak256(toUtf8Bytes("PROXIABLE"));

type ContractFunctionInput = {
internalType: string;
Expand Down Expand Up @@ -110,7 +108,7 @@ export default (context = useContext()) => {
try {
const addressBytes = await getAddressFn();
const address = `0x${addressBytes.slice(-40)}`;
if (!utils.isAddress(address) || address === constants.AddressZero) {
if (!isAddress(address) || address === ZeroAddress) {
return null;
}
return address;
Expand All @@ -121,12 +119,12 @@ export default (context = useContext()) => {

const getProxyImplementation = async (address: string): Promise<string | null> => {
const provider = context.getL2Provider();
const proxyContract = new ethers.Contract(address, PROXY_CONTRACT_IMPLEMENTATION_ABI, provider);
const proxyContract = new EthersContract(address, PROXY_CONTRACT_IMPLEMENTATION_ABI, provider);
const [implementation, eip1967Implementation, eip1967Beacon, eip1822Implementation] = await Promise.all([
getAddressSafe(() => proxyContract.implementation()),
getAddressSafe(() => provider.getStorageAt(address, EIP1967_PROXY_IMPLEMENTATION_SLOT)),
getAddressSafe(() => provider.getStorageAt(address, EIP1967_PROXY_BEACON_SLOT)),
getAddressSafe(() => provider.getStorageAt(address, EIP1822_PROXY_IMPLEMENTATION_SLOT)),
getAddressSafe(() => provider.getStorage(address, EIP1967_PROXY_IMPLEMENTATION_SLOT)),
getAddressSafe(() => provider.getStorage(address, EIP1967_PROXY_BEACON_SLOT)),
getAddressSafe(() => provider.getStorage(address, EIP1822_PROXY_IMPLEMENTATION_SLOT)),
]);
if (implementation) {
return implementation;
Expand All @@ -138,7 +136,7 @@ export default (context = useContext()) => {
return eip1822Implementation;
}
if (eip1967Beacon) {
const beaconContract = new ethers.Contract(eip1967Beacon, PROXY_CONTRACT_IMPLEMENTATION_ABI, provider);
const beaconContract = new EthersContract(eip1967Beacon, PROXY_CONTRACT_IMPLEMENTATION_ABI, provider);
return getAddressSafe(() => beaconContract.implementation());
}
return null;
Expand Down
Loading

0 comments on commit 8085be9

Please sign in to comment.