@merkl/api 0.21.32 → 0.21.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/src/eden/index.d.ts +80 -0
  2. package/dist/src/engine/deprecated/erc20SubTypeProcessors/helpers/factoryFinder.js +1 -1
  3. package/dist/src/engine/deprecated/erc20SubTypeProcessors/implementations/curveProcessor.js +6 -2
  4. package/dist/src/engine/deprecated/erc20SubTypeProcessors/implementations/processorMapping.js +1 -0
  5. package/dist/src/engine/deprecated/erc20SubTypeProcessors/tokenTypeToProtocolAndAction.js +4 -0
  6. package/dist/src/engine/implementations/Erc20/subTypes/implementations/euler/tvl.js +5 -1
  7. package/dist/src/engine/implementations/Erc20/subTypes/index.d.ts +2 -1
  8. package/dist/src/engine/implementations/Erc20/subTypes/index.js +1 -0
  9. package/dist/src/guards/BackOffice.guard.d.ts +1 -1
  10. package/dist/src/guards/BackOffice.guard.js +1 -1
  11. package/dist/src/guards/Engine.guard.d.ts +1 -1
  12. package/dist/src/guards/Engine.guard.js +2 -3
  13. package/dist/src/guards/VerifyJwt.guard.d.ts +10 -0
  14. package/dist/src/guards/VerifyJwt.guard.js +13 -0
  15. package/dist/src/index.d.ts +32 -0
  16. package/dist/src/index.js +2 -0
  17. package/dist/src/modules/v4/accounting/accounting.controller.js +7 -13
  18. package/dist/src/modules/v4/authentication/authentication.controller.d.ts +52 -0
  19. package/dist/src/modules/v4/authentication/authentication.controller.js +23 -0
  20. package/dist/src/modules/v4/authentication/authentication.model.d.ts +10 -0
  21. package/dist/src/modules/v4/authentication/authentication.model.js +6 -0
  22. package/dist/src/modules/v4/authentication/authentication.service.d.ts +10 -0
  23. package/dist/src/modules/v4/authentication/authentication.service.js +31 -0
  24. package/dist/src/modules/v4/blacklist/blacklist.controller.js +2 -2
  25. package/dist/src/modules/v4/cache/cache.repository.d.ts +3 -0
  26. package/dist/src/modules/v4/cache/cache.repository.js +9 -0
  27. package/dist/src/modules/v4/cache/cache.service.d.ts +3 -0
  28. package/dist/src/modules/v4/cache/cache.service.js +9 -0
  29. package/dist/src/modules/v4/opportunity/opportunity.controller.js +1 -3
  30. package/dist/src/modules/v4/reward/reward.controller.js +13 -4
  31. package/dist/src/modules/v4/router.d.ts +32 -0
  32. package/dist/src/modules/v4/router.js +3 -1
  33. package/dist/src/modules/v4/token/token.controller.js +1 -1
  34. package/dist/src/modules/v4/uniswap/uniswap.controller.js +1 -1
  35. package/dist/src/utils/decodeCalls.js +15 -5
  36. package/dist/src/utils/generateCardName.js +1 -0
  37. package/dist/tsconfig.package.tsbuildinfo +1 -1
  38. package/package.json +4 -3
@@ -4951,6 +4951,30 @@ declare const eden: {
4951
4951
  };
4952
4952
  };
4953
4953
  };
4954
+ authlogin: {
4955
+ post: (body: {
4956
+ message: string;
4957
+ address: string;
4958
+ signature: string;
4959
+ }, options?: {
4960
+ headers?: Record<string, unknown> | undefined;
4961
+ query?: Record<string, unknown> | undefined;
4962
+ fetch?: RequestInit | undefined;
4963
+ } | undefined) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
4964
+ 200: void;
4965
+ }>>;
4966
+ };
4967
+ auth: {
4968
+ revoke: {
4969
+ delete: (body?: unknown, options?: {
4970
+ headers?: Record<string, unknown> | undefined;
4971
+ query?: Record<string, unknown> | undefined;
4972
+ fetch?: RequestInit | undefined;
4973
+ } | undefined) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
4974
+ 200: void;
4975
+ }>>;
4976
+ };
4977
+ };
4954
4978
  };
