@merkl/api 0.10.283 → 0.10.285

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.
@@ -549,7 +549,7 @@ const config = {
549
549
  "binaryTargets": [
550
550
  {
551
551
  "fromEnvVar": null,
552
- "value": "debian-openssl-1.1.x",
552
+ "value": "debian-openssl-3.0.x",
553
553
  "native": true
554
554
  },
555
555
  {
@@ -550,7 +550,7 @@ const config = {
550
550
  "binaryTargets": [
551
551
  {
552
552
  "fromEnvVar": null,
553
- "value": "debian-openssl-1.1.x",
553
+ "value": "debian-openssl-3.0.x",
554
554
  "native": true
555
555
  },
556
556
  {
@@ -628,8 +628,8 @@ exports.PrismaClient = PrismaClient
628
628
  Object.assign(exports, Prisma)
629
629
 
630
630
  // file annotations for bundling tools to include these files
631
- path.join(__dirname, "libquery_engine-debian-openssl-1.1.x.so.node");
632
- path.join(process.cwd(), "database/api/.generated/libquery_engine-debian-openssl-1.1.x.so.node")
631
+ path.join(__dirname, "libquery_engine-debian-openssl-3.0.x.so.node");
632
+ path.join(process.cwd(), "database/api/.generated/libquery_engine-debian-openssl-3.0.x.so.node")
633
633
 
634
634
  // file annotations for bundling tools to include these files
635
635
  path.join(__dirname, "libquery_engine-linux-arm64-openssl-1.1.x.so.node");
@@ -373,7 +373,7 @@ const config = {
373
373
  "binaryTargets": [
374
374
  {
375
375
  "fromEnvVar": null,
376
- "value": "debian-openssl-1.1.x",
376
+ "value": "debian-openssl-3.0.x",
377
377
  "native": true
378
378
  },
379
379
  {
@@ -374,7 +374,7 @@ const config = {
374
374
  "binaryTargets": [
375
375
  {
376
376
  "fromEnvVar": null,
377
- "value": "debian-openssl-1.1.x",
377
+ "value": "debian-openssl-3.0.x",
378
378
  "native": true
379
379
  },
380
380
  {
@@ -452,8 +452,8 @@ exports.PrismaClient = PrismaClient
452
452
  Object.assign(exports, Prisma)
453
453
 
454
454
  // file annotations for bundling tools to include these files
455
- path.join(__dirname, "libquery_engine-debian-openssl-1.1.x.so.node");
456
- path.join(process.cwd(), "database/engine/.generated/libquery_engine-debian-openssl-1.1.x.so.node")
455
+ path.join(__dirname, "libquery_engine-debian-openssl-3.0.x.so.node");
456
+ path.join(process.cwd(), "database/engine/.generated/libquery_engine-debian-openssl-3.0.x.so.node")
457
457
 
458
458
  // file annotations for bundling tools to include these files
459
459
  path.join(__dirname, "libquery_engine-linux-arm64-openssl-1.1.x.so.node");
@@ -24,6 +24,7 @@ export declare const campaignsCacheUpdater: Elysia<"", false, {
24
24
  body: unknown;
25
25
  params: {};
26
26
  query: {
27
+ campaignTypes?: number[] | undefined;
27
28
  chainId: string;
28
29
  };
29
30
  headers: unknown;
@@ -18,7 +18,7 @@ import { executeSimple } from "../../utils/execute";
18
18
  import { log } from "../../utils/logger";
19
19
  import { ALL_CAMPAIGNS_FOR_CHAIN_AFTER } from "../../utils/queries/allCampaigns";
20
20
  const highCampaignsChains = [ChainId.ARBITRUM, ChainId.POLYGON, ChainId.BLAST, ChainId.BASE];
21
- export const campaignsCacheUpdater = new Elysia().get("/v3/update", async ({ query, set }) => {
21
+ export const campaignsCacheUpdater = new Elysia().get("/v3/update", async ({ query }) => {
22
22
  const rawChainId = query.chainId;
23
23
  let chainId;
24
24
  if (typeof rawChainId === "string") {
@@ -58,15 +58,17 @@ export const campaignsCacheUpdater = new Elysia().get("/v3/update", async ({ que
58
58
  log.local(`Data length after filtering: ${staticData.length}`);
59
59
  if (!!staticData) {
60
60
  // Build list of existing campaign types for this chain
61
- const campaignTypes = !staticData
62
- ? []
63
- : staticData
64
- .map(campaign => campaign.campaignType)
65
- .reduce((prev, campaignType) => {
66
- if (!prev.includes(campaignType))
67
- prev.push(campaignType);
68
- return prev;
69
- }, []);
61
+ const campaignTypes = !!query.campaignTypes
62
+ ? query.campaignTypes
63
+ : !staticData
64
+ ? []
65
+ : staticData
66
+ .map(campaign => campaign.campaignType)
67
+ .reduce((prev, campaignType) => {
68
+ if (!prev.includes(campaignType))
69
+ prev.push(campaignType);
70
+ return prev;
71
+ }, []);
70
72
  // Fetch dynamic data for all these types
71
73
  const promisesPerType = campaignTypes.map(async (campaignType) => {
72
74
  const campaigns = staticData.filter(campaign => campaign.campaignType === campaignType);
@@ -156,5 +158,6 @@ export const campaignsCacheUpdater = new Elysia().get("/v3/update", async ({ que
156
158
  }, {
157
159
  query: t.Object({
158
160
  chainId: t.String(),
161
+ campaignTypes: t.Optional(t.Array(t.Numeric())),
159
162
  }),
160
163
  });
@@ -882,6 +882,26 @@ declare const eden: {
882
882
  }>>;
883
883
  };
884
884
  };
885
+ explorers: {
886
+ post: (body: {
887
+ type: "ETHERSCAN" | "BLOCKSCOUT";
888
+ url: string;
889
+ chainId: number;
890
+ }, options: {
891
+ headers: {
892
+ authorization: string;
893
+ };
894
+ query?: Record<string, unknown> | undefined;
895
+ fetch?: RequestInit | undefined;
896
+ }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
897
+ 200: {
898
+ type: import("../../database/api/.generated").$Enums.ExplorerType;
899
+ url: string;
900
+ id: string;
901
+ chainId: number;
902
+ };
903
+ }>>;
904
+ };
885
905
  tokens: ((params: {
886
906
  id: string | number;
887
907
  }) => {
@@ -3839,6 +3859,31 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
3839
3859
  };
3840
3860
  };
3841
3861
  };
3862
+ } & {
3863
+ v4: {
3864
+ explorers: {
3865
+ post: {
3866
+ body: {
3867
+ type: "ETHERSCAN" | "BLOCKSCOUT";
3868
+ url: string;
3869
+ chainId: number;
3870
+ };
3871
+ params: {};
3872
+ query: unknown;
3873
+ headers: {
3874
+ authorization: string;
3875
+ };
3876
+ response: {
3877
+ 200: {
3878
+ type: import("../../database/api/.generated").$Enums.ExplorerType;
3879
+ url: string;
3880
+ id: string;
3881
+ chainId: number;
3882
+ };
3883
+ };
3884
+ };
3885
+ };
3886
+ };
3842
3887
  } & {
3843
3888
  v4: {
3844
3889
  tokens: {
@@ -7197,6 +7242,26 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
7197
7242
  }>>;
7198
7243
  };
7199
7244
  };
7245
+ explorers: {
7246
+ post: (body: {
7247
+ type: "ETHERSCAN" | "BLOCKSCOUT";
7248
+ url: string;
7249
+ chainId: number;
7250
+ }, options: {
7251
+ headers: {
7252
+ authorization: string;
7253
+ };
7254
+ query?: Record<string, unknown> | undefined;
7255
+ fetch?: RequestInit | undefined;
7256
+ }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
7257
+ 200: {
7258
+ type: import("../../database/api/.generated").$Enums.ExplorerType;
7259
+ url: string;
7260
+ id: string;
7261
+ chainId: number;
7262
+ };
7263
+ }>>;
7264
+ };
7200
7265
  tokens: ((params: {
7201
7266
  id: string | number;
7202
7267
  }) => {
@@ -583,6 +583,291 @@ export const extractOpportunities = {
583
583
  };
584
584
  return opportunity;
585
585
  },
586
+ [Campaign.ERC20]: (campaign, campaigns, prices) => {
587
+ const { chainId, tvl, campaignParameters: params, typeInfo, computeChainId, mainParameter } = campaign;
588
+ const { active, all } = campaigns;
589
+ // DEPRECATED!!!!
590
+ const map = {
591
+ actions: {
592
+ pool: [
593
+ "uniswapv2",
594
+ "velodrome",
595
+ "aerodrome",
596
+ "balancerGauge",
597
+ "balancerPool",
598
+ "curve",
599
+ "aura",
600
+ "akron",
601
+ "beefy",
602
+ "dragonswap",
603
+ "poolside",
604
+ "koi",
605
+ "pancakeswap",
606
+ "tempest",
607
+ "cross_curve",
608
+ "zkswap",
609
+ "maverickBoostedPosition",
610
+ "zkSwapThreePool",
611
+ "syncswap",
612
+ "rfx",
613
+ ],
614
+ borrow: ["radiant_borrow", "aave_borrowing", "euler_borrow", "zerolend_borrowing"],
615
+ lend: [
616
+ "gearbox",
617
+ "compound",
618
+ "radiant_lend",
619
+ "aave_lending",
620
+ "sturdy_aggregator",
621
+ "sturdy_silo",
622
+ "fraxlend",
623
+ "moonwell",
624
+ "ionic",
625
+ "fluid",
626
+ "silostaking",
627
+ "euler_lend",
628
+ "layerbank",
629
+ "zerolend_lending",
630
+ "venus",
631
+ "reactor_fusion",
632
+ "woofi",
633
+ ],
634
+ },
635
+ icons: {
636
+ pool: () => {
637
+ if (["balancerGauge", "balancerPool"].includes(campaign.type ?? ""))
638
+ return Object.values(typeInfo.poolTokens ?? {})
639
+ .map(tkn => tkn?.symbol)
640
+ .filter(tkn => tkn);
641
+ if (["curve"].includes(campaign.type ?? ""))
642
+ return Object.values(typeInfo.poolTokens ?? {}).filter(tkn => tkn);
643
+ if (["rfx"].includes(campaign.type ?? "")) {
644
+ return [typeInfo.symbolShortToken, typeInfo.symbolLongToken];
645
+ }
646
+ if (["maverickBoostedPosition"].includes(campaign.type ?? "")) {
647
+ return [typeInfo.symbolTokenA, typeInfo.symbolTokenB];
648
+ }
649
+ return [typeInfo.symbolToken0, typeInfo.symbolToken1];
650
+ },
651
+ lend: () => (campaign.type === "compound" ? [typeInfo.symbolBaseToken] : [typeInfo.symbolUnderlyingToken]),
652
+ borrow: () => [typeInfo.symbolUnderlyingToken],
653
+ hold: () => {
654
+ if (["toros", "enzyme"].includes(campaign.type))
655
+ return [typeInfo.symbolUnderlyingToken];
656
+ return [campaign.campaignParameters.symbolTargetToken];
657
+ },
658
+ },
659
+ };
660
+ const action = Object.entries(map.actions).find(([_action, _types]) => _types.includes(campaign.type ?? ""))?.[0] ?? "hold";
661
+ const icons = map.icons[action]();
662
+ const opportunity = {
663
+ id: `${Campaign.ERC20}_${mainParameter}`,
664
+ platform: params.symbolTargetToken,
665
+ name: typeInfo?.cardName,
666
+ chainId: !computeChainId ? chainId : computeChainId,
667
+ distributionChainId: chainId,
668
+ tvl,
669
+ action,
670
+ apr: getApr(active),
671
+ status: getStatus(all),
672
+ tags: getTags(campaigns.all),
673
+ dailyrewards: getDailyRewards(active, prices),
674
+ tokenIcons: icons,
675
+ campaigns: { ...campaigns, type: Campaign.ERC20, ids: campaigns.all.map(c => c.campaignId) },
676
+ rewardTokenIcons: getRewardTokenIcons(campaigns.active),
677
+ dailyRewardTokens: getRewardTokens(campaigns.active),
678
+ };
679
+ return opportunity;
680
+ },
681
+ [Campaign.ERC20LOGPROCESSOR]: (campaign, campaigns, prices) => {
682
+ const { chainId, tvl, campaignParameters: params, typeInfo, computeChainId, mainParameter } = campaign;
683
+ const { active, all } = campaigns;
684
+ // DEPRECATED!!!!
685
+ const map = {
686
+ actions: {
687
+ pool: [
688
+ "uniswapv2",
689
+ "velodrome",
690
+ "aerodrome",
691
+ "balancerGauge",
692
+ "balancerPool",
693
+ "curve",
694
+ "aura",
695
+ "akron",
696
+ "beefy",
697
+ "dragonswap",
698
+ "poolside",
699
+ "koi",
700
+ "pancakeswap",
701
+ "tempest",
702
+ "cross_curve",
703
+ "zkswap",
704
+ "maverickBoostedPosition",
705
+ "zkSwapThreePool",
706
+ "syncswap",
707
+ "rfx",
708
+ ],
709
+ borrow: ["radiant_borrow", "aave_borrowing", "euler_borrow", "zerolend_borrowing"],
710
+ lend: [
711
+ "gearbox",
712
+ "compound",
713
+ "radiant_lend",
714
+ "aave_lending",
715
+ "sturdy_aggregator",
716
+ "sturdy_silo",
717
+ "fraxlend",
718
+ "moonwell",
719
+ "ionic",
720
+ "fluid",
721
+ "silostaking",
722
+ "euler_lend",
723
+ "layerbank",
724
+ "zerolend_lending",
725
+ "venus",
726
+ "reactor_fusion",
727
+ "woofi",
728
+ ],
729
+ },
730
+ icons: {
731
+ pool: () => {
732
+ if (["balancerGauge", "balancerPool"].includes(campaign.type ?? ""))
733
+ return Object.values(typeInfo.poolTokens ?? {})
734
+ .map(tkn => tkn?.symbol)
735
+ .filter(tkn => tkn);
736
+ if (["curve"].includes(campaign.type ?? ""))
737
+ return Object.values(typeInfo.poolTokens ?? {}).filter(tkn => tkn);
738
+ if (["rfx"].includes(campaign.type ?? "")) {
739
+ return [typeInfo.symbolShortToken, typeInfo.symbolLongToken];
740
+ }
741
+ if (["maverickBoostedPosition"].includes(campaign.type ?? "")) {
742
+ return [typeInfo.symbolTokenA, typeInfo.symbolTokenB];
743
+ }
744
+ return [typeInfo.symbolToken0, typeInfo.symbolToken1];
745
+ },
746
+ lend: () => (campaign.type === "compound" ? [typeInfo.symbolBaseToken] : [typeInfo.symbolUnderlyingToken]),
747
+ borrow: () => [typeInfo.symbolUnderlyingToken],
748
+ hold: () => {
749
+ if (["toros", "enzyme"].includes(campaign.type))
750
+ return [typeInfo.symbolUnderlyingToken];
751
+ return [campaign.campaignParameters.symbolTargetToken];
752
+ },
753
+ },
754
+ };
755
+ const action = Object.entries(map.actions).find(([_action, _types]) => _types.includes(campaign.type ?? ""))?.[0] ?? "hold";
756
+ const icons = map.icons[action]();
757
+ const opportunity = {
758
+ id: `${Campaign.ERC20}_${mainParameter}`,
759
+ platform: params.symbolTargetToken,
760
+ name: typeInfo?.cardName,
761
+ chainId: !computeChainId ? chainId : computeChainId,
762
+ distributionChainId: chainId,
763
+ tvl,
764
+ action,
765
+ apr: getApr(active),
766
+ status: getStatus(all),
767
+ tags: getTags(campaigns.all),
768
+ dailyrewards: getDailyRewards(active, prices),
769
+ tokenIcons: icons,
770
+ campaigns: { ...campaigns, type: Campaign.ERC20, ids: campaigns.all.map(c => c.campaignId) },
771
+ rewardTokenIcons: getRewardTokenIcons(campaigns.active),
772
+ dailyRewardTokens: getRewardTokens(campaigns.active),
773
+ };
774
+ return opportunity;
775
+ },
776
+ [Campaign.ERC20REBASELOGPROCESSOR]: (campaign, campaigns, prices) => {
777
+ const { chainId, tvl, campaignParameters: params, typeInfo, computeChainId, mainParameter } = campaign;
778
+ const { active, all } = campaigns;
779
+ // DEPRECATED!!!!
780
+ const map = {
781
+ actions: {
782
+ pool: [
783
+ "uniswapv2",
784
+ "velodrome",
785
+ "aerodrome",
786
+ "balancerGauge",
787
+ "balancerPool",
788
+ "curve",
789
+ "aura",
790
+ "akron",
791
+ "beefy",
792
+ "dragonswap",
793
+ "poolside",
794
+ "koi",
795
+ "pancakeswap",
796
+ "tempest",
797
+ "cross_curve",
798
+ "zkswap",
799
+ "maverickBoostedPosition",
800
+ "zkSwapThreePool",
801
+ "syncswap",
802
+ "rfx",
803
+ ],
804
+ borrow: ["radiant_borrow", "aave_borrowing", "euler_borrow", "zerolend_borrowing"],
805
+ lend: [
806
+ "gearbox",
807
+ "compound",
808
+ "radiant_lend",
809
+ "aave_lending",
810
+ "sturdy_aggregator",
811
+ "sturdy_silo",
812
+ "fraxlend",
813
+ "moonwell",
814
+ "ionic",
815
+ "fluid",
816
+ "silostaking",
817
+ "euler_lend",
818
+ "layerbank",
819
+ "zerolend_lending",
820
+ "venus",
821
+ "reactor_fusion",
822
+ "woofi",
823
+ ],
824
+ },
825
+ icons: {
826
+ pool: () => {
827
+ if (["balancerGauge", "balancerPool"].includes(campaign.type ?? ""))
828
+ return Object.values(typeInfo.poolTokens ?? {})
829
+ .map(tkn => tkn?.symbol)
830
+ .filter(tkn => tkn);
831
+ if (["curve"].includes(campaign.type ?? ""))
832
+ return Object.values(typeInfo.poolTokens ?? {}).filter(tkn => tkn);
833
+ if (["rfx"].includes(campaign.type ?? "")) {
834
+ return [typeInfo.symbolShortToken, typeInfo.symbolLongToken];
835
+ }
836
+ if (["maverickBoostedPosition"].includes(campaign.type ?? "")) {
837
+ return [typeInfo.symbolTokenA, typeInfo.symbolTokenB];
838
+ }
839
+ return [typeInfo.symbolToken0, typeInfo.symbolToken1];
840
+ },
841
+ lend: () => (campaign.type === "compound" ? [typeInfo.symbolBaseToken] : [typeInfo.symbolUnderlyingToken]),
842
+ borrow: () => [typeInfo.symbolUnderlyingToken],
843
+ hold: () => {
844
+ if (["toros", "enzyme"].includes(campaign.type))
845
+ return [typeInfo.symbolUnderlyingToken];
846
+ return [campaign.campaignParameters.symbolTargetToken];
847
+ },
848
+ },
849
+ };
850
+ const action = Object.entries(map.actions).find(([_action, _types]) => _types.includes(campaign.type ?? ""))?.[0] ?? "hold";
851
+ const icons = map.icons[action]();
852
+ const opportunity = {
853
+ id: `${Campaign.ERC20}_${mainParameter}`,
854
+ platform: params.symbolTargetToken,
855
+ name: typeInfo?.cardName,
856
+ chainId: !computeChainId ? chainId : computeChainId,
857
+ distributionChainId: chainId,
858
+ tvl,
859
+ action,
860
+ apr: getApr(active),
861
+ status: getStatus(all),
862
+ tags: getTags(campaigns.all),
863
+ dailyrewards: getDailyRewards(active, prices),
864
+ tokenIcons: icons,
865
+ campaigns: { ...campaigns, type: Campaign.ERC20, ids: campaigns.all.map(c => c.campaignId) },
866
+ rewardTokenIcons: getRewardTokenIcons(campaigns.active),
867
+ dailyRewardTokens: getRewardTokens(campaigns.active),
868
+ };
869
+ return opportunity;
870
+ },
586
871
  };
587
872
  /**
588
873
  * @returns the opportunities map with their corresponding campaign's data added
@@ -1042,6 +1042,31 @@ declare const app: Elysia<"", false, {
1042
1042
  };
1043
1043
  };
1044
1044
  };
1045
+ } & {
1046
+ v4: {
1047
+ explorers: {
1048
+ post: {
1049
+ body: {
1050
+ type: "ETHERSCAN" | "BLOCKSCOUT";
1051
+ url: string;
1052
+ chainId: number;
1053
+ };
1054
+ params: {};
1055
+ query: unknown;
1056
+ headers: {
1057
+ authorization: string;
1058
+ };
1059
+ response: {
1060
+ 200: {
1061
+ type: import("../database/api/.generated").$Enums.ExplorerType;
1062
+ url: string;
1063
+ id: string;
1064
+ chainId: number;
1065
+ };
1066
+ };
1067
+ };
1068
+ };
1069
+ };
1045
1070
  } & {
1046
1071
  v4: {
1047
1072
  tokens: {
@@ -385,8 +385,6 @@ campaign //FIXME
385
385
  return prepareCompoundFetch(previous, campaign);
386
386
  case Campaign.EIGENLAYER:
387
387
  return prepareEigenLayerFetch(previous, campaign);
388
- case Campaign.VEST:
389
- return prepareEigenLayerFetch(previous, campaign);
390
388
  default:
391
389
  return previous;
392
390
  }
@@ -32,6 +32,7 @@ export class ClaimService {
32
32
  const token = claim?.token ? tokens[claim.token.toLowerCase()] : undefined;
33
33
  return {
34
34
  ...claim,
35
+ amount: claim.rawAmount,
35
36
  token,
36
37
  };
37
38
  });
@@ -22,7 +22,7 @@ import { getJsonAirdropMetadata } from "./subservices/getJsonAirDropMetadata.ser
22
22
  import { getMorphoMetadata } from "./subservices/getMorphoMetadata.service";
23
23
  import { getRadiantMetadata } from "./subservices/getRadiantMetadata.service";
24
24
  import { getSiloMetadata } from "./subservices/getSiloMetadata.service";
25
- import { getVestMetaData } from "./subservices/getVestMetaData";
25
+ import { getVestMetaData } from "./subservices/getVestMetaData.service";
26
26
  export class OpportunityService {
27
27
  static hashId(opportunity) {
28
28
  return Bun.hash(`${opportunity.chainId}${opportunity.type}${opportunity.identifier}`).toString();
@@ -106,7 +106,7 @@ export class RewardConvertorService {
106
106
  const userType = {
107
107
  transactionData: rewardsV4[0].rewards.reduce((acc, reward) => {
108
108
  acc[reward.token.address] = {
109
- claim: (BigInt(reward.amount) - BigInt(reward.claimed)).toString(),
109
+ claim: BigInt(reward.amount).toString(),
110
110
  leaf: reward.proofs?.[0],
111
111
  proof: reward.proofs,
112
112
  token: reward.token.address,
@@ -920,6 +920,31 @@ export declare const v4: Elysia<"/v4", false, {
920
920
  };
921
921
  };
922
922
  };
923
+ } & {
924
+ v4: {
925
+ explorers: {
926
+ post: {
927
+ body: {
928
+ type: "ETHERSCAN" | "BLOCKSCOUT";
929
+ url: string;
930
+ chainId: number;
931
+ };
932
+ params: {};
933
+ query: unknown;
934
+ headers: {
935
+ authorization: string;
936
+ };
937
+ response: {
938
+ 200: {
939
+ type: import("../../../database/api/.generated").$Enums.ExplorerType;
940
+ url: string;
941
+ id: string;
942
+ chainId: number;
943
+ };
944
+ };
945
+ };
946
+ };
947
+ };
923
948
  } & {
924
949
  v4: {
925
950
  tokens: {
@@ -18,6 +18,7 @@ import Elysia from "elysia";
18
18
  import { BoostController } from "./boost";
19
19
  import { ClaimController } from "./claims";
20
20
  import { DynamicDataController } from "./dynamicData";
21
+ import { ExplorerController } from "./explorer/explorer.controller";
21
22
  import { InteractionController } from "./interaction/interaction.controller";
22
23
  import { LiquidityController } from "./liquidity/liquidity.controller";
23
24
  import { MerklRootController } from "./merklRoot";
@@ -51,6 +52,7 @@ export const v4 = new Elysia({ tags: ["v4"], prefix: "/v4" })
51
52
  .use(OpportunityController)
52
53
  .use(CampaignController)
53
54
  .use(ProtocolController)
55
+ .use(ExplorerController)
54
56
  .use(TokenController)
55
57
  .use(RewardController)
56
58
  .use(ChainController)