Skip to content

Commit

Permalink
refactor: replace Service with Provider (#53)
Browse files Browse the repository at this point in the history
## Description

- replace `Service` class names with `Provider` where correspond
  • Loading branch information
0xkenj1 authored Aug 22, 2024
1 parent b7d67af commit 155aac9
Show file tree
Hide file tree
Showing 42 changed files with 170 additions and 190 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ You can fetch metrics from the ZKsync ecosystem and ZK chains from L1 RPC (Ether
This repository is a monorepo consisting of 4 packages and 1 app:

- [`@zkchainhub/shared`](./packages/shared): A library for shared configurations, constants, types, etc.
- [`@zkchainhub/providers`](./packages/providers): A library that provides abstracted services over Viem providers to query blockchain data
- [`@zkchainhub/chain-providers`](./packages/chain-providers): A library that provides abstracted services over Viem providers to query blockchain data
- [`@zkchainhub/pricing`](./packages/pricing): An extensible library that provides Pricing services to fetch token prices. Currently, only Coingecko provider is developed
- [`@zkchainhub/metrics`](./packages/metrics): A library that provides different aggregated metrics from the ZKsync ecosystem and ZK chains.
- [`@zkchainhub/api`](./apps/api): An Express server that exposes an API where you can fetch information about ZKsync ecosystem and their chains, using the before mentioned libraries
Expand Down
2 changes: 1 addition & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"dependencies": {
"@zkchainhub/metrics": "workspace:*",
"@zkchainhub/pricing": "workspace:*",
"@zkchainhub/providers": "workspace:*",
"@zkchainhub/chain-providers": "workspace:*",
"@zkchainhub/shared": "workspace:*",
"bignumber.js": "9.1.2",
"cache-manager": "5.7.6",
Expand Down
8 changes: 4 additions & 4 deletions apps/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { inspect } from "util";
import { caching } from "cache-manager";

import { L1MetricsService } from "@zkchainhub/metrics";
import { CoingeckoService } from "@zkchainhub/pricing";
import { EvmProviderService } from "@zkchainhub/providers";
import { CoingeckoProvider } from "@zkchainhub/pricing";
import { Logger } from "@zkchainhub/shared";

import { EvmProvider } from "../../../packages/chain-providers/dist/src/index.js";
import { App } from "./app.js";
import { config } from "./common/config/index.js";
import { MetricsController, MetricsRouter } from "./metrics/index.js";
Expand All @@ -18,8 +18,8 @@ const main = async (): Promise<void> => {
ttl: config.pricing.cacheOptions.ttl * 1000 /*milliseconds*/,
});

const evmProvider = new EvmProviderService(config.l1.rpcUrls, config.l1.chain, logger);
const pricingProvider = new CoingeckoService(
const evmProvider = new EvmProvider(config.l1.rpcUrls, config.l1.chain, logger);
const pricingProvider = new CoingeckoProvider(
{
apiBaseUrl: config.pricing.pricingOptions.apiBaseUrl,
apiKey: config.pricing.pricingOptions.apiKey,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@zkchainhub/providers",
"name": "@zkchainhub/chain-providers",
"version": "1.0.0",
"main": "./dist/src/index.js",
"type": "module",
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ export {
RpcUrlsEmpty,
} from "./internal.js";

export { EvmProviderService, ZKChainProviderService } from "./internal.js";
export { EvmProvider, ZKChainProvider } from "./internal.js";
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import {
/**
* Acts as a wrapper around Viem library to provide methods to interact with an EVM-based blockchain.
*/
export class EvmProviderService {
export class EvmProvider {
private client: ReturnType<
typeof createPublicClient<FallbackTransport<HttpTransport[]>, Chain>
>;
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import { GetL1BatchDetailsReturnType, PublicActionsL2, publicActionsL2 } from "v
import { ILogger } from "@zkchainhub/shared";

import { InvalidArgumentException } from "../internal.js";
import { EvmProviderService } from "./evmProvider.service.js";
import { EvmProvider } from "./evmProvider.service.js";

/**
* Acts as a wrapper around Viem library to provide methods to interact with ZK chains.
*/
export class ZKChainProviderService extends EvmProviderService {
export class ZKChainProvider extends EvmProvider {
private zkClient: Client<
FallbackTransport<HttpTransport[]>,
Chain,
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ILogger } from "@zkchainhub/shared";
import { arrayAbiFixture, structAbiFixture } from "../../../src/fixtures/batchRequest.fixture.js";
import {
DataDecodeException,
EvmProviderService,
EvmProvider,
MulticallNotFound,
RpcUrlsEmpty,
} from "../../../src/internal.js";
Expand Down Expand Up @@ -45,8 +45,8 @@ const testAbi = parseAbi([
"function tokenURI(uint256 tokenId) pure returns (string)",
]);

describe("EvmProviderService", () => {
let viemProvider: EvmProviderService | null = null;
describe("EvmProvider", () => {
let viemProvider: EvmProvider | null = null;
const defaultMockChain: viem.Chain = vi.mocked<viem.Chain>({
...localhost,
contracts: { multicall3: undefined },
Expand All @@ -60,19 +60,19 @@ describe("EvmProviderService", () => {
});

it("has a client property defined", () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
expect(viemProvider["client"]).toBeDefined();
});

it("throws RpcUrlsEmpty error if rpcUrls is empty", () => {
expect(() => {
new EvmProviderService([], defaultMockChain, mockLogger);
new EvmProvider([], defaultMockChain, mockLogger);
}).toThrowError(RpcUrlsEmpty);
});

describe("getBalance", () => {
it("should return the balance of the specified address", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const address = "0x123456789";
const expectedBalance = 100n;
vi.spyOn(mockClient, "getBalance").mockResolvedValue(expectedBalance);
Expand All @@ -86,7 +86,7 @@ describe("EvmProviderService", () => {

describe("getBlockNumber", () => {
it("should return the current block number", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const expectedBlockNumber = 1000n;
vi.spyOn(mockClient, "getBlockNumber").mockResolvedValue(expectedBlockNumber);

Expand All @@ -98,7 +98,7 @@ describe("EvmProviderService", () => {

describe("getGasPrice", () => {
it("should return the current gas price", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const expectedGasPrice = BigInt(100);
// Mock the getGasPrice method of the Viem client
vi.spyOn(mockClient, "getGasPrice").mockResolvedValue(expectedGasPrice);
Expand All @@ -111,7 +111,7 @@ describe("EvmProviderService", () => {

describe("estimateGas", () => {
it("return the estimated gas for the given transaction", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const args = vi.mocked<viem.EstimateGasParameters<typeof localhost>>({
account: "0xffff",
to: viem.zeroAddress,
Expand All @@ -130,7 +130,7 @@ describe("EvmProviderService", () => {

describe("getStorageAt", () => {
it("should return the value of the storage slot at the given address and slot number", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const address = "0x123456789";
const slot = 1;
const expectedValue = "0xabcdef";
Expand All @@ -143,7 +143,7 @@ describe("EvmProviderService", () => {
});

it("should return the value of the storage slot at the given address and slot value", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const address = "0x123456789";
const slot = "0x12";
const expectedValue = "0xabcdef";
Expand All @@ -156,7 +156,7 @@ describe("EvmProviderService", () => {
});

it("should throw an error if the slot is not a positive integer", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const address = "0x123456789";
const slot = -1;

Expand All @@ -168,7 +168,7 @@ describe("EvmProviderService", () => {

describe("readContract", () => {
it("should call the readContract method of the Viem client with the correct arguments", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const contractAddress = "0x123456789";
const abi = testAbi;
const functionName = "balanceOf";
Expand All @@ -188,7 +188,7 @@ describe("EvmProviderService", () => {
});

it("should call the readContract method of the Viem client with the correct arguments when args are provided", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const contractAddress = "0x123456789";
const functionName = "tokenURI";
const args = [1n] as const;
Expand Down Expand Up @@ -216,7 +216,7 @@ describe("EvmProviderService", () => {

describe("batchRequest", () => {
it("should properly encode bytecode data and decode return data from batch request call", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const returnAbiParams = viem.parseAbiParameters([
"TokenData[] returnData",
"struct TokenData { uint8 tokenDecimals; string tokenSymbol; string tokenName; }",
Expand Down Expand Up @@ -245,7 +245,7 @@ describe("EvmProviderService", () => {
});

it("should fail if no data is returned", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const returnAbiParams = viem.parseAbiParameters([
"TokenData[] returnData",
"struct TokenData { uint8 tokenDecimals; string tokenSymbol; string tokenName; }",
Expand All @@ -264,7 +264,7 @@ describe("EvmProviderService", () => {
});

it("should fail if decoded data does not match validator (missing struct fields)", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
// this schema is incorrect, it should have 3 fields instead of 2
const returnAbiParams = viem.parseAbiParameters([
"WrongTokenData[] returnData",
Expand All @@ -286,7 +286,7 @@ describe("EvmProviderService", () => {
});

it("should fail if decoded data does not match validator (not struct vs struct)", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
// this schema is incorrect, it should have 3 fields instead of 2
const returnAbiParams = viem.parseAbiParameters("uint8 decimals, address[] owners");

Expand All @@ -305,7 +305,7 @@ describe("EvmProviderService", () => {
});

it("should properly decode address[]", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const returnAbiParams = viem.parseAbiParameters("address[]");

vi.spyOn(mockClient, "call").mockResolvedValue({ data: arrayAbiFixture.returnData });
Expand All @@ -327,7 +327,7 @@ describe("EvmProviderService", () => {
contracts: { multicall3: { address: "0x123456789" } },
});

viemProvider = new EvmProviderService(defaultRpcUrls, mockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, mockChain, mockLogger);
const contracts = [
{
address: "0x123456789",
Expand Down Expand Up @@ -363,7 +363,7 @@ describe("EvmProviderService", () => {
});

it("throws a MulticallNotFound error if the Multicall contract is not found for the chain", async () => {
viemProvider = new EvmProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
viemProvider = new EvmProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const contracts = [
{
address: "0x123456789",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";

import { ILogger } from "@zkchainhub/shared";

import {
InvalidArgumentException,
RpcUrlsEmpty,
ZKChainProviderService,
} from "../../../src/internal.js";
import { InvalidArgumentException, RpcUrlsEmpty, ZKChainProvider } from "../../../src/internal.js";

export const mockLogger: ILogger = {
info: vi.fn(),
Expand All @@ -18,8 +14,8 @@ export const mockLogger: ILogger = {
debug: vi.fn(),
};

describe("ZKChainProviderService", () => {
let zkProvider: ZKChainProviderService;
describe("ZKChainProvider", () => {
let zkProvider: ZKChainProvider;
const defaultMockChain = localhost;
const defaultRpcUrls = ["http://localhost:8545"];

Expand All @@ -28,19 +24,19 @@ describe("ZKChainProviderService", () => {
});

it("has a zkclient property defined", () => {
zkProvider = new ZKChainProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
zkProvider = new ZKChainProvider(defaultRpcUrls, defaultMockChain, mockLogger);
expect(zkProvider["zkClient"]).toBeDefined();
});

it("throws RpcUrlsEmpty error if rpcUrls is empty", () => {
expect(() => {
new ZKChainProviderService([], localhost, mockLogger);
new ZKChainProvider([], localhost, mockLogger);
}).toThrowError(RpcUrlsEmpty);
});

describe("avgBlockTime", () => {
it("should return the average block time over the given range", async () => {
zkProvider = new ZKChainProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
zkProvider = new ZKChainProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const currentBlockNumber = 1000;
const range = 100;
const currentBlockTimestamp = { timestamp: BigInt(123234345) };
Expand Down Expand Up @@ -68,7 +64,7 @@ describe("ZKChainProviderService", () => {
});

it("should throw an InvalidArgumentException if the range is less than 1", async () => {
zkProvider = new ZKChainProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
zkProvider = new ZKChainProvider(defaultRpcUrls, defaultMockChain, mockLogger);
await expect(zkProvider.avgBlockTime(0)).rejects.toThrowError(
new InvalidArgumentException("range for avgBlockTime should be >= 1"),
);
Expand All @@ -77,7 +73,7 @@ describe("ZKChainProviderService", () => {

describe("tps", () => {
it("should return the transactions per second (TPS)", async () => {
zkProvider = new ZKChainProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
zkProvider = new ZKChainProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const currentBatchNumber = 1000; // 1000 in hexadecimal
const currentBatchDetails = { l2TxCount: 200, timestamp: 123234345 };
const prevBatchDetails = { timestamp: 123123123 };
Expand All @@ -103,7 +99,7 @@ describe("ZKChainProviderService", () => {
});

it("should handle the case when there are no transactions", async () => {
zkProvider = new ZKChainProviderService(defaultRpcUrls, defaultMockChain, mockLogger);
zkProvider = new ZKChainProvider(defaultRpcUrls, defaultMockChain, mockLogger);
const currentBatchNumber = 1000; // 1000 in hexadecimal
const currentBatchDetails = { l2TxCount: 0, timestamp: 123234345 };
const prevBatchDetails = { timestamp: 123123123 };
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions packages/metadata/src/external.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export type { IMetadataService } from "./internal.js";
export type { IMetadataProvider } from "./internal.js";

export { StaticMetadataService, GithubMetadataService } from "./internal.js";
export { StaticMetadataProvider, GithubMetadataProvider } from "./internal.js";
2 changes: 1 addition & 1 deletion packages/metadata/src/interfaces/metadata.interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Token, TokenType, ZKChainMetadata } from "@zkchainhub/shared";

export interface IMetadataService {
export interface IMetadataProvider {
getChainsMetadata(): Promise<ZKChainMetadata>;
getTokensMetadata(): Promise<Token<TokenType>[]>;
}
2 changes: 1 addition & 1 deletion packages/metadata/src/internal.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from "./interfaces/index.js";
export * from "./services/index.js";
export * from "./providers/index.js";
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Token, TokenType, ZKChainMetadata } from "@zkchainhub/shared";

import { IMetadataService } from "../interfaces/index.js";
import { IMetadataProvider } from "../interfaces/index.js";

export class GithubMetadataService implements IMetadataService {
export class GithubMetadataProvider implements IMetadataProvider {
async getChainsMetadata(): Promise<ZKChainMetadata> {
//TODO: Implement this method
throw new Error("Method not implemented.");
Expand Down
2 changes: 2 additions & 0 deletions packages/metadata/src/providers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./githubMetadata.provider.js";
export * from "./staticMetadata.provider.js";
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Token, tokens, TokenType, ZKChainMetadata, zkChainsMetadata } from "@zkchainhub/shared";

import { IMetadataService } from "../interfaces/index.js";
import { IMetadataProvider } from "../interfaces/index.js";

export class StaticMetadataService implements IMetadataService {
export class StaticMetadataProvider implements IMetadataProvider {
async getChainsMetadata(): Promise<ZKChainMetadata> {
return structuredClone(zkChainsMetadata);
}
Expand Down
2 changes: 0 additions & 2 deletions packages/metadata/src/services/index.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { beforeEach, describe, expect, expectTypeOf, it } from "vitest";

import { Token, TokenType, ZKChainMetadata } from "@zkchainhub/shared";

import { StaticMetadataService } from "../../../src/internal.js";
import { StaticMetadataProvider } from "../../../src/internal.js";

describe("StaticMetadataService", () => {
let metadataService: StaticMetadataService;
describe("StaticMetadataProvider", () => {
let metadataService: StaticMetadataProvider;

beforeEach(() => {
metadataService = new StaticMetadataService();
metadataService = new StaticMetadataProvider();
});

describe("getChainsMetadata", () => {
Expand Down
Loading

0 comments on commit 155aac9

Please sign in to comment.