@merkl/api 0.11.3 → 0.12.0

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 (44) hide show
  1. package/dist/database/api/.generated/drizzle/schema.d.ts +5 -5
  2. package/dist/database/api/.generated/drizzle/schema.js +1 -1
  3. package/dist/database/api/.generated/drizzle/schema.ts +1 -1
  4. package/dist/database/api/.generated/edge.js +5 -4
  5. package/dist/database/api/.generated/index-browser.js +2 -1
  6. package/dist/database/api/.generated/index.d.ts +2 -1
  7. package/dist/database/api/.generated/index.js +5 -4
  8. package/dist/database/api/.generated/package.json +1 -1
  9. package/dist/database/api/.generated/schema.prisma +1 -0
  10. package/dist/database/api/.generated/wasm.js +2 -1
  11. package/dist/src/eden/index.d.ts +35 -35
  12. package/dist/src/entities/opportunity.js +30 -0
  13. package/dist/src/index.d.ts +7 -7
  14. package/dist/src/libs/campaigns/campaignTypes/AmbientDynamicData.d.ts +3 -0
  15. package/dist/src/libs/campaigns/campaignTypes/AmbientDynamicData.js +243 -0
  16. package/dist/src/libs/campaigns/campaignTypes/ERC20SubTypes/helpers/tokenType.d.ts +2 -1
  17. package/dist/src/libs/campaigns/campaignTypes/ERC20SubTypes/helpers/tokenType.js +2 -0
  18. package/dist/src/libs/campaigns/campaignTypes/ERC20SubTypes/processor/EqualizerGaugeProcessor.d.ts +28 -0
  19. package/dist/src/libs/campaigns/campaignTypes/ERC20SubTypes/processor/EqualizerGaugeProcessor.js +28 -0
  20. package/dist/src/libs/campaigns/campaignTypes/ERC20SubTypes/processor/processorMapping.js +2 -0
  21. package/dist/src/libs/campaigns/campaignTypes/ERC20SubTypes/subtypesRound1.js +2 -0
  22. package/dist/src/libs/campaigns/campaignsDynamicData.js +4 -0
  23. package/dist/src/libs/campaigns/utils/fetchAmbientInfo.d.ts +12 -0
  24. package/dist/src/libs/campaigns/utils/fetchAmbientInfo.js +59 -0
  25. package/dist/src/modules/v4/campaign/campaign.controller.d.ts +2 -2
  26. package/dist/src/modules/v4/campaign/campaign.model.d.ts +2 -0
  27. package/dist/src/modules/v4/campaign/campaign.model.js +1 -0
  28. package/dist/src/modules/v4/campaign/campaign.repository.d.ts +1 -1
  29. package/dist/src/modules/v4/dynamicData/dynamicData.controller.d.ts +2 -2
  30. package/dist/src/modules/v4/dynamicData/dynamicData.model.d.ts +2 -0
  31. package/dist/src/modules/v4/dynamicData/dynamicData.service.js +4 -0
  32. package/dist/src/modules/v4/opportunity/opportunity.controller.d.ts +3 -3
  33. package/dist/src/modules/v4/opportunity/opportunity.model.d.ts +1 -0
  34. package/dist/src/modules/v4/opportunity/opportunity.service.d.ts +4 -4
  35. package/dist/src/modules/v4/opportunity/opportunity.service.js +3 -0
  36. package/dist/src/modules/v4/opportunity/subservices/getAmbientMetadata.service.d.ts +3 -0
  37. package/dist/src/modules/v4/opportunity/subservices/getAmbientMetadata.service.js +29 -0
  38. package/dist/src/modules/v4/protocol/protocol.model.d.ts +1 -1
  39. package/dist/src/modules/v4/protocol/protocol.model.js +1 -0
  40. package/dist/src/modules/v4/router.d.ts +7 -7
  41. package/dist/src/utils/generateCardName.d.ts +1 -1
  42. package/dist/src/utils/generateCardName.js +5 -3
  43. package/dist/tsconfig.package.tsbuildinfo +1 -1
  44. package/package.json +1 -1
