Skip to content

Commit

Permalink
feat(indexer-api): expose hubpool balance endpoint (#81)
Browse files Browse the repository at this point in the history
Signed-off-by: david <[email protected]>
  • Loading branch information
daywiss authored Oct 25, 2024
1 parent bdbe939 commit 58fda7f
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 63 deletions.
2 changes: 2 additions & 0 deletions packages/indexer-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
"license": "ISC",
"dependencies": {
"@repo/indexer-database": "workspace:*",
"@repo/indexer": "workspace:*",
"@types/express": "^4.17.21",
"@types/supertest": "^6.0.2",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"express": "^4.19.2",
"ioredis": "^5.4.1",
"superstruct": "2.0.3-1",
"winston": "^3.13.1"
},
Expand Down
22 changes: 12 additions & 10 deletions packages/indexer-api/src/controllers/balances.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
import { Request, Response, NextFunction } from "express";
import * as s from "superstruct";
import { DepositsService } from "../services/deposits";
import { BalancesService } from "../services/balances";
import {
HubPoolBalanceParams,
HubPoolBalanceQueryParams,
SpokePoolBalanceParams,
} from "../dtos/balances.dto";

export class BalancesController {
constructor(private service: DepositsService) {}
constructor(private service: BalancesService) {}

public getHubPoolBalance = async (
public getHubPoolBalance = (
req: Request,
res: Response,
next: NextFunction,
) => {
s.assert(req.query, HubPoolBalanceParams);
return 0;
req.query && s.assert(req.query, HubPoolBalanceQueryParams);
this.service
.hubPoolBalance(req.query)
.then((result) => res.json(result))
.catch((err) => next(err));
};

public getSpokePoolBalance = async (
public getSpokePoolBalance = (
req: Request,
res: Response,
next: NextFunction,
) => {
s.assert(req.query, SpokePoolBalanceParams);

return 0;
req.query && s.assert(req.query, SpokePoolBalanceParams);
res.json([]);
};
}
5 changes: 2 additions & 3 deletions packages/indexer-api/src/dtos/balances.dto.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import * as s from "superstruct";

// query hub pools by chainId? default to 1 if not specified. will leave option in case of testnets?
export const HubPoolBalanceParams = s.object({
chainId: s.defaulted(s.number(), 1),
l1Token: s.string(),
export const HubPoolBalanceQueryParams = s.object({
l1Token: s.optional(s.string()),
});

// query spokepools by chainId, must specify
Expand Down
34 changes: 34 additions & 0 deletions packages/indexer-api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,38 @@ import { createDataSource, DatabaseConfig } from "@repo/indexer-database";
import * as routers from "./routers";
import winston from "winston";
import { type Router } from "express";
import Redis from "ioredis";
import * as s from "superstruct";
import * as Indexer from "@repo/indexer";

async function initializeRedis(
config: Indexer.RedisConfig,
logger: winston.Logger,
) {
const redis = new Redis({
...config,
});

return new Promise<Redis>((resolve, reject) => {
redis.on("ready", () => {
logger.info({
at: "Indexer-API",
message: "Redis connection established",
config,
});
resolve(redis);
});

redis.on("error", (err) => {
logger.error({
at: "Indexer-API",
message: "Redis connection failed",
error: err,
});
reject(err);
});
});
}
export async function connectToDatabase(
databaseConfig: DatabaseConfig,
logger: winston.Logger,
Expand Down Expand Up @@ -52,9 +83,12 @@ export async function Main(

const postgresConfig = getPostgresConfig(env);
const postgres = await connectToDatabase(postgresConfig, logger);
const redisConfig = Indexer.parseRedisConfig(env);
const redis = await initializeRedis(redisConfig, logger);

const allRouters: Record<string, Router> = {
deposits: routers.deposits.getRouter(postgres),
balances: routers.balances.getRouter(redis),
};
const app = ExpressApp(allRouters);

Expand Down
13 changes: 13 additions & 0 deletions packages/indexer-api/src/routers/balances.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Router } from "express";
import Redis from "ioredis";
import { BalancesController } from "../controllers/balances";
import { BalancesService } from "../services/balances";

export function getRouter(redis: Redis): Router {
const router = Router();
const service = new BalancesService(redis);
const controller = new BalancesController(service);
router.get("/hubpool-balance", controller.getHubPoolBalance);
router.get("/spokepool-balance", controller.getSpokePoolBalance);
return router;
}
1 change: 1 addition & 0 deletions packages/indexer-api/src/routers/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * as deposits from "./deposits";
export * as balances from "./balances";
25 changes: 25 additions & 0 deletions packages/indexer-api/src/services/balances.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import assert from "assert";
import Redis from "ioredis";
import * as Indexer from "@repo/indexer";

export class BalancesService {
hubBalancesCache: Indexer.redis.hubBalancesCache.HubPoolBalanceCache;
constructor(private redis: Redis) {
this.hubBalancesCache =
new Indexer.redis.hubBalancesCache.HubPoolBalanceCache({
redis,
prefix: "hubBalanceCache",
});
}
async hubPoolBalance(params?: {
l1Token?: string;
}): Promise<Indexer.redis.hubBalancesCache.HubPoolBalances> {
if (params?.l1Token) {
const balance = await this.hubBalancesCache.get(params.l1Token);
assert(balance, `No hubpoolBalance found for ${params.l1Token}`);
return [balance];
} else {
return this.hubBalancesCache.getAllL1Tokens();
}
}
}
1 change: 1 addition & 0 deletions packages/indexer/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./main";
export * from "./parseEnv";
export * as redis from "./redis";
2 changes: 1 addition & 1 deletion packages/indexer/src/parseEnv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type ProviderConfig = [providerUrl: string, chainId: number];

export type Env = Record<string, string | undefined>;

function parseRedisConfig(env: Env): RedisConfig {
export function parseRedisConfig(env: Env): RedisConfig {
assert(env.REDIS_HOST, "requires REDIS_HOST");
assert(env.REDIS_PORT, "requires REDIS_PORT");
const port = parseNumber(env.REDIS_PORT);
Expand Down
4 changes: 4 additions & 0 deletions packages/indexer/src/redis/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * as bundleLeavesCache from "./bundleLeavesCache";
export * as hubBalancesCache from "./hubBalancesCache";
export * as rangeQueryStore from "./rangeQueryStore";
export * as redisCache from "./redisCache";
63 changes: 14 additions & 49 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 58fda7f

Please sign in to comment.