4955
4979
  v3: {
4956
4980
  app: {
@@ -11623,6 +11647,38 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
11623
11647
  };
11624
11648
  };
11625
11649
  };
11650
+ } & {
11651
+ v4: {
11652
+ authlogin: {
11653
+ post: {
11654
+ body: {
11655
+ message: string;
11656
+ address: string;
11657
+ signature: string;
11658
+ };
11659
+ params: {};
11660
+ query: unknown;
11661
+ headers: unknown;
11662
+ response: {
11663
+ 200: void;
11664
+ };
11665
+ };
11666
+ };
11667
+ } & {
11668
+ auth: {
11669
+ revoke: {
11670
+ delete: {
11671
+ body: unknown;
11672
+ params: {};
11673
+ query: unknown;
11674
+ headers: unknown;
11675
+ response: {
11676
+ 200: void;
11677
+ };
11678
+ };
11679
+ };
11680
+ };
11681
+ };
11626
11682
  } & {
11627
11683
  v3: {
11628
11684
  app: {
@@ -17387,6 +17443,30 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
17387
17443
  };
17388
17444
  };
17389
17445
  };
17446
+ authlogin: {
17447
+ post: (body: {
17448
+ message: string;
17449
+ address: string;
17450
+ signature: string;
17451
+ }, options?: {
17452
+ headers?: Record<string, unknown> | undefined;
17453
+ query?: Record<string, unknown> | undefined;
17454
+ fetch?: RequestInit | undefined;
17455
+ } | undefined) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
17456
+ 200: void;
17457
+ }>>;
17458
+ };
17459
+ auth: {
17460
+ revoke: {
17461
+ delete: (body?: unknown, options?: {
17462
+ headers?: Record<string, unknown> | undefined;
17463
+ query?: Record<string, unknown> | undefined;
17464
+ fetch?: RequestInit | undefined;
17465
+ } | undefined) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
17466
+ 200: void;
17467
+ }>>;
17468
+ };
17469
+ };
17390
17470
  };
