@merkl/api 0.20.31 → 0.20.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.
@@ -54,7 +54,6 @@ async function computeUniV4PoolTVLFromMostRecentStateSave(chainId, poolID, price
54
54
  catch {
55
55
  log.warn(`merklDynamic data - failed to decode state of pool ${poolID} on ${NETWORK_LABELS[chainId]}`);
56
56
  }
57
- console.log("debug tvl", chainId, poolID, amount0, amount1, tvl);
58
57
  return { tvl, amount0, amount1, blockNumber: blockNumber };
59
58
  }
60
59
  export class UniswapV4DynamicData {
@@ -243,7 +242,8 @@ export class UniswapV4DynamicData {
243
242
  sqrtPrice,
244
243
  tick: tick,
245
244
  priceRewardToken: priceRewardToken,
246
- tvl: poolBalanceToken0 * priceToken0 + poolBalanceToken1 * priceToken1,
245
+ tvl: (!!priceToken0 ? poolBalanceToken0 * priceToken0 : 0) +
246
+ (!!priceToken1 ? poolBalanceToken1 * priceToken1 : 0),
247
247
  });
248
248
  }
249
249
  }
@@ -2,8 +2,9 @@ import { protocolIdList } from "@/modules/v4/protocol/protocol.model";
2
2
  import { ProtocolService } from "@/modules/v4/protocol/protocol.service";
3
3
  import { camelToKebabCase } from "@/utils/caseChanges";
4
4
  import { log } from "@/utils/logger";
5
+ import { sanitizeChainName } from "@/utils/sanitizeChain";
5
6
  import { OpportunityAction } from "@db/api";
6
- import { AMM, ChainId, NETWORK_LABELS, almName, ammName, } from "@sdk";
7
+ import { AMM, ChainId, almName, ammName, } from "@sdk";
7
8
  import { getAddress } from "viem";
8
9
  export const uniswapV3OkuChains = {
9
10
  [ChainId.BLAST]: "blast",
@@ -110,20 +111,18 @@ export class ClammMetadata {
110
111
  };
111
112
  }