@@ -0,0 +1,243 @@
1
+ import { AmbientAddresses, AmbientLens, BN2Number, EAprBreakdownType, NETWORK_LABELS, YEAR, } from "@sdk";
2
+ import moment from "moment";
3
+ import { log } from "../../../utils/logger";
4
+ import { Pricer } from "../../../utils/pricer";
5
+ import { fetchAmbientPotentialPositions } from "../utils/fetchAmbientInfo";
6
+ var AmbientPositionType;
7
+ (function (AmbientPositionType) {
8
+ AmbientPositionType["Concentrated"] = "concentrated";
9
+ AmbientPositionType["Ambient"] = "ambient";
10
+ AmbientPositionType["Knockout"] = "knockout";
11
+ })(AmbientPositionType || (AmbientPositionType = {}));
12
+ function encodeCall(chainId, holder) {
13
+ if (holder.positionType === AmbientPositionType.Concentrated) {
14
+ return [
15
+ {
16
+ allowFailure: true,
17
+ callData: AmbientLens.encodeFunctionData("queryRangeTokens", [
18
+ holder.owner,
19
+ holder.base,
20
+ holder.quote,
21
+ holder.poolIdx,
22
+ holder.lowerTick,
23
+ holder.upperTick,
24
+ ]),
25
+ target: AmbientAddresses[chainId].CrocQuery,
26
+ },
27
+ ];
28
+ }
29
+ return [
30
+ {
31
+ allowFailure: true,
32
+ callData: AmbientLens.encodeFunctionData("queryAmbientTokens", [
33
+ holder.owner,
34
+ holder.base,
35
+ holder.quote,
36
+ holder.poolIdx,
37
+ ]),
38
+ target: AmbientAddresses[chainId].CrocQuery,
39
+ },
40
+ ];
41
+ }
42
+ async function decodeCall(result, holder) {
43
+ let amount0 = BigInt(0n);
44
+ let amount1 = BigInt(0n);
45
+ if (holder.positionType === AmbientPositionType.Concentrated) {
46
+ const resTok = AmbientLens.decodeFunctionResult("queryRangeTokens", result);
47
+ amount0 = BigInt(resTok[1]);
48
+ amount1 = BigInt(resTok[2]);
49
+ }
50
+ if (holder.positionType === AmbientPositionType.Ambient) {
51
+ const resTok = AmbientLens.decodeFunctionResult("queryAmbientTokens", result);
52
+ amount0 = BigInt(resTok[1]);
53
+ amount1 = BigInt(resTok[2]);
54
+ }
55
+ return { amount0, amount1 };
56
+ }
57
+ export async function AmbientDynamicData(chainId, campaigns) {
58
+ const dynamicData = [];
59
+ const pricer = await Pricer.load();
60
+ let calls = [];
61
+ /** Dedupe pools from campaigns to build pool list */
62
+ const poolList = [];
63
+ for (const campaign of campaigns ?? []) {
64
+ /** Loop through all campaigns to add pools */
65
+ if (!poolList?.map(p => p.mainParameter.toLowerCase()).includes(campaign.mainParameter.toLowerCase())) {
66
+ poolList.push({
67
+ id: campaign.campaignParameters.poolId,
68
+ mainParameter: campaign.mainParameter, // main parameter containes info of poolAddress + AMM (in case its a priority AMM)
69
+ baseToken: campaign.campaignParameters.baseToken,
70
+ quoteToken: campaign.campaignParameters.quoteToken,
71
+ poolIdx: campaign.campaignParameters.poolIdx,
72
+ potentialHolders: await fetchAmbientPotentialPositions(campaign.campaignParameters.poolId, campaign.chainId),
73
+ });
74
+ }
75
+ }
76
+ if (!!poolList) {
77
+ for (const pool of poolList) {
78
+ calls.push({
79
+ allowFailure: true,
80
+ callData: AmbientLens.encodeFunctionData("queryLiquidity", [pool.baseToken, pool.quoteToken, pool.poolIdx]),
81
+ target: AmbientAddresses[chainId].CrocQuery,
82
+ }, {
83
+ allowFailure: true,
84
+ callData: AmbientLens.encodeFunctionData("queryCurveTick", [pool.baseToken, pool.quoteToken, pool.poolIdx]),
85
+ target: AmbientAddresses[chainId].CrocQuery,
86
+ });
87
+ calls = calls.concat(...pool.potentialHolders.map(holder => encodeCall(chainId, holder)));
88
+ }
89
+ return {
90
+ cached: false,
91
+ call: {
92
+ callData: calls,
93
+ handler: () => { },
94
+ reducer: async (result) => {
95
+ let i = 0;
96
+ if (!!poolList) {
97
+ for (const pool of poolList) {
98
+ // This liquidity call gives the active liquidity on the pool. To get the total liquidity we would need to loop over all positions
99
+ let poolTotalLiquidity;
100
+ let activeTick;
101
+ let poolBalanceToken0 = 0;
102
+ let poolBalanceToken1 = 0;
103
+ const d = campaigns?.filter(campaign => campaign.mainParameter.toLowerCase() === pool.mainParameter.toLowerCase())[0];
104
+ const decimalsBaseToken = d.campaignParameters.decimalsBaseToken;
105
+ const decimalsQuoteToken = d.campaignParameters.decimalsQuoteToken;
106
+ const symbolBaseToken = d.campaignParameters.symbolBaseToken;
107
+ const symbolQuoteToken = d.campaignParameters.symbolQuoteToken;
108
+ const prevI = i;
109
+ try {
110
+ poolTotalLiquidity = BN2Number(AmbientLens.decodeFunctionResult("queryLiquidity", result[i++])[0]);
111
+ activeTick = Number(AmbientLens.decodeFunctionResult("queryCurveTick", result[i++])[0]);
112
+ for (let index = 0; index < pool.potentialHolders.length; index++) {
113
+ // to verify
114
+ if (calls.length === 0) {
115
+ break;
116
+ }
117
+ const res = await decodeCall(result[i++], pool.potentialHolders[index]);
118
+ poolBalanceToken0 += BN2Number(res.amount0, decimalsBaseToken);
119
+ poolBalanceToken1 += BN2Number(res.amount1, decimalsQuoteToken);
120
+ }
121
+ }
122
+ catch (e) {
123
+ log.warn(`merklDynamic data - failed to decode state of pool ${pool.id} on ${NETWORK_LABELS[chainId]}`);
124
+ i = prevI + 2 + pool.potentialHolders.length;
125
+ continue;
126
+ }
127
+ const priceToken0 = (await pricer.get({
128
+ address: d.campaignParameters.baseToken,
129
+ chainId: chainId,
130
+ symbol: symbolBaseToken,
131
+ })) ?? 2800;
132
+ const priceToken1 = (await pricer.get({
133
+ address: d.campaignParameters.quoteToken,
134
+ chainId: chainId,
135
+ symbol: symbolQuoteToken,
136
+ }));
137
+ /** Iterate over distributions to compute APRs */
138
+ for (const campaign of campaigns.filter(campaign => campaign.mainParameter.toLowerCase() === pool.mainParameter.toLowerCase())) {
139
+ const c = campaign;
140
+ const amount = BN2Number(c.amount, c.campaignParameters.decimalsRewardToken);
141
+ const startTimestamp = BN2Number(c.startTimestamp, 0);
142
+ const endTimestamp = BN2Number(c.endTimestamp, 0);
143
+ const isLive = moment().unix() >= startTimestamp && moment().unix() < endTimestamp;
144
+ const totalWeight = BN2Number(c.campaignParameters.weightFees, 4) +
145
+ BN2Number(c.campaignParameters.weightToken0, 4) +
146
+ BN2Number(c.campaignParameters.weightToken1, 4);
147
+ // Proportions in percentage
148
+ const propFees = (BN2Number(c.campaignParameters.weightFees, 4) / totalWeight) * 100;
149
+ const propToken0 = (BN2Number(c.campaignParameters.weightToken0, 4) / totalWeight) * 100;
150
+ const propToken1 = (BN2Number(c.campaignParameters.weightToken1, 4) / totalWeight) * 100;
151
+ let distributionMeanAPR = 0;
152
+ const aprs = {};
153
+ const aprBreakdowns = [];
154
+ let priceRewardToken = 0;
155
+ if (isLive && c.campaignParameters.symbolRewardToken !== "aglaMerkl") {
156
+ priceRewardToken = (await pricer.get({
157
+ address: c.rewardToken,
158
+ chainId: chainId,
159
+ symbol: c.campaignParameters.symbolRewardToken,
160
+ }));
161
+ /** Yearly rewards in $ */
162
+ const yearlyToken0Rewards = (propToken0 * priceRewardToken * amount * YEAR) / (endTimestamp - startTimestamp);
163
+ const yearlyToken1Rewards = (propToken1 * priceRewardToken * amount * YEAR) / (endTimestamp - startTimestamp);
164
+ const yearlyFeeRewards = (propFees * priceRewardToken * amount * YEAR) / (endTimestamp - startTimestamp);
165
+ let poolAPRkey = "";
166
+ const tvl = poolBalanceToken0 * priceToken0 + poolBalanceToken1 * priceToken1;
167
+ distributionMeanAPR = (yearlyToken0Rewards + yearlyToken1Rewards + yearlyFeeRewards) / tvl;
168
+ distributionMeanAPR =
169
+ !distributionMeanAPR || Number.isNaN(distributionMeanAPR) ? 0 : distributionMeanAPR;
170
+ /**
171
+ * @dev We cannot include a whitelisted distrib apr into the mean APR
172
+ */
173
+ if (c.campaignParameters.whitelist.length === 0) {
174
+ poolAPRkey = "Average APR (rewards / pool TVL)";
175
+ if (!aprs[poolAPRkey])
176
+ aprs[poolAPRkey] = 0;
177
+ aprs[poolAPRkey] += distributionMeanAPR;
178
+ // @Hugo wip: new way to structure aprBreakdowns
179
+ aprBreakdowns.push({
180
+ address: pool.id,
181
+ value: distributionMeanAPR,
182
+ type: EAprBreakdownType.AVERAGE,
183
+ label: "Average APR (rewards / pool TVL)",
184
+ });
185
+ // APR per token
186
+ poolAPRkey = `APR for holding ${c.campaignParameters.symbolBaseToken} in pool`;
187
+ if (!aprs[poolAPRkey])
188
+ aprs[poolAPRkey] = 0;
189
+ aprs[poolAPRkey] += yearlyToken0Rewards / (poolBalanceToken0 * priceToken0);
190
+ // @Hugo wip: new way to structure aprBreakdowns
191
+ aprBreakdowns.push({
192
+ address: pool.id,
193
+ value: yearlyToken0Rewards / (poolBalanceToken0 * priceToken0),
194
+ type: EAprBreakdownType.TOKEN1,
195
+ label: c.campaignParameters.symbolBaseToken,
196
+ });
197
+ poolAPRkey = `APR for holding ${c.campaignParameters.symbolQuoteToken} in pool`;
198
+ if (!aprs[poolAPRkey])
199
+ aprs[poolAPRkey] = 0;
200
+ aprs[poolAPRkey] += yearlyToken1Rewards / (poolBalanceToken1 * priceToken1);
201
+ // @Hugo wip: new way to structure aprBreakdowns
202
+ aprBreakdowns.push({
203
+ address: pool.id,
204
+ value: yearlyToken1Rewards / (poolBalanceToken1 * priceToken1),
205
+ type: EAprBreakdownType.TOKEN2,
206
+ label: c.campaignParameters.symbolQuoteToken,
207
+ });
208
+ }
209
+ else {
210
+ }
211
+ }
212
+ dynamicData.push({
213
+ ...campaign,
214
+ apr: distributionMeanAPR,
215
+ aprs,
216
+ forwarders: [],
217
+ poolBalanceToken0,
218
+ poolBalanceToken1,
219
+ poolTotalLiquidity,
220
+ tick: activeTick,
221
+ priceRewardToken: priceRewardToken,
222
+ tvl: poolBalanceToken0 * priceToken0 + poolBalanceToken1 * priceToken1,
223
+ });
224
+ }
225
+ }
226
+ }
227
+ return dynamicData;
228
+ },
229
+ },
230
+ };
231
+ }
232
+ // Fallback in case something fails
233
+ return {
234
+ cached: false,
235
+ call: {
236
+ callData: [],
237
+ handler: () => { },
238
+ reducer: async (_result) => {
239
+ return campaigns;
240
+ },
241
+ },
242
+ };
243
+ }
@@ -78,7 +78,8 @@ export declare enum tokenType {
78
78
  lendle_borrowing = "lendle_borrowing",
79
79
  lendle_lending = "lendle_lending",
80
80
  takotako_borrowing = "takotako_borrowing",
81
- takotako_lending = "takotako_lending"
81
+ takotako_lending = "takotako_lending",
82
+ equalizer_gauge = "equalizer_gauge"
82
83
  }
