Skip to content

Commit

Permalink
fix: explorer doesn't require defined bridge address (#257)
Browse files Browse the repository at this point in the history
# What ❔

Fix explorer so that a defined bridge address is not required.

## Why ❔

In-memory node doesn't have L1 network and bridge addresses defined.
This fix make explorer work with the in-memory node.

## 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 May 24, 2024
1 parent 3c38e15 commit 146e2d9
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 47 deletions.
38 changes: 25 additions & 13 deletions packages/data-fetcher/src/blockchain/blockchain.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2362,23 +2362,35 @@ describe("BlockchainService", () => {

describe("onModuleInit", () => {
let bridgeAddresses;
beforeEach(() => {
bridgeAddresses = {
erc20L1: "l1Erc20DefaultBridge",
erc20L2: "l2Erc20DefaultBridge",
};

jest.spyOn(provider, "getDefaultBridgeAddresses").mockResolvedValueOnce(bridgeAddresses);
});
describe("when l2 ERC20 default bridge is defined", () => {
beforeEach(() => {
bridgeAddresses = {
erc20L2: "l2Erc20DefaultBridge",
};

it("inits L2 ERC20 bridge address", async () => {
await blockchainService.onModuleInit();
expect(blockchainService.bridgeAddresses.l2Erc20DefaultBridge).toBe(bridgeAddresses.erc20L2.toLowerCase());
jest.spyOn(provider, "getDefaultBridgeAddresses").mockResolvedValueOnce(bridgeAddresses);
});

it("inits L2 ERC20 bridge address", async () => {
await blockchainService.onModuleInit();
expect(blockchainService.bridgeAddresses.l2Erc20DefaultBridge).toBe(bridgeAddresses.erc20L2.toLowerCase());
});
});

it("inits L1 ERC20 bridge address", async () => {
await blockchainService.onModuleInit();
expect(blockchainService.bridgeAddresses.l1Erc20DefaultBridge).toBe(bridgeAddresses.erc20L1.toLowerCase());
describe("when l2 ERC20 default bridge is not defined", () => {
beforeEach(() => {
bridgeAddresses = {
erc20L2: null,
};

jest.spyOn(provider, "getDefaultBridgeAddresses").mockResolvedValueOnce(bridgeAddresses);
});

it("sets L2 ERC20 bridge address to null", async () => {
await blockchainService.onModuleInit();
expect(blockchainService.bridgeAddresses.l2Erc20DefaultBridge).toBe(undefined);
});
});
});
});
6 changes: 2 additions & 4 deletions packages/data-fetcher/src/blockchain/blockchain.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import { BLOCKCHAIN_RPC_CALL_DURATION_METRIC_NAME, BlockchainRpcCallMetricLabel
import { RetryableContract } from "./retryableContract";

export interface BridgeAddresses {
l1Erc20DefaultBridge: string;
l2Erc20DefaultBridge: string;
l2Erc20DefaultBridge?: string;
}

export interface TraceTransactionResult {
Expand Down Expand Up @@ -184,8 +183,7 @@ export class BlockchainService implements OnModuleInit {
const bridgeAddresses = await this.getDefaultBridgeAddresses();

this.bridgeAddresses = {
l1Erc20DefaultBridge: bridgeAddresses.erc20L1.toLowerCase(),
l2Erc20DefaultBridge: bridgeAddresses.erc20L2.toLowerCase(),
l2Erc20DefaultBridge: bridgeAddresses.erc20L2?.toLowerCase(),
};

this.logger.debug(`L2 ERC20 Bridge is set to: ${this.bridgeAddresses.l2Erc20DefaultBridge}`);
Expand Down
54 changes: 54 additions & 0 deletions packages/data-fetcher/src/token/token.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,60 @@ describe("TokenService", () => {
});
});

describe("when there is a bridge initialize log in transaction receipt but the default bridge contract is not defined", () => {
beforeEach(() => {
blockchainServiceMock.bridgeAddresses.l2Erc20DefaultBridge = undefined;
transactionReceipt.to = "0x0000000000000000000000000000000000001112";
transactionReceipt.logs = [
mock<types.Log>({
topics: [
"0x290afdae231a3fc0bbae8b1af63698b0a1d79b21ad17df0342dfb952fe74f8e5",
"0x000000000000000000000000913389f49358cb49a8e9e984a5871df43f80eb96",
"0x01000125c745537b5254be2ca086aee7fbd5d91789ed15790a942f9422d36447",
"0x0000000000000000000000005a393c95e7bddd0281650023d8c746fb1f596b7b",
],
}),
mock<types.Log>({
address: "0x5a393c95e7Bddd0281650023D8C746fB1F596B7b",
topics: [
"0x81e8e92e5873539605a102eddae7ed06d19bea042099a437cbc3644415eb7404",
"0x000000000000000000000000c8f8ce6491227a6a2ab92e67a64011a4eba1c6cf",
],
data: "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000134c313131206465706c6f79656420746f204c310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044c31313100000000000000000000000000000000000000000000000000000000",
}),
];

deployedContractAddress = mock<ContractAddress>({
address: "0x5a393c95e7bddd0281650023d8c746fb1f596b7b",
blockNumber: 10,
transactionHash: "transactionHash",
logIndex: 20,
});
});

it("starts the get token info duration metric", async () => {
await tokenService.getERC20Token(deployedContractAddress, transactionReceipt);
expect(startGetTokenInfoDurationMetricMock).toHaveBeenCalledTimes(1);
});

it("gets token data by the contract address", async () => {
await tokenService.getERC20Token(deployedContractAddress, transactionReceipt);
expect(blockchainServiceMock.getERC20TokenData).toHaveBeenCalledTimes(1);
expect(blockchainServiceMock.getERC20TokenData).toHaveBeenCalledWith(deployedContractAddress.address);
});

it("returns the token without l1Address", async () => {
const token = await tokenService.getERC20Token(deployedContractAddress, transactionReceipt);
expect(token).toStrictEqual({
...tokenData,
blockNumber: deployedContractAddress.blockNumber,
transactionHash: deployedContractAddress.transactionHash,
l2Address: deployedContractAddress.address,
logIndex: deployedContractAddress.logIndex,
});
});
});

describe("if the token symbol or name has special symbols", () => {
beforeEach(() => {
jest.spyOn(blockchainServiceMock, "getERC20TokenData").mockResolvedValueOnce({
Expand Down
14 changes: 1 addition & 13 deletions packages/data-fetcher/src/transfer/transfer.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { mock } from "jest-mock-extended";
import { BigNumber } from "ethers";
import { types } from "zksync-web3";
import { TransferService } from "./transfer.service";
import { BlockchainService } from "../blockchain/blockchain.service";
import { TokenType } from "../token/token.service";

import * as ethDepositNoFee from "../../test/transactionReceipts/eth/deposit-no-fee.json";
Expand Down Expand Up @@ -68,18 +67,7 @@ describe("TransferService", () => {

beforeEach(async () => {
const app = await Test.createTestingModule({
providers: [
TransferService,
{
provide: BlockchainService,
useValue: {
bridgeAddresses: {
l1Erc20DefaultBridge: "0xc0543dab6ac5d3e3ff2e5a5e39e15186d0306808",
l2Erc20DefaultBridge: "0xc7e0220d02d549c4846a6ec31d89c3b670ebe35c",
},
},
},
],
providers: [TransferService],
}).compile();

app.useLogger(mock<Logger>());
Expand Down
38 changes: 25 additions & 13 deletions packages/worker/src/blockchain/blockchain.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1613,23 +1613,35 @@ describe("BlockchainService", () => {

describe("onModuleInit", () => {
let bridgeAddresses;
beforeEach(() => {
bridgeAddresses = {
erc20L1: "l1Erc20DefaultBridge",
erc20L2: "l2Erc20DefaultBridge",
};

jest.spyOn(provider, "getDefaultBridgeAddresses").mockResolvedValueOnce(bridgeAddresses);
});
describe("when l2 ERC20 default bridge is defined", () => {
beforeEach(() => {
bridgeAddresses = {
erc20L2: "l2Erc20DefaultBridge",
};

it("inits L2 ERC20 bridge address", async () => {
await blockchainService.onModuleInit();
expect(blockchainService.bridgeAddresses.l2Erc20DefaultBridge).toBe(bridgeAddresses.erc20L2.toLowerCase());
jest.spyOn(provider, "getDefaultBridgeAddresses").mockResolvedValueOnce(bridgeAddresses);
});

it("inits L2 ERC20 bridge address", async () => {
await blockchainService.onModuleInit();
expect(blockchainService.bridgeAddresses.l2Erc20DefaultBridge).toBe(bridgeAddresses.erc20L2.toLowerCase());
});
});

it("inits L1 ERC20 bridge address", async () => {
await blockchainService.onModuleInit();
expect(blockchainService.bridgeAddresses.l1Erc20DefaultBridge).toBe(bridgeAddresses.erc20L1.toLowerCase());
describe("when l2 ERC20 default bridge is not defined", () => {
beforeEach(() => {
bridgeAddresses = {
erc20L2: null,
};

jest.spyOn(provider, "getDefaultBridgeAddresses").mockResolvedValueOnce(bridgeAddresses);
});

it("sets L2 ERC20 bridge address to null", async () => {
await blockchainService.onModuleInit();
expect(blockchainService.bridgeAddresses.l2Erc20DefaultBridge).toBe(undefined);
});
});
});
});
6 changes: 2 additions & 4 deletions packages/worker/src/blockchain/blockchain.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import { BLOCKCHAIN_RPC_CALL_DURATION_METRIC_NAME, BlockchainRpcCallMetricLabel
import { RetryableContract } from "./retryableContract";

export interface BridgeAddresses {
l1Erc20DefaultBridge: string;
l2Erc20DefaultBridge: string;
l2Erc20DefaultBridge?: string;
}

export interface TraceTransactionResult {
Expand Down Expand Up @@ -176,8 +175,7 @@ export class BlockchainService implements OnModuleInit {
const bridgeAddresses = await this.getDefaultBridgeAddresses();

this.bridgeAddresses = {
l1Erc20DefaultBridge: bridgeAddresses.erc20L1.toLowerCase(),
l2Erc20DefaultBridge: bridgeAddresses.erc20L2.toLowerCase(),
l2Erc20DefaultBridge: bridgeAddresses.erc20L2?.toLowerCase(),
};

this.logger.debug(`L2 ERC20 Bridge is set to: ${this.bridgeAddresses.l2Erc20DefaultBridge}`);
Expand Down
56 changes: 56 additions & 0 deletions packages/worker/src/token/token.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,62 @@ describe("TokenService", () => {
});
});

describe("when there is a bridge initialize log in transaction receipt but the default bridge contract is not defined", () => {
beforeEach(() => {
blockchainServiceMock.bridgeAddresses.l2Erc20DefaultBridge = undefined;
transactionReceipt.to = "0x0000000000000000000000000000000000001112";
transactionReceipt.logs = [
mock<types.Log>({
topics: [
"0x290afdae231a3fc0bbae8b1af63698b0a1d79b21ad17df0342dfb952fe74f8e5",
"0x000000000000000000000000913389f49358cb49a8e9e984a5871df43f80eb96",
"0x01000125c745537b5254be2ca086aee7fbd5d91789ed15790a942f9422d36447",
"0x0000000000000000000000005a393c95e7bddd0281650023d8c746fb1f596b7b",
],
}),
mock<types.Log>({
address: "0x5a393c95e7Bddd0281650023D8C746fB1F596B7b",
topics: [
"0x81e8e92e5873539605a102eddae7ed06d19bea042099a437cbc3644415eb7404",
"0x000000000000000000000000c8f8ce6491227a6a2ab92e67a64011a4eba1c6cf",
],
data: "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000134c313131206465706c6f79656420746f204c310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044c31313100000000000000000000000000000000000000000000000000000000",
}),
];

deployedContractAddress = mock<ContractAddress>({
address: "0x5a393c95e7bddd0281650023d8c746fb1f596b7b",
blockNumber: 10,
transactionHash: "transactionHash",
logIndex: 20,
});
});

it("starts the get token info duration metric", async () => {
await tokenService.saveERC20Token(deployedContractAddress, transactionReceipt);
expect(startGetTokenInfoDurationMetricMock).toHaveBeenCalledTimes(1);
});

it("gets token data by the contract address", async () => {
await tokenService.saveERC20Token(deployedContractAddress, transactionReceipt);
expect(blockchainServiceMock.getERC20TokenData).toHaveBeenCalledTimes(1);
expect(blockchainServiceMock.getERC20TokenData).toHaveBeenCalledWith(deployedContractAddress.address);
});

it("upserts the token without l1Address", async () => {
await tokenService.saveERC20Token(deployedContractAddress, transactionReceipt);
expect(tokenRepositoryMock.upsert).toHaveBeenCalledTimes(1);
expect(tokenRepositoryMock.upsert).toHaveBeenCalledWith({
...tokenData,
blockNumber: deployedContractAddress.blockNumber,
transactionHash: deployedContractAddress.transactionHash,
l2Address: deployedContractAddress.address,
l1Address: undefined,
logIndex: deployedContractAddress.logIndex,
});
});
});

describe("if the token symbol is empty", () => {
beforeEach(() => {
jest.spyOn(blockchainServiceMock, "getERC20TokenData").mockResolvedValueOnce({
Expand Down

0 comments on commit 146e2d9

Please sign in to comment.