112
113
  static generateUrl(computeChainId, params) {
113
- const sanitizeChain = (computeChain) => NETWORK_LABELS[computeChain]?.toLowerCase().replaceAll(" ", "");
114
114
  const sanitizeFee = (poolFee) => Number(poolFee) * 10000;
115
115
  const ammLinkMap = {
116
116
  UniswapV3: ({ poolAddress }) => {
117
117
  const availableOnOku = Object.keys(uniswapV3OkuChains).includes(computeChainId?.toString());
118
118
  if (availableOnOku)
119
119
  return `https://oku.trade/app/${uniswapV3OkuChains[computeChainId]}/liquidity/${params.poolAddress} `;
120
- const chainLabel = computeChainId === ChainId.MAINNET ? "ethereum/" : `${sanitizeChain(computeChainId)}/`;
121
- return `https://app.uniswap.org/explore/pools/${chainLabel}${poolAddress?.toLowerCase()}`;
120
+ return `https://app.uniswap.org/explore/pools/${sanitizeChainName(computeChainId)}/${poolAddress?.toLowerCase()}`;
122
121
  },
123
122
  //Pool address mappings
124
123
  Sonex: ({ poolAddress }) => `https://app.sonex.so/explore/pools/${poolAddress}`,
125
124
  KYO: ({ poolAddress }) => `https://app.kyo.finance/liquidity/${poolAddress}`,
126
- SushiSwapV3: ({ poolAddress }) => `https://www.sushi.com/${sushiswapv3Chains[computeChainId] ?? sanitizeChain(computeChainId)}/pool/v3/${poolAddress}`,
125
+ SushiSwapV3: ({ poolAddress }) => `https://www.sushi.com/${sushiswapv3Chains[computeChainId] ?? sanitizeChainName(computeChainId)}/pool/v3/${poolAddress}`,
127
126
  Swapr: ({ poolAddress }) => `https://v3.swapr.eth.limo/#/info/pools/${poolAddress}`,
128
127
  Crust: ({ poolAddress }) => `https://v1.crust.finance/liquidity/${poolAddress}`,
129
128
  ThirdTrade: ({ poolAddress }) => `https://third.trade/pool/${poolAddress}`,
@@ -139,12 +138,12 @@ export class ClammMetadata {
139
138
  zkSwap: ({ token0, token1 }) => `https://www.zkswap.finance/add/${token0}/${token1}/2000?chain=${computeChainId}`,
140
139
  Velodrome: ({ token0, token1 }) => `https://velodrome.finance/pools?token0=${token0}&token1=${token1}&type=1&chain=${computeChainId}`,
141
140
  //Token address and pool fess
142
- PancakeSwapV3: ({ token0, token1, poolFee }) => `https://pancakeswap.finance/add/${token0}/${token1}/${sanitizeFee(poolFee)}?chain=${pancakeswapChains[computeChainId] ?? sanitizeChain(computeChainId)}`,
141
+ PancakeSwapV3: ({ token0, token1, poolFee }) => `https://pancakeswap.finance/add/${token0}/${token1}/${sanitizeFee(poolFee)}?chain=${pancakeswapChains[computeChainId] ?? sanitizeChainName(computeChainId)}`,
143
142
  BaseSwap: ({ token0, token1, poolFee }) => `https://${computeChainId === ChainId.MODE ? "swapmode" : "baseswap"}.fi/addV3?currencyIdA=${token0}&currencyIdB=${token1}&feeAmount=${sanitizeFee(poolFee)}`,
144
143
  Voltage: ({ token0, token1, poolFee }) => `https://app.voltage.finance/add/${token0}/${token1}?version=v3&feeAmount=${sanitizeFee(poolFee)}`,
145
144
  Izumi: ({ token0, token1, poolFee }) => `https://${computeChainId === ChainId.ROOTSTOCK ? "woodswap.org" : "izumi.finance"}/trade/add-liquidity/?token0=${token0}&token1=${token1}&chainId=${computeChainId}&fee=${Number(poolFee) * 10000}`,
146
145
  SupswapV3: ({ token0, token1, poolFee }) => `https://supswap.xyz/add/${token0}/${token1}/${sanitizeFee(poolFee)}`,
147
- Iguana: ({ token0, token1, poolFee }) => `https://www.iguanadex.com/add/${token0}/${token1}/${sanitizeFee(poolFee)}?chain=${sanitizeChain(computeChainId)}`,
146
+ Iguana: ({ token0, token1, poolFee }) => `https://www.iguanadex.com/add/${token0}/${token1}/${sanitizeFee(poolFee)}?chain=${sanitizeChainName(computeChainId)}`,
148
147
  //Token symbols
149
148
  Stryke: ({ symbolToken0, symbolToken1 }) => `https://www.stryke.xyz/en/trade/arbitrum/${symbolToken0}-${symbolToken1}`,
150
149
  StrykePCS: ({ symbolToken0, symbolToken1 }) => `https://pancakeswap.stryke.xyz/${symbolToken0}-${symbolToken1}?mode=LP`,
@@ -1,4 +1,4 @@
1
- import { Campaign as CampaignEnum, type CampaignParameters, type ChainId } from "@sdk";
1
+ import { type CampaignDynamicData, Campaign as CampaignEnum, type CampaignParameters, type ChainId } from "@sdk";
2
2
  import type { MetadataBuilder } from "../interface";
3
3
  type campaignType = CampaignEnum.ERC20;
4
4
  export declare class Erc20Metadata implements MetadataBuilder<campaignType> {
@@ -13,6 +13,6 @@ export declare class Erc20Metadata implements MetadataBuilder<campaignType> {
13
13
  depositUrl: any;
14
14
  explorerAddress: `0x${string}`;
15
15
  }>;
16
- static generateUrl(_computeChainId: ChainId, params: CampaignParameters<campaignType>["campaignParameters"]): any;
16
+ static generateUrl(_computeChainId: ChainId, params: CampaignParameters<campaignType>["campaignParameters"], dynamicData: CampaignDynamicData<campaignType>): any;
17
17
  }
18
18
  export {};
@@ -1,6 +1,6 @@
1
1
  import { dynamicDataBuilderFactory } from "@/engine/dynamicData/factory";
2
2
  import { log } from "@/utils/logger";
3
- import { Campaign as CampaignEnum } from "@sdk";
3
+ import { Campaign as CampaignEnum, } from "@sdk";
4
4
  import { getAddress } from "viem";
5
5
  import { ProtocolService } from "../../../modules/v4/protocol/protocol.service";
6
6
  export class Erc20Metadata {
@@ -9,6 +9,7 @@ export class Erc20Metadata {
9
9
  let name = `Hold ${params.symbolTargetToken}`;
10
10
  let mainProtocolId = undefined;
11
11
  const tokens = [{ chainId: computeChainId, address: params.targetToken }];
12
+ let depositUrl = params.url;
12
13
  try {
13
14
  const [dynamicData] = await dynamicDataBuilderFactory(CampaignEnum.ERC20).build(computeChainId, [
14
15
  {
@@ -31,6 +32,10 @@ export class Erc20Metadata {
31
32
  if (!!dynamicData && !!dynamicData.typeInfo?.underlying) {
32
33
  tokens.push({ chainId: computeChainId, address: dynamicData.typeInfo.underlying });
33
34
  }
35
+ // 2nd case of lending protocols and receipt tokens
36
+ if (!!dynamicData && !!dynamicData.typeInfo?.underlyingToken) {
37
+ tokens.push({ chainId: computeChainId, address: dynamicData.typeInfo.underlyingToken });
38
+ }
34
39
  // Case of perps protocols
35
40
  if (!!dynamicData && !!dynamicData.typeInfo?.shortToken && !!dynamicData.typeInfo?.longToken) {
36
41
  tokens.push({ chainId: computeChainId, address: dynamicData.typeInfo.shortToken });
@@ -60,6 +65,7 @@ export class Erc20Metadata {
60
65
  tokens.push({ chainId: computeChainId, address: dynamicData.typeInfo.token1Address });
61
66
  tokens.push({ chainId: computeChainId, address: dynamicData.typeInfo.token2Address });
62
67
  }
68
+ depositUrl = Erc20Metadata.generateUrl(computeChainId, params, dynamicData);
63
69
  }
64
70
  catch {
65
71
  log.warn(`failed to fetch dynamic data for ERC20 campaign ${campaignId}`);
@@ -72,11 +78,15 @@ export class Erc20Metadata {
72
78
  name,
73
79
  tokens,
74
80
  mainProtocol: mainProtocolId,
75
- depositUrl: Erc20Metadata.generateUrl(computeChainId, params),
81
+ depositUrl,
76
82
  explorerAddress: getAddress(params.targetToken),
77
83
  };
78
84
  }
79
- static generateUrl(_computeChainId, params) {
85
+ static generateUrl(_computeChainId, params, dynamicData) {
86
+ const erc20type = dynamicData.typeInfo?.type;
87
+ if (erc20type === "gearbox") {
88
+ return `https://app.gearbox.fi/pools/${params.targetToken}`;
89
+ }
80
90
  return params.url;
81
91
  }
82
92
  }
@@ -14,6 +14,6 @@ export declare class EulerMetadata implements MetadataBuilder<campaignType> {
14
14
  depositUrl: string;
15
15
  explorerAddress: `0x${string}`;
16
16
  }>;
17
- static generateUrl(_computeChainId: ChainId, params: CampaignParameters<campaignType>["campaignParameters"]): string;
17
+ static generateUrl(computeChainId: ChainId, params: CampaignParameters<campaignType>["campaignParameters"]): string;
18
18
  }
19
19
  export {};
@@ -1,5 +1,6 @@
1
1
  import { dynamicDataBuilderFactory } from "@/engine/dynamicData/factory";
2
2
  import { log } from "@/utils/logger";
3
+ import { sanitizeChainName } from "@/utils/sanitizeChain";
3
4
  import { OpportunityAction } from "@db/api";
4
5
  import { Campaign as CampaignEnum } from "@sdk";
5
6
  import { getAddress } from "viem";
@@ -34,7 +35,7 @@ export class EulerMetadata {
34
35
  explorerAddress: getAddress(params.targetToken),
35
36
  };
36
37
  }
37
- static generateUrl(_computeChainId, params) {
38
- return `https://app.euler.finance/vault/${params.evkAddress}`;
38
+ static generateUrl(computeChainId, params) {
39
+ return `https://app.euler.finance/vault/${params.evkAddress}?network=${sanitizeChainName(computeChainId)}`;
39
40
  }
40
41
  }
@@ -1,5 +1,5 @@
1
1
  import type { ProtocolId } from "@/modules/v4/protocol/protocol.model";
2
- import { type Campaign as CampaignEnum, type CampaignParameters, ChainId } from "@sdk";
2
+ import type { Campaign as CampaignEnum, CampaignParameters, ChainId } from "@sdk";
3
3
  import type { MetadataBuilder } from "../interface";
4
4
  type campaignType = CampaignEnum.UNISWAP_V4;
5
5
  export declare class UniswapV4Metadata implements MetadataBuilder<campaignType> {
@@ -1,5 +1,5 @@
1
+ import { sanitizeChainName } from "@/utils/sanitizeChain";
1
2
  import { OpportunityAction } from "@db/api";
2
- import { ChainId, NETWORK_LABELS } from "@sdk";
3
3
  import { getAddress } from "viem";
4
4
  export class UniswapV4Metadata {
5
5
  async build(computeChainId, params, _subType) {
@@ -30,8 +30,6 @@ export class UniswapV4Metadata {
30
30
  };
31
31
  }
32
32
  static generateUrl(computeChainId, params) {
33
- const sanitizeChain = (computeChain) => NETWORK_LABELS[computeChain]?.toLowerCase().replaceAll(" ", "");
34
- const chainLabel = computeChainId === ChainId.MAINNET ? "ethereum/" : `${sanitizeChain(computeChainId)}/`;
35
- return `https://app.uniswap.org/explore/pools/${chainLabel}${params.poolId}`;
33
+ return `https://app.uniswap.org/explore/pools/${sanitizeChainName(computeChainId)}/${params.poolId}`;
36
34
  }
37
35
  }
@@ -63,7 +63,7 @@ export const CampaignController = new Elysia({ prefix: "/campaigns", detail: { t
63
63
  throw new NotFoundError();
64
64
  const campaign = await CampaignService.findUniqueOrThrow(id, true);
65
65
  const campaignV3 = OpportunityConvertorService.convertV4CampaignToV3(Campaign[campaign.type], CampaignService.format(campaign), campaign.Opportunity.identifier);
66
- return await DynamicDataService.updateForCampaigns([campaignV3], true);
66
+ return await DynamicDataService.updateForCampaignType([campaignV3], campaignV3.campaignType, true);
67
67
  }, { beforeHandle: BackOfficeGuard, headers: AuthorizationHeadersDto, detail: { hide: true } })
68
68
  // ─── Test Dynamic data computation with a list of campaignId ───────────────────────
69
69
  .post("/dynamic-data", async ({ body }) => {
@@ -0,0 +1,2 @@
1
+ import { ChainId } from "@sdk";
2
+ export declare const sanitizeChainName: (computeChainId: ChainId) => any;
@@ -0,0 +1,6 @@
1
+ import { ChainId, NETWORK_LABELS } from "@sdk";
2
+ export const sanitizeChainName = (computeChainId) => {
3
+ return computeChainId === ChainId.MAINNET
4
+ ? "ethereum"
5
+ : NETWORK_LABELS[computeChainId]?.toLowerCase().replaceAll(" ", "");
6
+ };