@merkl/api 0.21.31 → 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 (41) hide show
  1. package/dist/src/eden/index.d.ts +89 -9
  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 +35 -3
  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.d.ts +3 -3
  31. package/dist/src/modules/v4/reward/reward.controller.js +14 -5
  32. package/dist/src/modules/v4/reward/reward.model.d.ts +1 -1
  33. package/dist/src/modules/v4/reward/reward.model.js +1 -1
  34. package/dist/src/modules/v4/router.d.ts +35 -3
  35. package/dist/src/modules/v4/router.js +3 -1
  36. package/dist/src/modules/v4/token/token.controller.js +1 -1
  37. package/dist/src/modules/v4/uniswap/uniswap.controller.js +1 -1
  38. package/dist/src/utils/decodeCalls.js +15 -5
  39. package/dist/src/utils/generateCardName.js +1 -0
  40. package/dist/tsconfig.package.tsbuildinfo +1 -1
  41. package/package.json +4 -3
@@ -2906,9 +2906,9 @@ declare const eden: {
2906
2906
  query: {
2907
2907
  items?: number | undefined;
2908
2908
  page?: number | undefined;
2909
+ campaignIds?: string[] | undefined;
2909
2910
  address: string;
2910
2911
  chainId: number;
2911
- campaignIds: string[];
2912
2912
  };
2913
2913
  fetch?: RequestInit | undefined;
2914
2914
  }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
@@ -2926,9 +2926,9 @@ declare const eden: {
2926
2926
  query: {
2927
2927
  items?: number | undefined;
2928
2928
  page?: number | undefined;
2929
+ campaignIds?: string[] | undefined;
2929
2930
  address: string;
2930
2931
  chainId: number;
2931
- campaignIds: string[];
2932
2932
  };
2933
2933
  fetch?: RequestInit | undefined;
2934
2934
  }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
@@ -2944,9 +2944,9 @@ declare const eden: {
2944
2944
  query: {
2945
2945
  items?: number | undefined;
2946
2946
  page?: number | undefined;
2947
+ campaignIds?: string[] | undefined;
2947
2948
  address: string;
2948
2949
  chainId: number;
2949
- campaignIds: string[];
2950
2950
  };
2951
2951
  fetch?: RequestInit | undefined;
2952
2952
  }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
@@ -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: {
@@ -8919,9 +8943,9 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
8919
8943
  query: {
8920
8944
  items?: number | undefined;
8921
8945
  page?: number | undefined;
8946
+ campaignIds?: string[] | undefined;
8922
8947
  address: string;
8923
8948
  chainId: number;
8924
- campaignIds: string[];
8925
8949
  };
8926
8950
  headers: unknown;
8927
8951
  response: {
@@ -8944,9 +8968,9 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
8944
8968
  query: {
8945
8969
  items?: number | undefined;
8946
8970
  page?: number | undefined;
8971
+ campaignIds?: string[] | undefined;
8947
8972
  address: string;
8948
8973
  chainId: number;
8949
- campaignIds: string[];
8950
8974
  };
8951
8975
  headers: unknown;
8952
8976
  response: {
@@ -8967,9 +8991,9 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
8967
8991
  query: {
8968
8992
  items?: number | undefined;
8969
8993
  page?: number | undefined;
8994
+ campaignIds?: string[] | undefined;
8970
8995
  address: string;
8971
8996
  chainId: number;
8972
- campaignIds: string[];
8973
8997
  };
8974
8998
  headers: unknown;
8975
8999
  response: {
@@ -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: {
@@ -15342,9 +15398,9 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
15342
15398
  query: {
15343
15399
  items?: number | undefined;
15344
15400
  page?: number | undefined;
15401
+ campaignIds?: string[] | undefined;
15345
15402
  address: string;
15346
15403
  chainId: number;
15347
- campaignIds: string[];
15348
15404
  };
15349
15405
  fetch?: RequestInit | undefined;
15350
15406
  }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
@@ -15362,9 +15418,9 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
15362
15418
  query: {
15363
15419
  items?: number | undefined;
15364
15420
  page?: number | undefined;
15421
+ campaignIds?: string[] | undefined;
15365
15422
  address: string;
15366
15423
  chainId: number;
15367
- campaignIds: string[];
15368
15424
  };
15369
15425
  fetch?: RequestInit | undefined;
15370
15426
  }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
@@ -15380,9 +15436,9 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
15380
15436
  query: {
15381
15437
  items?: number | undefined;
15382
15438
  page?: number | undefined;
15439
+ campaignIds?: string[] | undefined;
15383
15440
  address: string;
15384
15441
  chainId: number;
15385
- campaignIds: string[];
15386
15442
  };
15387
15443
  fetch?: RequestInit | undefined;
15388
15444
  }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
@@ -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
+ }
@@ -3342,9 +3342,9 @@ declare const app: Elysia<"", false, {
3342
3342
  query: {
3343
3343
  items?: number | undefined;
3344
3344
  page?: number | undefined;
3345
+ campaignIds?: string[] | undefined;
3345
3346
  address: string;
3346
3347
  chainId: number;
3347
- campaignIds: string[];
3348
3348
  };
3349
3349
  headers: unknown;
3350
3350
  response: {
@@ -3367,9 +3367,9 @@ declare const app: Elysia<"", false, {
3367
3367
  query: {
3368
3368
  items?: number | undefined;
3369
3369
  page?: number | undefined;
3370
+ campaignIds?: string[] | undefined;
3370
3371
  address: string;
3371
3372
  chainId: number;
3372
- campaignIds: string[];
3373
3373
  };
3374
3374
  headers: unknown;
3375
3375
  response: {
@@ -3390,9 +3390,9 @@ declare const app: Elysia<"", false, {
3390
3390
  query: {
3391
3391
  items?: number | undefined;
3392
3392
  page?: number | undefined;
3393
+ campaignIds?: string[] | undefined;
3393
3394
  address: string;
3394
3395
  chainId: number;
3395
- campaignIds: string[];
3396
3396
  };
3397
3397
  headers: unknown;
3398
3398
  response: {
@@ -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
  }