Skip to content

Commit

Permalink
Merge pull request #331 from Gearbox-protocol/gearbox-campaigns
Browse files Browse the repository at this point in the history
feat: gearbox campaigns
  • Loading branch information
essserrr authored Feb 5, 2025
2 parents 45abac1 + 0c63579 commit 5c44b98
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 142 deletions.
188 changes: 59 additions & 129 deletions src/gearboxRewards/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,13 @@ import {
import { GearboxBackendApi } from "../core/endpoint";
import { PoolData } from "../core/pool";
import { TokenData } from "../tokens/tokenData";
import {
iAirdropDistributorAbi,
iFarmingPoolAbi,
iMulticall3Abi,
} from "../types";
import { toBN } from "../utils/formatter";
import { iAirdropDistributorAbi, iFarmingPoolAbi } from "../types";
import { BigIntMath } from "../utils/math";
import { ExtraRewardApy } from "./apy";
import {
MerkleXYZApi,
MerkleXYZRewardsCampaignsResponse,
MerkleXYZUserRewardsResponse,
MerkleXYZV4CampaignsResponse,
} from "./merklAPI";

export interface GearboxExtraMerkleLmReward {
Expand Down Expand Up @@ -97,29 +93,17 @@ export interface FarmInfo {
symbol: SupportedToken;
}

type PoolsWithExtraRewardsList = Record<NetworkType, Array<Address>>;

const DEFAULT_POOLS_WITH_EXTRA_REWARDS: PoolsWithExtraRewardsList = {
Mainnet: [
"0x7354EC6E852108411e681D13E11185c3a2567981", // dtBTCV3
],
Arbitrum: [],
Optimism: [],
Base: [],
};

type ReportHandler = (e: unknown, description?: string) => void;

export interface GetLmRewardsInfoProps {
pools: Record<Address, PoolData>;
tokensList: Record<Address, TokenData>;
provider: PublicClient;
}

multicallAddress: Address;

poolsWithExtraRewards?: PoolsWithExtraRewardsList;
network: NetworkType;
reportError?: ReportHandler;
export interface GetExtraRewardsProps {
chainId: number;
tokensList: Record<Address, TokenData>;
}

export interface GetLmRewardsProps {
Expand Down Expand Up @@ -150,15 +134,53 @@ export interface ClaimLmRewardsV3Props {
}

export class GearboxRewardsApi {
static async getExtraRewards({ chainId, tokensList }: GetExtraRewardsProps) {
const res = await axios.get<MerkleXYZV4CampaignsResponse>(
MerkleXYZApi.getGearboxCampaignsUrl(),
);
const currentActiveCampaigns = res.data.filter(
c => c.status === "LIVE" && c.chainId === chainId,
);

const r = currentActiveCampaigns.reduce<
Record<Address, Array<ExtraRewardApy>>
>((acc, campaign) => {
const rewardSource = (
campaign.tokens[0]?.address || campaign.identifier
).toLowerCase() as Address;

const allRewards = campaign.rewardsRecord.breakdowns
.map((r, i) => {
const tokenLc = r.token.address.toLowerCase() as Address;
const { symbol = r.token.symbol } = tokensList[tokenLc] || {};

const apy = campaign.aprRecord.breakdowns[i]?.value || 0;

const apyObject: ExtraRewardApy = {
token: rewardSource,
balance: null,

apy: apy,
rewardToken: tokenLc,
rewardTokenSymbol: symbol,
};

return apyObject;
})
.filter(r => r.apy > 0);

acc[rewardSource] = [...(acc[rewardSource] || []), ...allRewards];

return acc;
}, {});

return r;
}

static async getLmRewardsInfo({
pools,
provider,
multicallAddress,
tokensList,

poolsWithExtraRewards = DEFAULT_POOLS_WITH_EXTRA_REWARDS,
network,
reportError,
}: GetLmRewardsInfoProps) {
const poolByStakedDiesel = Object.values(pools).reduce<
Record<Address, Address>
Expand Down Expand Up @@ -187,19 +209,6 @@ export class GearboxRewardsApi {
const poolStakedTokens = TypedObjectUtils.keys(poolByStakedDiesel);
const allPoolTokens = TypedObjectUtils.keys(poolByItsToken);

const chainId = CHAINS[network];
const poolTokensWithExtraReward = (
poolsWithExtraRewards[network] || []
).filter(p => {
const token = tokensList[p.toLowerCase() as Address];

if (!token) {
console.error(`Pool token not found ${p}`);
return false;
}
return true;
});

const farmInfoCalls = poolStakedTokens.map(address => ({
address,
abi: iFarmingPoolAbi,
Expand All @@ -221,40 +230,14 @@ export class GearboxRewardsApi {
args: [],
}));

const [mc, ...extra] = await Promise.allSettled([
provider.multicall({
allowFailure: false,
multicallAddress: MULTICALL_ADDRESS,
contracts: [
{
address: multicallAddress,
abi: iMulticall3Abi as any,
functionName: "getCurrentBlockTimestamp",
args: [],
},

...farmInfoCalls,
...farmSupplyCalls,
...rewardTokenCalls,
],
}),

...poolTokensWithExtraReward.map(t => {
return axios.get<MerkleXYZRewardsCampaignsResponse>(
MerkleXYZApi.getRewardsCampaignsUrl({
params: {
chainId,
mainParameter: getAddress(t),
},
}),
);
}),
]);
const mc = await provider.multicall({
allowFailure: false,
multicallAddress: MULTICALL_ADDRESS,
contracts: [...farmInfoCalls, ...farmSupplyCalls, ...rewardTokenCalls],
});

const mcResponse =
this.extractFulfilled(mc, reportError, "rewardsInfoMulticall") || [];
const [ts = 0n, ...restMCResponse] = mcResponse;
const blockTimestamp = (ts as bigint) || 0n;
const mcResponse = mc;
const [...restMCResponse] = mcResponse;

const farmInfoCallsEnd = farmInfoCalls.length;
const farmInfo = restMCResponse.slice(
Expand Down Expand Up @@ -298,57 +281,8 @@ export class GearboxRewardsApi {
{},
);

const extraRewards = extra.reduce<Record<string, Array<FarmInfo>>>(
(acc, r, index) => {
const p = poolTokensWithExtraReward[index].toLowerCase() as Address;

const safeResp = this.extractFulfilled(
r,
reportError,
`merkleCampaign: ${p}`,
);

const l = safeResp?.data.reduce<Array<FarmInfo>>((infos, d) => {
const started = toBigInt(d.startTimestamp || 0);
const finished = toBigInt(d.endTimestamp || 0);

if (blockTimestamp >= started && blockTimestamp <= finished) {
const rewardTokenLc = (
d.rewardToken || ""
).toLowerCase() as Address;
const rewardTokenData = tokensList[rewardTokenLc];
const reward = toBN(
d.amountDecimal,
rewardTokenData?.decimals || 18,
);

if (rewardTokenData && reward > 0) {
infos.push({
pool: poolByItsToken[p],
duration: toBigInt(d.endTimestamp - d.startTimestamp),
finished,
reward,
balance: 0n,
symbol: rewardTokenData.symbol,
});
}
}

return infos;
}, []);

if (l) {
acc[p] = l;
}

return acc;
},
{},
);

const stakedTokenRewards = allPoolTokens.reduce<{
base: Record<string, FarmInfo>;
extra: Record<string, Array<FarmInfo>>;
all: Record<string, Array<FarmInfo>>;
}>(
(acc, pool) => {
Expand All @@ -368,15 +302,12 @@ export class GearboxRewardsApi {
}
: undefined;

const extra = extraRewards[pool] || [];

if (baseReward) acc.base[pool] = baseReward;
acc.extra[pool] = extra;
acc.all[pool] = [...(baseReward ? [baseReward] : []), ...extra];
acc.all[pool] = [...(baseReward ? [baseReward] : [])];

return acc;
},
{ base: {}, extra: {}, all: {} },
{ base: {}, all: {} },
);

const rewardPoolsSupply = allPoolTokens.reduce<Record<string, bigint>>(
Expand All @@ -391,7 +322,6 @@ export class GearboxRewardsApi {
return {
rewardPoolsInfo: stakedTokenRewards.all,
baseRewardPoolsInfo: stakedTokenRewards.base,
extraRewardPoolsInfo: stakedTokenRewards.extra,
rewardPoolsSupply,
};
}
Expand Down
18 changes: 14 additions & 4 deletions src/gearboxRewards/apy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ const ONE = PERCENTAGE_FACTOR_1KK * 10n;
export interface ExtraRewardApy {
token: Address;
balance: bigint | null;
apy: number;

rewardInfo: FarmInfo;
apy: number;
rewardToken: Address;
rewardTokenSymbol: string;
}

interface GetPoolExtraAPY_V3Props {
Expand Down Expand Up @@ -150,8 +151,10 @@ export class GearboxRewardsApy {
return {
token: stakedDieselToken,
balance: null,

apy: r,
rewardInfo: rewardPoolsInfo,
rewardToken: rewardAddress,
rewardTokenSymbol: rewardPoolsInfo.symbol,
};
}

Expand Down Expand Up @@ -252,6 +255,13 @@ export class GearboxRewardsApy {
},
}) / Number(PERCENTAGE_FACTOR);

return { token, balance, rewardInfo, apy: r };
return {
token,
balance,

apy: r,
rewardToken: rewardAddress,
rewardTokenSymbol: rewardInfo.symbol,
};
}
}
Loading

0 comments on commit 5c44b98

Please # to comment.