17391
17471
  v3: {
17392
17472
  app: {
@@ -26,7 +26,7 @@ const factoryAddresses = {
26
26
  "0x5Ea9DD3b6f042A34Df818C6c1324BC5A7c61427a": Erc20SubType.curve, // Curve Corn 2crypto Factory
27
27
  "0xd7E72f3615aa65b92A4DBdC211E296a35512988B": Erc20SubType.curveNPool, // Curve Corn Stableswap Factory
28
28
  "0x7Ca46A636b02D4aBC66883D7FF164bDE506DC66a": Erc20SubType.curveNPool, // Curve Corn 3crypto Factory
29
- "0xbC0797015fcFc47d9C1856639CaE50D0e69FbEE8": Erc20SubType.curveNPool, // Curve Arbitrum 3crypto Factory
29
+ "0xbC0797015fcFc47d9C1856639CaE50D0e69FbEE8": Erc20SubType.curveTricrypto, // Curve Arbitrum 3crypto Factory
30
30
  "0xA5961898870943c68037F6848d2D866Ed2016bcB": Erc20SubType.curveNPool, // Curve Base
31
31
  "0xB255D6A720BB7c39fee173cE22113397119cB930": Erc20SubType.katana, // Katana Ronin
32
32
  "0x29372c22459a4e373851798bFd6808e71EA34A71": Erc20SubType.punchswap, // Punchswap Flow EVM
@@ -2,6 +2,7 @@ import { Erc20SubType } from "@/engine/implementations/Erc20/subTypes";
2
2
  import { generateCardName } from "@/utils/generateCardName";
3
3
  import { BN2Number } from "@sdk";
4
4
  import { GenericProcessor } from "../GenericProcessor";
5
+ import { getCrossCurveTokenPrice } from "../helpers/getCrossCurveTokenPrice";
5
6
  export class CurveProcessor extends GenericProcessor {
6
7
  rounds = {
7
8
  round1: [
@@ -50,8 +51,11 @@ export class CurveProcessor extends GenericProcessor {
50
51
  }
51
52
  if (type === Erc20SubType.curve_2) {
52
53
  const prices = [];
53
- for (const symbol of Object.values(typeInfo.poolTokens)) {
54
- const price = (await pricer.get({ symbol: symbol })) ?? 0;
54
+ for (const [address, symbol] of Object.entries(typeInfo.poolTokens)) {
55
+ let price = (await pricer.get({ symbol: symbol })) ?? 0;
56
+ if (price === 0) {
57
+ price = await getCrossCurveTokenPrice(address);
58
+ }
55
59
  prices.push(price);
56
60
  }
57
61
  let minPrice = Math.min(...prices);
@@ -155,4 +155,5 @@ export const processorMapping = {
155
155
  [Erc20SubType.stability]: StabilityProcessor,
156
156
  [Erc20SubType.stability_lending]: AaveProcessor,
157
157
  [Erc20SubType.hyperswap]: UniswapProcessor,
158
+ [Erc20SubType.curveTricrypto]: CurveNPoolProcessor,
158
159
  };
@@ -128,6 +128,10 @@ export const tokenTypeToProtocolAndAction = {
128
128
  protocol: "curve",
129
129
  action: OpportunityAction.POOL,
130
130
  },
131
+ [Erc20SubType.curveTricrypto]: {
132
+ protocol: "curve",
133
+ action: OpportunityAction.POOL,
134
+ },
131
135
  [Erc20SubType.sake_borrowing]: {
132
136
  protocol: "sake",
133
137
  action: OpportunityAction.BORROW,
@@ -37,7 +37,11 @@ export class EulerTVLBuilder {
37
37
  if (!underlyingToken.decimals || !underlyingToken.price) {
38
38
  throw new Error(`Missing decimals or price for token ${underlylingTokenAddress}`);
39
39
  }
40
- const tvl = bigIntToNumber(totalAssets, underlyingToken.decimals) * underlyingToken.price;
40
+ let tvl = bigIntToNumber(totalAssets, underlyingToken.decimals) * underlyingToken.price;
41
+ // If TVL is zero, set to 0.01
42
+ if (tvl === 0) {
43
+ tvl = 0.01;
44
+ }
41
45
  tvls.push({
42
46
  campaign,
43
47
  tvl,
@@ -113,5 +113,6 @@ export declare enum Erc20SubType {
113
113
  stability_lending = "stability_lending",
114
114
  lendle_vaults = "lendle_vaults",
115
115
  termmax = "termmax",
116
- hyperswap = "hyperswap"
116
+ hyperswap = "hyperswap",
117
+ curveTricrypto = "curveTricrypto"
117
118
  }
@@ -113,4 +113,5 @@ export var Erc20SubType;
113
113
  Erc20SubType["lendle_vaults"] = "lendle_vaults";
114
114
  Erc20SubType["termmax"] = "termmax";
115
115
  Erc20SubType["hyperswap"] = "hyperswap";
116
+ Erc20SubType["curveTricrypto"] = "curveTricrypto";
116
117
  })(Erc20SubType || (Erc20SubType = {}));
@@ -4,4 +4,4 @@ export declare const AuthorizationHeadersDto: import("@sinclair/typebox").TObjec
4
4
  export type AuthorizationHeaders = typeof AuthorizationHeadersDto.static;
5
5
  export declare function BackOfficeGuard({ headers }: {
6
6
  headers: AuthorizationHeaders;
7
- }): Promise<void>;
7
+ }): void;
@@ -3,7 +3,7 @@ import { t } from "elysia";
3
3
  export const AuthorizationHeadersDto = t.Object({
4
4
  authorization: t.String(),
5
5
  });
6
- export async function BackOfficeGuard({ headers }) {
6
+ export function BackOfficeGuard({ headers }) {
7
7
  if (headers.authorization !== `Bearer ${process.env.BACKOFFICE_SECRET}`) {
8
8
  throw new UnauthorizedError();
9
9
  }
@@ -4,4 +4,4 @@ export declare const AuthorizationHeadersDto: import("@sinclair/typebox").TObjec
4
4
  export type AuthorizationHeaders = typeof AuthorizationHeadersDto.static;
5
5
  export declare function EngineGuard({ headers }: {
6
6
  headers: AuthorizationHeaders;
7
- }): Promise<void>;
7
+ }): void;
@@ -3,8 +3,7 @@ import { t } from "elysia";
3
3
  export const AuthorizationHeadersDto = t.Object({
4
4
  authorization: t.String(),
5
5
  });
6
- export async function EngineGuard({ headers }) {
7
- if (headers.authorization !== `Bearer ${process.env.ENGINE_SECRET}`) {
6
+ export function EngineGuard({ headers }) {
7
+ if (headers.authorization !== `Bearer ${process.env.ENGINE_SECRET}`)
8
8
  throw new UnauthorizedError();
9
- }
10
9
  }
@@ -0,0 +1,10 @@
1
+ export declare const JwtCookieDto: import("@sinclair/typebox").TObject<{
2
+ jwt: import("@sinclair/typebox").TString;
3
+ }>;
4
+ export declare function VerifyJwtGuard({ cookie }: {
5
+ cookie: {
6
+ jwt: {
7
+ value: string;
8
+ };
9
+ };
10
+ }): Promise<void>;
@@ -0,0 +1,13 @@
1
+ import { UnauthorizedError } from "@/errors";
2
+ import { CacheService } from "@/modules/v4/cache/cache.service";
3
+ import { t } from "elysia";
4
+ import { jwtVerify } from "jose";
5
+ export const JwtCookieDto = t.Cookie({
6
+ jwt: t.String(),
7
+ });
8
+ const JWT_SECRET = new TextEncoder().encode(process.env.JWT_SECRET);
9
+ export async function VerifyJwtGuard({ cookie }) {
10
+ const decodedJwt = await jwtVerify(cookie.jwt.value, JWT_SECRET);
11
+ if (!decodedJwt.payload.jti || (await CacheService.sIsMember("token:revoked", decodedJwt.payload.jti)))
12
+ throw new UnauthorizedError("Failed to verify JWT.");
13
+ }
@@ -6046,6 +6046,38 @@ declare const app: Elysia<"", false, {
6046
6046
  };
6047
6047
  };
6048
6048
  };
6049
+ } & {
6050
+ v4: {
6051
+ authlogin: {
6052
+ post: {
6053
+ body: {
6054
+ message: string;
6055
+ address: string;
6056
+ signature: string;
6057
+ };
6058
+ params: {};
6059
+ query: unknown;
6060
+ headers: unknown;
6061
+ response: {
6062
+ 200: void;
6063
+ };
6064
+ };
6065
+ };
6066
+ } & {
6067
+ auth: {
6068
+ revoke: {
6069
+ delete: {
6070
+ body: unknown;
6071
+ params: {};
6072
+ query: unknown;
6073
+ headers: unknown;
6074
+ response: {
6075
+ 200: void;
6076
+ };
6077
+ };
6078
+ };
6079
+ };
6080
+ };
6049
6081
  } & {
6050
6082
  v3: {
6051
6083
  app: {
package/dist/src/index.js CHANGED
@@ -10,6 +10,8 @@ import { v2 } from "./routes/v2/router";
10
10
  import { v3 } from "./routes/v3/router";
11
11
  import { errorHandler } from "./utils/error";
12
12
  import { log } from "./utils/logger";
13
+ if (!process.env.JWT_SECRET)
14
+ throw new Error("Environment variable JWT_SECRET is missing.");
13
15
  // Axios with bun workaround
14
16
  axios.defaults.headers.common["Accept-Encoding"] = "gzip";
15
17
  const PORT = process.env.PORT || 3000;
@@ -7,30 +7,24 @@ export const AccountingController = new Elysia({ prefix: "/accounting", detail:
7
7
  .get("/", async ({ query }) => await AccountingService.findMany(query), {
8
8
  query: GetTransactionsQueryModel,
9
9
  headers: AuthorizationHeadersDto,
10
- beforeHandle: async ({ headers }) => {
11
- await BackOfficeGuard({ headers });
12
- },
10
+ beforeHandle: BackOfficeGuard,
13
11
  })
14
12
  .group("/revenues", app => {
15
13
  return app
16
14
  .get("", async () => await AccountingService.getAllRevenueBreakdownByChain(), {
17
15
  headers: AuthorizationHeadersDto,
18
- beforeHandle: async ({ headers }) => {
19
- await BackOfficeGuard({ headers });
20
- },
16
+ beforeHandle: BackOfficeGuard,
21
17
  })
22
18
  .get("/per-month/:year/:month", async ({ params }) => await AccountingService.getMonthlyRevenue(params.year, params.month), {
23
19
  params: DateDto,
24
20
  headers: AuthorizationHeadersDto,
25
- beforeHandle: async ({ headers }) => {
26
- await BackOfficeGuard({ headers });
27
- },
21
+ beforeHandle: BackOfficeGuard,
28
22
  })
29
23
  .get("/chains/:chainId", async ({ params }) => await AccountingService.getRevenueByChain(params.chainId), {
30
24
  params: ChainDto,
31
25
  headers: AuthorizationHeadersDto,
32
26
  beforeHandle: async ({ params, headers }) => {
33
- await BackOfficeGuard({ headers });
27
+ BackOfficeGuard({ headers });
34
28
  throwOnUnsupportedChainId(params.chainId);
35
29
  },
36
30
  })
@@ -38,7 +32,7 @@ export const AccountingController = new Elysia({ prefix: "/accounting", detail:
38
32
  params: RevenuesDto,
39
33
  headers: AuthorizationHeadersDto,
40
34
  beforeHandle: async ({ params, headers }) => {
41
- await BackOfficeGuard({ headers });
35
+ BackOfficeGuard({ headers });
42
36
  throwOnUnsupportedChainId(params.chainId);
43
37
  },
44
38
  });
@@ -50,7 +44,7 @@ export const AccountingController = new Elysia({ prefix: "/accounting", detail:
50
44
  params: TokensDto,
51
45
  headers: AuthorizationHeadersDto,
52
46
  beforeHandle: async ({ params, headers }) => {
53
- await BackOfficeGuard({ headers });
47
+ BackOfficeGuard({ headers });
54
48
  params.tokenAddress = throwOnInvalidRequiredAddress(params.tokenAddress);
55
49
  throwOnUnsupportedChainId(params.chainId);
56
50
  },
@@ -59,7 +53,7 @@ export const AccountingController = new Elysia({ prefix: "/accounting", detail:
59
53
  params: TokensDateDto,
60
54
  headers: AuthorizationHeadersDto,
61
55
  beforeHandle: async ({ params, headers }) => {
62
- await BackOfficeGuard({ headers });
56
+ BackOfficeGuard({ headers });
63
57
  params.tokenAddress = throwOnInvalidRequiredAddress(params.tokenAddress);
64
58
  throwOnUnsupportedChainId(params.chainId);
65
59
  },
@@ -0,0 +1,52 @@
1
+ import Elysia from "elysia";
2
+ export declare const AuthController: Elysia<"/auth", false, {
3
+ decorator: {};
4
+ store: {};
5
+ derive: {};
6
+ resolve: {};
7
+ }, {
8
+ type: {};
9
+ error: {};
10
+ }, {
11
+ schema: {};
12
+ macro: {};
13
+ macroFn: {};
14
+ }, {
15
+ authlogin: {
16
+ post: {
17
+ body: {
18
+ message: string;
19
+ address: string;
20
+ signature: string;
21
+ };
22
+ params: {};
23
+ query: unknown;
24
+ headers: unknown;
25
+ response: {
26
+ 200: void;
27
+ };
28
+ };
29
+ };
30
+ } & {
31
+ auth: {
32
+ revoke: {
33
+ delete: {
34
+ body: unknown;
35
+ params: {};
36
+ query: unknown;
37
+ headers: unknown;
38
+ response: {
39
+ 200: void;
40
+ };
41
+ };
42
+ };
43
+ };
44
+ }, {
45
+ derive: {};
46
+ resolve: {};
47
+ schema: {};
48
+ }, {
49
+ derive: {};
50
+ resolve: {};
51
+ schema: {};
52
+ }>;
@@ -0,0 +1,23 @@
1
+ import { JwtCookieDto, VerifyJwtGuard } from "@/guards/VerifyJwt.guard";
2
+ import Elysia from "elysia";
3
+ import { LoginDto } from "./authentication.model";
4
+ import { AuthService } from "./authentication.service";
5
+ const authService = new AuthService();
6
+ export const AuthController = new Elysia({
7
+ prefix: "/auth",
8
+ detail: { tags: ["Authentication"] },
9
+ })
10
+ .post("login", async ({ body, cookie: { jwt } }) => {
11
+ jwt.value = await authService.login(body);
12
+ jwt.sameSite = true;
13
+ jwt.path = "/";
14
+ jwt.httpOnly = true;
15
+ jwt.secure = true;
16
+ jwt.maxAge = 2 * 60 * 60; // 2h
17
+ return;
18
+ }, { body: LoginDto })
19
+ .delete("/revoke", async ({ cookie: { jwt } }) => {
20
+ await authService.revokeToken(jwt.value);
21
+ jwt.remove();
22
+ return;
23
+ }, { beforeHandle: VerifyJwtGuard, cookie: JwtCookieDto });
@@ -0,0 +1,10 @@
1
+ export declare const LoginDto: import("@sinclair/typebox").TObject<{
2
+ address: import("@sinclair/typebox").TString;
3
+ message: import("@sinclair/typebox").TString;
4
+ signature: import("@sinclair/typebox").TString;
5
+ }>;
6
+ export type MessageModel = {
7
+ address: `0x${string}`;
8
+ message: string;
9
+ signature: `0x${string}`;
10
+ };
@@ -0,0 +1,6 @@
1
+ import { t } from "elysia";
2
+ export const LoginDto = t.Object({
3
+ address: t.String({ pattern: "^(0x)?[0-9a-fA-F]{40}$" }),
4
+ message: t.String(),
5
+ signature: t.String({ pattern: "^(0x)?[0-9a-fA-F]{130}$" }),
6
+ });
@@ -0,0 +1,10 @@
1
+ import type { MessageModel } from "./authentication.model";
2
+ export declare class AuthService {
3
+ #private;
4
+ login(message: MessageModel): Promise<string>;
5
+ generateJwt(user: {
6
+ address: string;
7
+ creatorId: string | null;
8
+ }): Promise<string>;
9
+ revokeToken(jwt: string): Promise<void>;
10
+ }
@@ -0,0 +1,31 @@
1
+ import { UnauthorizedError } from "@/errors";
2
+ import { SignJWT, decodeJwt } from "jose";
3
+ import { http, createPublicClient } from "viem";
4
+ import { mainnet } from "viem/chains";
5
+ import { CacheService } from "../cache/cache.service";
6
+ import { UserService } from "../user/user.service";
7
+ export class AuthService {
8
+ #publicClient = createPublicClient({ chain: mainnet, transport: http() });
9
+ #encodedJwtSecret = new TextEncoder().encode(process.env.JWT_SECRET);
10
+ async login(message) {
11
+ if (!this.#publicClient.verifyMessage(message))
12
+ throw new UnauthorizedError("Failed to verify the message signature.");
13
+ let user = await UserService.findUnique(message.address);
14
+ if (!user)
15
+ user = await UserService.create({ address: message.address, tags: [] });
16
+ return await this.generateJwt(user);
17
+ }
18
+ async generateJwt(user) {
19
+ return await new SignJWT({ creator: user.creatorId })
20
+ .setProtectedHeader({ alg: "HS256" })
21
+ .setExpirationTime("2h")
22
+ .setAudience(user.address)
23
+ .setIssuer("merkl")
24
+ .setSubject("studio")
25
+ .setJti(Bun.randomUUIDv7())
26
+ .sign(this.#encodedJwtSecret);
27
+ }
28
+ async revokeToken(jwt) {
29
+ return await CacheService.sAdd("token:revoked", decodeJwt(jwt).jti);
30
+ }
31
+ }
@@ -23,7 +23,7 @@ export const BlacklistController = new Elysia({ prefix: "/blacklists", detail: {
23
23
  body: AddBlacklistDto,
24
24
  headers: AuthorizationHeadersDto,
25
25
  beforeHandle: async ({ body, headers }) => {
26
- await BackOfficeGuard({ headers });
26
+ BackOfficeGuard({ headers });
27
27
  body.userAddress = throwOnInvalidRequiredAddress(body.userAddress);
28
28
  body.poolAddress = throwOnInvalidRequiredAddress(body.poolAddress ?? NULL_ADDRESS);
29
29
  throwOnUnsupportedChainId(body.chainId);
@@ -35,7 +35,7 @@ export const BlacklistController = new Elysia({ prefix: "/blacklists", detail: {
35
35
  params: RemoveBlacklistDto,
36
36
  headers: AuthorizationHeadersDto,
37
37
  beforeHandle: async ({ headers, params }) => {
38
- await BackOfficeGuard({ headers });
38
+ BackOfficeGuard({ headers });
39
39
  params.address = throwOnInvalidRequiredAddress(params.address);
40
40
  },
41
41
  detail: { hide: true },
@@ -2,4 +2,7 @@ export declare abstract class CacheRepository {
2
2
  static set(ttl: number, key: string, value: string): Promise<void>;
3
3
  static ttl(key: string): Promise<number>;
4
4
  static get(key: string): Promise<string | null>;
5
+ static sAdd(sName: string, sValue: string): Promise<void>;
6
+ static sRem(sName: string, sValue: string): Promise<void>;
7
+ static sIsMember(sName: string, sValue: string): Promise<any>;
5
8
  }
@@ -10,4 +10,13 @@ export class CacheRepository {
10
10
  static async get(key) {
11
11
  return await withRetry(withTimeout, [redisClient.get(key), REDIS_READ_TIMEOUT], REDIS_RETRIES);
12
12
  }
13
+ static async sAdd(sName, sValue) {
14
+ await withRetry(withTimeout, [redisClient.sAdd(sName, sValue), REDIS_WRITE_TIMEOUT], REDIS_RETRIES);
15
+ }
16
+ static async sRem(sName, sValue) {
17
+ await withRetry(withTimeout, [redisClient.sRem(sName, sValue), REDIS_WRITE_TIMEOUT], REDIS_RETRIES);
18
+ }
19
+ static async sIsMember(sName, sValue) {
20
+ return await withRetry(withTimeout, [redisClient.sIsMember(sName, sValue), REDIS_READ_TIMEOUT], REDIS_RETRIES);
21
+ }
13
22
  }
@@ -6,4 +6,7 @@ export declare abstract class CacheService {
6
6
  static keyAndTTL<Fn extends (...args: Args) => Promise<unknown>, Args extends unknown[]>(fn: Fn, ...args: Args): Promise<[string, number]>;
7
7
  static set<Fn extends (...args: Args) => Promise<unknown>, Args extends unknown[], T extends Awaited<ReturnType<Fn>>>(ttl: number, fn: Fn, ...args: Args): Promise<T>;
8
8
  static get<Fn extends (...args: Args) => Promise<unknown>, Args extends unknown[], T extends Awaited<ReturnType<Fn>>>(fn: Fn, args: Args): Promise<T | null>;
9
+ static sAdd(sName: string, sValue: string): Promise<void>;
10
+ static sRem(sName: string, sValue: string): Promise<void>;
11
+ static sIsMember(sName: string, sValue: string): Promise<any>;
9
12
  }
@@ -47,4 +47,13 @@ export class CacheService {
47
47
  return null;
48
48
  return CacheService.#uncompress(cached);
49
49
  }
50
+ static async sAdd(sName, sValue) {
51
+ return CacheRepository.sAdd(sName, sValue);
52
+ }
53
+ static async sRem(sName, sValue) {
54
+ return CacheRepository.sRem(sName, sValue);
55
+ }
56
+ static async sIsMember(sName, sValue) {
57
+ return await CacheRepository.sIsMember(sName, sValue);
58
+ }
50
59
  }
@@ -13,9 +13,7 @@ import { validateId } from "./validate-id.pipe";
13
13
  // ─── Opportunities Controller ────────────────────────────────────────────────
14
14
  export const OpportunityController = new Elysia({
15
15
  prefix: "/opportunities",
16
- detail: {
17
- tags: ["Opportunities"],
18
- },
16
+ detail: { tags: ["Opportunities"] },
19
17
  })
20
18
  // ─── Get All Opportunities ───────────────────────────────────────────
21
19
  .get("/", async ({ query }) => OpportunityService.findMany(query), {
@@ -68,11 +68,20 @@ export const RewardController = new Elysia({ prefix: "/rewards", detail: { tags:
68
68
  query.campaignIds = query?.campaignIds?.flatMap(x => x.split(","));
69
69
  throwOnUnsupportedChainId(query.chainId);
70
70
  },
71
- detail: { hide: true },
72
71
  })
73
- .get("/", async ({ query }) => await RewardService.breakdownForToken(query))
74
- .get("/total", async ({ query }) => await RewardService.totalForToken(query))
75
- .get("/count", async ({ query }) => await RewardService.countForToken(query));
72
+ .get("/", async ({ query }) => await RewardService.breakdownForToken(query), {
73
+ detail: {
74
+ description: "Returns the all the address that received rewards of a given token, sorted by descending amounts",
75
+ },
76
+ })
77
+ .get("/total", async ({ query }) => await RewardService.totalForToken(query), {
78
+ detail: { description: "Returns the total amount distributed for a given token" },
79
+ })
80
+ .get("/count", async ({ query }) => await RewardService.countForToken(query), {
81
+ detail: {
82
+ description: "Returns the number of recipients that earned rewards in a given token",
83
+ },
84
+ });
76
85
  })
77
86
  .group("/engine", {
78
87
  headers: AuthorizationHeadersDto,
@@ -5916,6 +5916,38 @@ export declare const v4: Elysia<"/v4", false, {
5916
5916
  };
5917
5917
  };
5918
5918
  };
5919
+ } & {
5920
+ v4: {
5921
+ authlogin: {
5922
+ post: {
5923
+ body: {
5924
+ message: string;
5925
+ address: string;
5926
+ signature: string;
5927
+ };
5928
+ params: {};
5929
+ query: unknown;
5930
+ headers: unknown;
5931
+ response: {
5932
+ 200: void;
5933
+ };
5934
+ };
5935
+ };
5936
+ } & {
5937
+ auth: {
5938
+ revoke: {
5939
+ delete: {
5940
+ body: unknown;
5941
+ params: {};
5942
+ query: unknown;
5943
+ headers: unknown;
5944
+ response: {
5945
+ 200: void;
5946
+ };
5947
+ };
5948
+ };
5949
+ };
5950
+ };
5919
5951
  }, {
5920
5952
  derive: {};
5921
5953
  resolve: {};
@@ -30,6 +30,7 @@ import { RedisInstrumentation } from "@opentelemetry/instrumentation-redis-4";
30
30
  import { AlwaysOffSampler, BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
31
31
  import { PrismaInstrumentation } from "@prisma/instrumentation";
32
32
  import Elysia from "elysia";
33
+ import { AuthController } from "./authentication/authentication.controller";
33
34
  import { ReferralController } from "./referral/referral.controller";
34
35
  import { TurtleController } from "./turtle/turtle.controller";
35
36
  // ─── V4 Router ───────────────────────────────────────────────────────────────
@@ -88,4 +89,5 @@ export const v4 = new Elysia({ tags: ["v4"], prefix: "/v4" })
88
89
  .use(CreatorController)
89
90
  .use(ReferralController)
90
91
  .use(UniswapController)
91
- .use(TurtleController);
92
+ .use(TurtleController)
93
+ .use(AuthController);