Skip to content

Commit 58fda7f

Browse files
authored
feat(indexer-api): expose hubpool balance endpoint (#81)
Signed-off-by: david <[email protected]>
1 parent bdbe939 commit 58fda7f

File tree

11 files changed

+109
-63
lines changed

11 files changed

+109
-63
lines changed

packages/indexer-api/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
"license": "ISC",
2323
"dependencies": {
2424
"@repo/indexer-database": "workspace:*",
25+
"@repo/indexer": "workspace:*",
2526
"@types/express": "^4.17.21",
2627
"@types/supertest": "^6.0.2",
2728
"body-parser": "^1.20.2",
2829
"cors": "^2.8.5",
2930
"express": "^4.19.2",
31+
"ioredis": "^5.4.1",
3032
"superstruct": "2.0.3-1",
3133
"winston": "^3.13.1"
3234
},
Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
import { Request, Response, NextFunction } from "express";
22
import * as s from "superstruct";
3-
import { DepositsService } from "../services/deposits";
3+
import { BalancesService } from "../services/balances";
44
import {
5-
HubPoolBalanceParams,
5+
HubPoolBalanceQueryParams,
66
SpokePoolBalanceParams,
77
} from "../dtos/balances.dto";
88

99
export class BalancesController {
10-
constructor(private service: DepositsService) {}
10+
constructor(private service: BalancesService) {}
1111

12-
public getHubPoolBalance = async (
12+
public getHubPoolBalance = (
1313
req: Request,
1414
res: Response,
1515
next: NextFunction,
1616
) => {
17-
s.assert(req.query, HubPoolBalanceParams);
18-
return 0;
17+
req.query && s.assert(req.query, HubPoolBalanceQueryParams);
18+
this.service
19+
.hubPoolBalance(req.query)
20+
.then((result) => res.json(result))
21+
.catch((err) => next(err));
1922
};
2023

21-
public getSpokePoolBalance = async (
24+
public getSpokePoolBalance = (
2225
req: Request,
2326
res: Response,
2427
next: NextFunction,
2528
) => {
26-
s.assert(req.query, SpokePoolBalanceParams);
27-
28-
return 0;
29+
req.query && s.assert(req.query, SpokePoolBalanceParams);
30+
res.json([]);
2931
};
3032
}

packages/indexer-api/src/dtos/balances.dto.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import * as s from "superstruct";
22

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

98
// query spokepools by chainId, must specify

packages/indexer-api/src/main.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,38 @@ import { createDataSource, DatabaseConfig } from "@repo/indexer-database";
44
import * as routers from "./routers";
55
import winston from "winston";
66
import { type Router } from "express";
7+
import Redis from "ioredis";
8+
import * as s from "superstruct";
9+
import * as Indexer from "@repo/indexer";
710

11+
async function initializeRedis(
12+
config: Indexer.RedisConfig,
13+
logger: winston.Logger,
14+
) {
15+
const redis = new Redis({
16+
...config,
17+
});
18+
19+
return new Promise<Redis>((resolve, reject) => {
20+
redis.on("ready", () => {
21+
logger.info({
22+
at: "Indexer-API",
23+
message: "Redis connection established",
24+
config,
25+
});
26+
resolve(redis);
27+
});
28+
29+
redis.on("error", (err) => {
30+
logger.error({
31+
at: "Indexer-API",
32+
message: "Redis connection failed",
33+
error: err,
34+
});
35+
reject(err);
36+
});
37+
});
38+
}
839
export async function connectToDatabase(
940
databaseConfig: DatabaseConfig,
1041
logger: winston.Logger,
@@ -52,9 +83,12 @@ export async function Main(
5283

5384
const postgresConfig = getPostgresConfig(env);
5485
const postgres = await connectToDatabase(postgresConfig, logger);
86+
const redisConfig = Indexer.parseRedisConfig(env);
87+
const redis = await initializeRedis(redisConfig, logger);
5588

5689
const allRouters: Record<string, Router> = {
5790
deposits: routers.deposits.getRouter(postgres),
91+
balances: routers.balances.getRouter(redis),
5892
};
5993
const app = ExpressApp(allRouters);
6094

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Router } from "express";
2+
import Redis from "ioredis";
3+
import { BalancesController } from "../controllers/balances";
4+
import { BalancesService } from "../services/balances";
5+
6+
export function getRouter(redis: Redis): Router {
7+
const router = Router();
8+
const service = new BalancesService(redis);
9+
const controller = new BalancesController(service);
10+
router.get("/hubpool-balance", controller.getHubPoolBalance);
11+
router.get("/spokepool-balance", controller.getSpokePoolBalance);
12+
return router;
13+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * as deposits from "./deposits";
2+
export * as balances from "./balances";
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import assert from "assert";
2+
import Redis from "ioredis";
3+
import * as Indexer from "@repo/indexer";
4+
5+
export class BalancesService {
6+
hubBalancesCache: Indexer.redis.hubBalancesCache.HubPoolBalanceCache;
7+
constructor(private redis: Redis) {
8+
this.hubBalancesCache =
9+
new Indexer.redis.hubBalancesCache.HubPoolBalanceCache({
10+
redis,
11+
prefix: "hubBalanceCache",
12+
});
13+
}
14+
async hubPoolBalance(params?: {
15+
l1Token?: string;
16+
}): Promise<Indexer.redis.hubBalancesCache.HubPoolBalances> {
17+
if (params?.l1Token) {
18+
const balance = await this.hubBalancesCache.get(params.l1Token);
19+
assert(balance, `No hubpoolBalance found for ${params.l1Token}`);
20+
return [balance];
21+
} else {
22+
return this.hubBalancesCache.getAllL1Tokens();
23+
}
24+
}
25+
}

packages/indexer/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from "./main";
22
export * from "./parseEnv";
3+
export * as redis from "./redis";

packages/indexer/src/parseEnv.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export type ProviderConfig = [providerUrl: string, chainId: number];
1717

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

20-
function parseRedisConfig(env: Env): RedisConfig {
20+
export function parseRedisConfig(env: Env): RedisConfig {
2121
assert(env.REDIS_HOST, "requires REDIS_HOST");
2222
assert(env.REDIS_PORT, "requires REDIS_PORT");
2323
const port = parseNumber(env.REDIS_PORT);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export * as bundleLeavesCache from "./bundleLeavesCache";
2+
export * as hubBalancesCache from "./hubBalancesCache";
3+
export * as rangeQueryStore from "./rangeQueryStore";
4+
export * as redisCache from "./redisCache";

0 commit comments

Comments
 (0)