@merkl/api 0.17.24 → 0.17.26

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.
@@ -0,0 +1,3 @@
1
+ import { type Campaign, type CampaignDynamicData, type CampaignParameters, type MerklChainId } from "@sdk";
2
+ import type { UncachedResult } from "../../../utils/execute";
3
+ export declare function EventBasedDynamicData(chainId: MerklChainId, campaigns: CampaignParameters<Campaign.EVENT_BASED>[]): Promise<UncachedResult<Partial<CampaignDynamicData<Campaign.EVENT_BASED>[]>>>;
@@ -0,0 +1,117 @@
1
+ import { BucketService } from "../../../modules/v4/bucket/bucket.service";
2
+ import { engineDbClient } from "../../../utils/prisma";
3
+ import { BN2Number, ChainInteractionService, NETWORK_LABELS, } from "@sdk";
4
+ import moment from "moment";
5
+ import { log } from "../../../utils/logger";
6
+ import { Pricer } from "../../../utils/pricer";
7
+ // Constants
8
+ const CALLS_LENGTH = 2;
9
+ /**
10
+ * Compute TVL
11
+ * @dev important: using the most recent state save with current prices
12
+ * it's only an estimate
13
+ */
14
+ async function computeEventBasedPoolTVLFromMostRecentStateSave(chainId, campaignID, priceCurrency, decimalsCurrency) {
15
+ let stateSave;
16
+ let blockNumber;
17
+ let states = {};
18
+ try {
19
+ const currentBlock = await ChainInteractionService(chainId).getBlockNumber();
20
+ const mostRecentStateSave = await engineDbClient.stateSave.findFirst({
21
+ where: {
22
+ id: `EventBasedProcessor_${chainId}_${campaignID}`,
23
+ blockNumber: {
24
+ lte: currentBlock,
25
+ },
26
+ },
27
+ orderBy: {
28
+ blockNumber: "desc",
29
+ },
30
+ });
31
+ stateSave = mostRecentStateSave.state;
32
+ blockNumber = mostRecentStateSave?.blockNumber;
33
+ states = stateSave.states;
34
+ // const globalState = stateSave.globalState as { tick: number; liquidity: string };
35
+ }
36
+ catch (e) {
37
+ log.warn(`merklDynamic data - failed to read a recent state of ${campaignID} on ${NETWORK_LABELS[chainId]}`);
38
+ }
39
+ const { fileName, bucketName } = states;
40
+ // Bucket service
41
+ let tvl = 0;
42
+ try {
43
+ const bucket = new BucketService(bucketName, "merkl-production");
44
+ const storedStates = JSON.parse(await bucket.pull(fileName));
45
+ for (const [_, { value, params: _params }] of Object.entries(storedStates)) {
46
+ tvl += priceCurrency * BN2Number(value.allTimeValue, decimalsCurrency);
47
+ }
48
+ }
49
+ catch (e) {
50
+ console.log(e);
51
+ log.warn(`merklDynamic data - failed to decode state of event based on ${NETWORK_LABELS[chainId]}`);
52
+ }
53
+ return { tvl, blockNumber: blockNumber };
54
+ }
55
+ export async function EventBasedDynamicData(chainId, campaigns) {
56
+ const dynamicData = [];
57
+ const pricer = await Pricer.load();
58
+ const calls = [];
59
+ return {
60
+ cached: false,
61
+ call: {
62
+ callData: calls,
63
+ handler: () => { },
64
+ reducer: async (result) => {
65
+ for (const campaign of campaigns) {
66
+ try {
67
+ const decimalsCurrency0 = 6;
68
+ const symbolCurrency0 = "USDC";
69
+ const priceToken = (await pricer.get({
70
+ chainId: chainId,
71
+ symbol: symbolCurrency0,
72
+ }));
73
+ const { tvl, blockNumber } = await computeEventBasedPoolTVLFromMostRecentStateSave(chainId, campaign.campaignId, priceToken, decimalsCurrency0);
74
+ const c = campaign;
75
+ const amount = BN2Number(c.amount, c.campaignParameters.decimalsRewardToken);
76
+ const multiplier = BN2Number(c.campaignParameters.topicToData[0].multiplier, 9);
77
+ const startTimestamp = BN2Number(c.startTimestamp, 0);
78
+ const endTimestamp = BN2Number(c.endTimestamp, 0);
79
+ const isLive = moment().unix() > startTimestamp && moment().unix() < endTimestamp;
80
+ let distributionMeanAPR = 0;
81
+ const priceRewardToken = 1;
82
+ if (isLive && c.campaignParameters.symbolRewardToken !== "aglaMerkl") {
83
+ /**
84
+ * Handle whitelisted/blacklisted addresses to compute APR
85
+ */
86
+ if (c.campaignParameters.whitelist.length > 0) {
87
+ // TODO
88
+ }
89
+ else if (c.campaignParameters.blacklist.length > 0) {
90
+ // TODO
91
+ }
92
+ /** Yearly rewards in $ */
93
+ const yearlyTokenRewards = (multiplier * priceRewardToken * amount * (365 * 24 * 3_600)) / (endTimestamp - startTimestamp);
94
+ distributionMeanAPR = yearlyTokenRewards / tvl;
95
+ distributionMeanAPR = !distributionMeanAPR || Number.isNaN(distributionMeanAPR) ? 0 : distributionMeanAPR;
96
+ dynamicData.push({
97
+ ...campaign,
98
+ apr: distributionMeanAPR,
99
+ priceRewardToken: priceRewardToken,
100
+ tvl: tvl,
101
+ });
102
+ }
103
+ }
104
+ catch (e) {
105
+ dynamicData.push({
106
+ ...campaign,
107
+ apr: 0,
108
+ priceRewardToken: 0,
109
+ tvl: 1,
110
+ });
111
+ }
112
+ }
113
+ return dynamicData;
114
+ },
115
+ },
116
+ };
117
+ }
@@ -10,6 +10,7 @@ import { ERC20DynamicData } from "./campaignTypes/ERC20DynamicData";
10
10
  import { ERC20_SNAPSHOTDynamicData } from "./campaignTypes/ERC20_SNAPSHOTDynamicData";