83
84
  export declare const tokenTypeToProtocol: {
84
85
  [key in tokenType]: {
@@ -80,6 +80,7 @@ export var tokenType;
80
80
  tokenType["lendle_lending"] = "lendle_lending";
81
81
  tokenType["takotako_borrowing"] = "takotako_borrowing";
82
82
  tokenType["takotako_lending"] = "takotako_lending";
83
+ tokenType["equalizer_gauge"] = "equalizer_gauge";
83
84
  })(tokenType || (tokenType = {}));
84
85
  export const tokenTypeToProtocol = {
85
86
  [tokenType.aave_borrowing]: { protocol: "Aave" },
@@ -191,4 +192,5 @@ export const tokenTypeToProtocol = {
191
192
  [tokenType.lendle_lending]: { protocol: "Lendle" },
192
193
  [tokenType.takotako_borrowing]: { protocol: "TakoTako" },
193
194
  [tokenType.takotako_lending]: { protocol: "TakoTako" },
195
+ [tokenType.equalizer_gauge]: { protocol: "Equalizer" },
194
196
  };
@@ -0,0 +1,28 @@
1
+ import type { Pricer } from "../../../../../utils/pricer";
2
+ import type { Campaign, CampaignParameters } from "@sdk";
3
+ import type { tokenType } from "../helpers/tokenType";
4
+ import { GenericProcessor, type dataType, type mandatoryCallKeys } from "./GenericProcessor";
5
+ type callType = {
6
+ key: keyof dataRawEqualizerGauge;
7
+ call: string;
8
+ target: keyof callKeysEqualizerGauge;
9
+ metaData?: any;
10
+ };
11
+ type callKeysEqualizerGauge = mandatoryCallKeys & {
12
+ tokenPrice: string;
13
+ name: string;
14
+ };
15
+ type dataRawEqualizerGauge = callKeysEqualizerGauge & {};
16
+ type dataTypeEqualizerGauge = dataType & {
17
+ tokenPrice: string;
18
+ };
19
+ export declare class EqualizerGaugeProcessor extends GenericProcessor<callKeysEqualizerGauge, dataRawEqualizerGauge, dataTypeEqualizerGauge> {
20
+ rounds: {
21
+ round1: callType[];
22
+ round2: callType[];
23
+ round3: callType[];
24
+ round4: callType[];
25
+ };
26
+ processingRound5(_index: number, type: tokenType, typeInfo: dataRawEqualizerGauge, _calls: string[], campaign: CampaignParameters<Campaign.ERC20>, _pricer: Pricer): Promise<dataTypeEqualizerGauge>;
27
+ }
28
+ export {};
@@ -0,0 +1,28 @@
1
+ import { generateCardName } from "../../../../../utils/generateCardName";
2
+ import axios from "axios";
3
+ import { GenericProcessor } from "./GenericProcessor";
4
+ export class EqualizerGaugeProcessor extends GenericProcessor {
5
+ rounds = {
6
+ round1: [],
7
+ round2: [],
8
+ round3: [],
9
+ round4: [{ key: "totalSupply", call: "totalSupply", target: "tokenAddress" }],
10
+ };
11
+ async processingRound5(_index, type, typeInfo, _calls, campaign, _pricer) {
12
+ const { whitelistedSupplyTargetToken, totalSupply, blacklistedSupply } = this.handleWhiteListBlacklistRound5(typeInfo, campaign);
13
+ const EXTERNAL_EQUALIZER_ENDPOINT = "https://eqapi-sonic-prod-ltanm.ondigitalocean.app/sonic/v4/gauges/";
14
+ const data = (await axios(EXTERNAL_EQUALIZER_ENDPOINT)).data.data;
15
+ const tvl = data[typeInfo.tokenAddress].token0.reserveUsd + data[typeInfo.tokenAddress].token1.reserveUsd;
16
+ const priceTargetToken = tvl / totalSupply;
17
+ const displayName = `Stake into ${data[typeInfo.tokenAddress].pair.displayName} Equalizer Gauge`;
18
+ return {
19
+ ...typeInfo,
20
+ totalSupply,
21
+ tvl,
22
+ whitelistedSupplyTargetToken,
23
+ blacklistedSupply,
24
+ priceTargetToken,
25
+ cardName: generateCardName(type, typeInfo, campaign, [], displayName),
26
+ };
27
+ }
28
+ }
@@ -8,6 +8,7 @@ import { BeefyProcessor } from "./BeefyProcessor";
8
8
  import { CompoundProcessor } from "./CompoundProcessor";
9
9
  import { ERC4626Processor } from "./ERC4626Processor";
10
10
  import { EnzymeProcessor } from "./EnzymeProcessor";
11
+ import { EqualizerGaugeProcessor } from "./EqualizerGaugeProcessor";
11
12
  import { EulerBorrowProcessor } from "./EulerBorrowProcessor";
12
13
  import { EulerLendProcessor } from "./EulerLendProcessor";
13
14
  import { FluidProcessor } from "./FluidProcessor";
@@ -116,4 +117,5 @@ export const processorMapping = {
116
117
  [tokenType.lendle_lending]: AaveProcessor,
117
118
  [tokenType.takotako_lending]: AaveProcessor,
118
119
  [tokenType.takotako_borrowing]: AaveProcessor,
120
+ [tokenType.equalizer_gauge]: EqualizerGaugeProcessor,
119
121
  };
@@ -132,6 +132,8 @@ function satisfiesNameConditions(name, type) {
132
132
  return lowerCaseName.includes("cian");
133
133
  case tokenType.concrete:
134
134
  return lowerCaseName.includes("concrete");
135
+ case tokenType.equalizer_gauge:
136
+ return lowerCaseName.includes("equalizer");
135
137
  default:
136
138
  return false;
137
139
  }
@@ -1,6 +1,7 @@
1
1
  import { UserService } from "../../modules/v4/user";
2
2
  import { Campaign } from "@sdk";
3
3
  import { AjnaDynamicData } from "./campaignTypes/AjnaDynamicData";
4
+ import { AmbientDynamicData } from "./campaignTypes/AmbientDynamicData";
4
5
  import { BadgerDynamicData } from "./campaignTypes/BadgerDynamicData";
5
6
  import { CLAMMDynamicData } from "./campaignTypes/CLAMMDynamicData";
6
7
  import { CompoundDynamicData } from "./campaignTypes/CompoundDynamicData";
@@ -79,6 +80,9 @@ export async function campaignsDynamicData(chainId, campaigns, type) {
79
80
  case Campaign.HYPERDRIVELOGFIXPROCESSOR: {
80
81
  return HyperdriveDynamicData(chainId, campaigns);
81
82
  }
83
+ case Campaign.AMBIENTPROCESSOR: {
84
+ return AmbientDynamicData(chainId, campaigns);
85
+ }
82
86
  }
83
87
  return {
84
88
  cached: false,
@@ -0,0 +1,12 @@
1
+ import { type ChainId } from "@sdk";
2
+ export type AmbientHolderType = {
3
+ owner: string;
4
+ base: string;
5
+ quote: string;
6
+ poolIdx: number;
7
+ lowerTick: number;
8
+ upperTick: number;
9
+ positionType: string;
10
+ };
11
+ export declare const holdersQuery: string;
12
+ export declare function fetchAmbientPotentialPositions(poolId: string, chainId: ChainId): Promise<AmbientHolderType[]>;
@@ -0,0 +1,59 @@
1
+ import { subgraphAmbientEndpoints, withRetry } from "@sdk";
2
+ import { gql, request } from "graphql-request";
3
+ const BATCH_NUMBER = 1000;
4
+ export const holdersQuery = gql `
5
+ query LiquidityChanges($poolId: String!, $minId: String!) {
6
+ liquidityChanges(
7
+ where: { pool_: { id: $poolId }, id_gt: $minId , positionType_not: "knockout"},
8
+ first: ${BATCH_NUMBER},
9
+ orderBy: pool__id
10
+ ) {
11
+ id
12
+ user
13
+ positionType
14
+ bidTick
15
+ askTick
16
+ pool {
17
+ base
18
+ quote
19
+ poolIdx
20
+ }
21
+ }
22
+ }
23
+ `;
24
+ export async function fetchAmbientPotentialPositions(poolId, chainId) {
25
+ let isFullyFetched = false;
26
+ let holders = [];
27
+ let minId = "";
28
+ while (!isFullyFetched) {
29
+ const data = await withRetry(request, [
30
+ subgraphAmbientEndpoints[chainId],
31
+ holdersQuery,
32
+ {
33
+ poolId: poolId,
34
+ minId: minId,
35
+ },
36
+ ]);
37
+ const fetchedHolders = data.liquidityChanges?.map(entry => {
38
+ return {
39
+ owner: entry.user,
40
+ base: entry.pool.base,
41
+ quote: entry.pool.quote,
42
+ poolIdx: Number(entry.pool.poolIdx),
43
+ lowerTick: Number(entry.bidTick),
44
+ upperTick: Number(entry.askTick),
45
+ positionType: entry.positionType,
46
+ };
47
+ });
48
+ if (fetchedHolders.length < BATCH_NUMBER) {
49
+ isFullyFetched = true;
50
+ }
51
+ else {
52
+ minId = data.liquidityChanges[fetchedHolders.length - 1].id;
53
+ }
54
+ holders = holders.concat(fetchedHolders);
55
+ }
56
+ // Only keep unique positions
57
+ holders = Array.from(new Set(holders.map(h => JSON.stringify(h)))).map(h => JSON.parse(h));
58
+ return holders;
59
+ }
@@ -112,7 +112,7 @@ export declare const CampaignController: Elysia<"/campaigns", false, {
112
112
  body: unknown;
113
113
  params: {};
114
114
  query: {
115
- type?: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR" | undefined;
115
+ type?: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR" | "AMBIENTPROCESSOR" | undefined;
116
116
  items?: number | undefined;
117
117
  subType?: number | undefined;
118
118
  page?: number | undefined;
@@ -186,7 +186,7 @@ export declare const CampaignController: Elysia<"/campaigns", false, {
186
186
  body: unknown;
187
187
  params: {};
188
188
  query: {
189
- type?: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR" | undefined;
189
+ type?: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR" | "AMBIENTPROCESSOR" | undefined;
190
190
  items?: number | undefined;
191
191
  subType?: number | undefined;
192
192
  page?: number | undefined;
@@ -42,6 +42,7 @@ export declare const campaignTypeToEnumMap: {
42
42
  readonly ERC20_FIX_APR: any;
43
43
  readonly HYPERDRIVELOGPROCESSOR: any;
44
44
  readonly HYPERDRIVELOGFIXPROCESSOR: any;
45
+ readonly AMBIENTPROCESSOR: any;
45
46
  };
46
47
  export type ConvertedCampaignType<C extends CampaignType> = (typeof campaignTypeToEnumMap)[C];
47
48
  export declare const CampaignUniqueDto: import("@sinclair/typebox").TObject<{
@@ -149,6 +150,7 @@ export declare const GetCampaignQueryDto: import("@sinclair/typebox").TObject<{
149
150
  ERC20_FIX_APR: "ERC20_FIX_APR";
150
151
  HYPERDRIVELOGPROCESSOR: "HYPERDRIVELOGPROCESSOR";
151
152
  HYPERDRIVELOGFIXPROCESSOR: "HYPERDRIVELOGFIXPROCESSOR";
153
+ AMBIENTPROCESSOR: "AMBIENTPROCESSOR";
152
154
  }>>;
153
155
  subType: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
154
156
  campaignId: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
@@ -29,6 +29,7 @@ export const campaignTypeToEnumMap = {
29
29
  ERC20_FIX_APR: CampaignTypeEnum.ERC20_FIX_APR,
30
30
  HYPERDRIVELOGPROCESSOR: CampaignTypeEnum.HYPERDRIVELOGPROCESSOR,
31
31
  HYPERDRIVELOGFIXPROCESSOR: CampaignTypeEnum.HYPERDRIVELOGFIXPROCESSOR,
32
+ AMBIENTPROCESSOR: CampaignTypeEnum.AMBIENTPROCESSOR,
32
33
  };
33
34
  // ─── DTOs ────────────────────────────────────────────────────────────────────
34
35
  export const CampaignUniqueDto = t.Object({
@@ -17,7 +17,7 @@ export declare abstract class CampaignRepository {
17
17
  gte: number;
18
18
  } | undefined;
19
19
  subType: number | undefined;
20
- type: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR" | undefined;
20
+ type: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR" | "AMBIENTPROCESSOR" | undefined;
21
21
  creatorAddress: string | undefined;
22
22
  RewardToken: {
23
23
  address: string | undefined;
@@ -62,7 +62,7 @@ export declare const DynamicDataController: Elysia<"/dynamic-data", false, {
62
62
  rewardTokenAddress?: string | undefined;
63
63
  distributionChain?: {} | undefined;
64
64
  opportunityIdentifier?: string | undefined;
65
- type: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR";
65
+ type: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR" | "AMBIENTPROCESSOR";
66
66
  params: {};
67
67
  computeChainId: number;
68
68
  };
@@ -84,7 +84,7 @@ export declare const DynamicDataController: Elysia<"/dynamic-data", false, {
84
84
  body: unknown;
85
85
  params: {};
86
86
  query: {
87
- type?: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR" | undefined;
87
+ type?: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR" | "AMBIENTPROCESSOR" | undefined;
88
88
  items?: number | undefined;
89
89
  subType?: number | undefined;
90
90
  page?: number | undefined;
@@ -41,6 +41,7 @@ export declare const SimplifiedCampaignDto: import("@sinclair/typebox").TObject<
41
41
  ERC20_FIX_APR: "ERC20_FIX_APR";
42
42
  HYPERDRIVELOGPROCESSOR: "HYPERDRIVELOGPROCESSOR";
43
43
  HYPERDRIVELOGFIXPROCESSOR: "HYPERDRIVELOGFIXPROCESSOR";
44
+ AMBIENTPROCESSOR: "AMBIENTPROCESSOR";
44
45
  }>;
45
46
  subType: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
46
47
  rewardTokenAddress: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
@@ -89,6 +90,7 @@ export declare const FilledCampaignDto: import("@sinclair/typebox").TObject<{
89
90
  ERC20_FIX_APR: "ERC20_FIX_APR";
90
91
  HYPERDRIVELOGPROCESSOR: "HYPERDRIVELOGPROCESSOR";
91
92
  HYPERDRIVELOGFIXPROCESSOR: "HYPERDRIVELOGFIXPROCESSOR";
93
+ AMBIENTPROCESSOR: "AMBIENTPROCESSOR";
92
94
  }>;
93
95
  subType: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
94
96
  rewardTokenAddress: import("@sinclair/typebox").TString;
@@ -84,6 +84,10 @@ export class DynamicDataService {
84
84
  parsedParams = campaign.params;
85
85
  targetToken = parsedParams.poolAddress;
86
86
  }
87
+ else if (campaign.type === Campaign[Campaign.AMBIENTPROCESSOR]) {
88
+ parsedParams = campaign.params;
89
+ targetToken = parsedParams.poolId;
90
+ }
87
91
  else {
88
92
  parsedParams = campaign.params;
89
93
  targetToken = parsedParams.targetToken;
@@ -21,7 +21,7 @@ export declare const OpportunityController: Elysia<"/opportunities", false, {
21
21
  depositUrl?: string | undefined;
22
22
  protocols?: string[] | undefined;
23
23
  mainProtocol?: string | undefined;
24
- type: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR";
24
+ type: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR" | "AMBIENTPROCESSOR";
25
25
  tokens: {
26
26
  chainId: number;
27
27
  address: string;
@@ -91,7 +91,7 @@ export declare const OpportunityController: Elysia<"/opportunities", false, {
91
91
  } & {
92
92
  price?: number | null | undefined;
93
93
  })[];
94
- mainProtocol: "morpho" | "arthswap" | "baseswap" | "camelot" | "crust" | "fenix" | "horiza" | "izumi" | "kim" | "pancakeswap-v3" | "quickswap-algebra" | "quickswap-uni" | "ramses" | "retro" | "stryke" | "stryke-pcs" | "stryke-sushi" | "sushiswap-v3" | "swapr" | "thruster" | "uniswap-v3" | "voltage" | "zero" | "koi" | "supswap-v3" | "zkswap" | "thirdtrade" | "uniswap-v2" | "velodrome" | "aerodrome" | "balancer" | "curve" | "cross_curve" | "curveNPool" | "aura" | "akron" | "beefy" | "dragonswap" | "poolside" | "syncswap-v3" | "neptune" | "zkSwapThreePool" | "syncswap" | "rfx" | "radiant" | "aave" | "euler" | "gearbox" | "compound" | "sturdy" | "frax" | "ionic" | "moonwell" | "fluid" | "silo" | "coumpound" | "dolomite" | "badger" | "ajna" | "layerbank" | "ion" | "venus" | "woofi" | "reactor_fusion" | "eigenlayer" | "vest" | "zerolend" | "hyperdrive" | undefined;
94
+ mainProtocol: "morpho" | "ambient" | "arthswap" | "baseswap" | "camelot" | "crust" | "fenix" | "horiza" | "izumi" | "kim" | "pancakeswap-v3" | "quickswap-algebra" | "quickswap-uni" | "ramses" | "retro" | "stryke" | "stryke-pcs" | "stryke-sushi" | "sushiswap-v3" | "swapr" | "thruster" | "uniswap-v3" | "voltage" | "zero" | "koi" | "supswap-v3" | "zkswap" | "thirdtrade" | "uniswap-v2" | "velodrome" | "aerodrome" | "balancer" | "curve" | "cross_curve" | "curveNPool" | "aura" | "akron" | "beefy" | "dragonswap" | "poolside" | "syncswap-v3" | "neptune" | "zkSwapThreePool" | "syncswap" | "rfx" | "radiant" | "aave" | "euler" | "gearbox" | "compound" | "sturdy" | "frax" | "ionic" | "moonwell" | "fluid" | "silo" | "coumpound" | "dolomite" | "badger" | "ajna" | "layerbank" | "ion" | "venus" | "woofi" | "reactor_fusion" | "eigenlayer" | "vest" | "zerolend" | "hyperdrive" | undefined;
95
95
  depositUrl: any;
96
96
  tags: string[];
97
97
  };
@@ -362,7 +362,7 @@ export declare const OpportunityController: Elysia<"/opportunities", false, {
362
362
  body: unknown;
363
363
  params: {};
364
364
  query: {
365
- type?: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR" | undefined;
365
+ type?: "INVALID" | "ERC20" | "CLAMM" | "ERC20_SNAPSHOT" | "JSON_AIRDROP" | "SILO" | "RADIANT" | "MORPHO" | "DOLOMITE" | "BADGER" | "COMPOUND" | "AJNA" | "EULER" | "UNISWAP_V4" | "ION" | "EIGENLAYER" | "ERC20TRANSFERS" | "ERC20LOGPROCESSOR" | "ERC20REBASELOGPROCESSOR" | "VEST" | "ERC20_FIX_APR" | "HYPERDRIVELOGPROCESSOR" | "HYPERDRIVELOGFIXPROCESSOR" | "AMBIENTPROCESSOR" | undefined;
366
366
  items?: number | undefined;
367
367
  subType?: number | undefined;
368
368
  page?: number | undefined;
@@ -324,6 +324,7 @@ export declare const CreateOpportunityDto: import("@sinclair/typebox").TObject<{
324
324
  ERC20_FIX_APR: "ERC20_FIX_APR";
325
325
  HYPERDRIVELOGPROCESSOR: "HYPERDRIVELOGPROCESSOR";
326
326
  HYPERDRIVELOGFIXPROCESSOR: "HYPERDRIVELOGFIXPROCESSOR";
327
+ AMBIENTPROCESSOR: "AMBIENTPROCESSOR";
327
328
  }>;
328
329
  identifier: import("@sinclair/typebox").TString;
329
330
  name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;