11
11
  import { EigenLayerDynamicData } from "./campaignTypes/EigenLayerDynamicData";
12
12
  import { EncompassingDynamicData } from "./campaignTypes/EncompassingDynamicData";
13
+ import { EventBasedDynamicData } from "./campaignTypes/EventBasedDynamicData";
13
14
  import { HyperdriveDynamicData } from "./campaignTypes/HyperdriveDynamicData";
14
15
  import { JSON_AIRDROPDynamicData } from "./campaignTypes/JSON_AIRDROPDynamicData";
15
16
  import { MORPHODynamicData } from "./campaignTypes/MORPHODynamicData";
@@ -112,6 +113,10 @@ export async function campaignsDynamicData(chainId, campaigns, type) {
112
113
  case Campaign.ENCOMPASSING: {
113
114
  return EncompassingDynamicData(chainId, campaigns);
114
115
  }
116
+ case "EVENT_BASED":
117
+ case Campaign.EVENT_BASED: {
118
+ return EventBasedDynamicData(chainId, campaigns);
119
+ }
115
120
  }
116
121
  return {
117
122
  cached: false,
@@ -22,6 +22,7 @@ import { getEncompassingMetadata } from "./subservices/getEncompassingMetadata.s
22
22
  import { getErc20Metadata } from "./subservices/getErc20Metadata.service";
23
23
  import { getErc20SnapshotMetadata } from "./subservices/getErc20SnapshotMetadata.service";
24
24
  import { getEulerMetadata } from "./subservices/getEulerMetadata.service";
25
+ import { getEventBasedMetadata } from "./subservices/getEventBasedMetadata.service.ts";
25
26
  import { getHyperdriveMetadata } from "./subservices/getHyperdriveMetadata.service";
26
27
  import { getJsonAirdropMetadata } from "./subservices/getJsonAirDropMetadata.service";
27
28
  import { getMorphoMetadata } from "./subservices/getMorphoMetadata.service";
@@ -99,6 +100,8 @@ export class OpportunityService {
99
100
  return getUniswapV4Metadata(chainId, campaignParams);
100
101
  case "ENCOMPASSING":
101
102
  return getEncompassingMetadata(chainId, campaign.rewardTokenAddress, campaignParams);
103
+ case "EVENT_BASED":
104
+ return getEventBasedMetadata(chainId, campaign.computeChainId, campaign.campaignId, campaign.rewardTokenAddress, campaign.amount, campaignParams);
102
105
  case "INVALID":
103
106
  return {
104
107
  name: "Invalid Campaigns",
@@ -0,0 +1,3 @@
1
+ import type { OpportunityMetadata } from "..";
2
+ import type { ChainId, EventBasedCampaign } from "@sdk";
3
+ export declare const getEventBasedMetadata: (computeChainId: ChainId, _distributionChainId: ChainId, _campaignId: string, _rewardToken: string, _amount: string, params: EventBasedCampaign["campaignParameters"]) => Promise<OpportunityMetadata>;
@@ -0,0 +1,43 @@
1
+ export const getEventBasedMetadata = async (computeChainId, _distributionChainId, _campaignId, _rewardToken, _amount, params) => {
2
+ try {
3
+ const action = "INVALID";
4
+ const mainProtocolId = "Hanji";
5
+ let name = `${params.eventID.split("(")[0]} on ${mainProtocolId}`;
6
+ let tokens = [{ chainId: computeChainId, address: params.contract }];
7
+ if (params.contract === "0xd0bc067cf877f7b76ceb331891331d9e6acda1a7") {
8
+ name = `Trade USDC/XTZ on ${mainProtocolId}`;
9
+ tokens = [
10
+ { chainId: computeChainId, address: "0x796Ea11Fa2dD751eD01b53C372fFDB4AAa8f00F9" },
11
+ { chainId: computeChainId, address: "0xc9B53AB2679f573e480d01e0f49e2B5CFB7a3EAb" },
12
+ ];
13
+ }
14
+ if (params.contract === "0x65ea4dd7f789c71c0f57ed84b3bdc3062898d3cb") {
15
+ name = `Trade USDC/ETH on ${mainProtocolId}`;
16
+ tokens = [
17
+ { chainId: computeChainId, address: "0x796Ea11Fa2dD751eD01b53C372fFDB4AAa8f00F9" },
18
+ { chainId: computeChainId, address: "0xfc24f770F94edBca6D6f885E12d4317320BcB401" },
19
+ ];
20
+ }
21
+ if (params.contract === "0xbb6b01d94e3f6ebae8647cb56d544f57928ab758") {
22
+ name = `Trade USDC/BTC on ${mainProtocolId}`;
23
+ tokens = [
24
+ { chainId: computeChainId, address: "0x796Ea11Fa2dD751eD01b53C372fFDB4AAa8f00F9" },
25
+ { chainId: computeChainId, address: "0xbFc94CD2B1E55999Cfc7347a9313e88702B83d0F" },
26
+ ];
27
+ }
28
+ return {
29
+ action,
30
+ name,
31
+ tokens,
32
+ mainProtocol: mainProtocolId,
33
+ };
34
+ }
35
+ catch (error) {
36
+ return {
37
+ action: "INVALID",
38
+ name: "Event Based Campaign",
39
+ tokens: [],
40
+ mainProtocol: undefined,
41
+ };
42
+ }
43
+ };