Skip to content

Commit

Permalink
Merge pull request #227 from prevostc/add-beefy-clm
Browse files Browse the repository at this point in the history
beefy - yield : add CLM
  • Loading branch information
0xroll authored Jun 23, 2024
2 parents b9c6113 + 8993356 commit 9828159
Show file tree
Hide file tree
Showing 14 changed files with 155 additions and 44 deletions.
2 changes: 2 additions & 0 deletions adapters/beefy/hourly_blocks.csv
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ number,timestamp
4740000,1716263772
4730000,1716233771
4784763,1716398064
5684890,1718771519
5784890,1718972096
19 changes: 19 additions & 0 deletions adapters/beefy/src/abi/BeefyClmStrategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const BeefyClmStrategyAbi = [
{
type: "function",
name: "price",
inputs: [],
outputs: [{ name: "_price", type: "uint256", internalType: "uint256" }],
stateMutability: "view",
},
{
type: "function",
name: "range",
inputs: [],
outputs: [
{ name: "lowerPrice", type: "uint256", internalType: "uint256" },
{ name: "upperPrice", type: "uint256", internalType: "uint256" },
],
stateMutability: "view",
},
] as const;
29 changes: 29 additions & 0 deletions adapters/beefy/src/abi/BeefyVaultConcLiq.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export const BeefyVaultConcLiqAbi = [
{
inputs: [],
name: "balances",
outputs: [
{ internalType: "uint256", name: "amount0", type: "uint256" },
{ internalType: "uint256", name: "amount1", type: "uint256" },
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "totalSupply",
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "wants",
outputs: [
{ internalType: "address", name: "token0", type: "address" },
{ internalType: "address", name: "token1", type: "address" },
],
stateMutability: "view",
type: "function",
},
] as const;
4 changes: 2 additions & 2 deletions adapters/beefy/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export const BEEFY_VAULT_API = "https://api.beefy.finance/vaults";
export const BEEFY_VAULT_API = "https://api.beefy.finance/harvestable-vaults";

// subgraph source: https://github.com/beefyfinance/l2-lxp-liquidity-subgraph
export const BEEFY_SUBGRAPH_URL =
"https://api.goldsky.com/api/public/project_clu2walwem1qm01w40v3yhw1f/subgraphs/beefy-l2-lxp-liquidity-linea/latest/gn";
"https://api.goldsky.com/api/public/project_clu2walwem1qm01w40v3yhw1f/subgraphs/beefy-balances-linea/latest/gn";

export const SUBGRAPH_PAGE_SIZE = 1000;

Expand Down
15 changes: 10 additions & 5 deletions adapters/beefy/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { getVaultBreakdowns } from "./sdk/breakdown/getVaultBreakdown";
import { uniq } from "lodash";
import { BeefyVaultBreakdown } from "./sdk/breakdown/types";
import { Hex } from "viem";
import { getVaultShareTokenBalances } from "./sdk/vault/getVaultShareTokenBalances";
import { getTokenBalances } from "./sdk/vault/getTokenBalances";

interface BlockData {
blockNumber: number;
Expand All @@ -30,11 +30,11 @@ export const getUserTVLByBlock = async (

const [vaultConfigs, investorPositions] = await Promise.all([
getBeefyVaultConfig("linea"),
getVaultShareTokenBalances(BigInt(blockNumber)),
getTokenBalances(BigInt(blockNumber)),
]);

const vaultAddressWithActivePosition = uniq(
investorPositions.map((pos) => pos.vault_address.toLowerCase())
investorPositions.map((pos) => pos.token_address)
);
const vaults = vaultConfigs.filter((vault) =>
vaultAddressWithActivePosition.includes(vault.vault_address)
Expand All @@ -53,12 +53,17 @@ export const getUserTVLByBlock = async (
Record<Hex /* token */, bigint /* amount */>
> = {};
for (const position of investorPositions) {
const breakdown = breakdownByVaultAddress[position.vault_address];
const breakdown = breakdownByVaultAddress[position.token_address];
if (!breakdown) {
// some test vaults were never available in the api
continue;
}

if (breakdown.isLiquidityEligible === false) {
// skip non-eligible vaults
continue;
}

if (!investorTokenBalances[position.user_address]) {
investorTokenBalances[position.user_address] = {};
}
Expand All @@ -70,7 +75,7 @@ export const getUserTVLByBlock = async (
}

investorTokenBalances[position.user_address][balance.tokenAddress] +=
(BigInt(position.shares_balance) * balance.vaultBalance) /
(BigInt(position.token_address) * balance.vaultBalance) /
breakdown.vaultTotalSupply;
}
}
Expand Down
2 changes: 2 additions & 0 deletions adapters/beefy/src/sdk/breakdown/getVaultBreakdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BeefyViemClient, getViemClient } from "../viemClient";
import { getSolidlyVaultBreakdown } from "./protocol_type/solidly";
import { getGammaVaultBreakdown } from "./protocol_type/gamma";
import { getMendiVaultBreakdown } from "./protocol_type/mendi";
import { getBeefyClmVaultBreakdown } from "./protocol_type/beefy_clm";

type BreakdownMethod = (
client: BeefyViemClient,
Expand All @@ -16,6 +17,7 @@ const breakdownMethods: Record<BeefyProtocolType, BreakdownMethod> = {
mendi: getMendiVaultBreakdown,
gamma: getGammaVaultBreakdown,
ichi: getGammaVaultBreakdown,
beefy_clm: getBeefyClmVaultBreakdown,
};

export const getVaultBreakdowns = async (
Expand Down
52 changes: 52 additions & 0 deletions adapters/beefy/src/sdk/breakdown/protocol_type/beefy_clm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Hex, getContract } from "viem";
import { BeefyVault } from "../../vault/getBeefyVaultConfig";
import { BeefyViemClient } from "../../viemClient";
import { BeefyVaultBreakdown } from "../types";
import { BeefyVaultConcLiqAbi } from "../../../abi/BeefyVaultConcLiq";
import { BeefyClmStrategyAbi } from "../../../abi/BeefyClmStrategy";

export const getBeefyClmVaultBreakdown = async (
client: BeefyViemClient,
blockNumber: bigint,
vault: BeefyVault
): Promise<BeefyVaultBreakdown> => {
const managerContract = getContract({
client,
address: vault.vault_address,
abi: BeefyVaultConcLiqAbi,
});

const strategyContract = getContract({
client,
address: vault.strategy_address,
abi: BeefyClmStrategyAbi,
});

const [balances, vaultTotalSupply, wants, range, price] = await Promise.all([
managerContract.read.balances({ blockNumber }),
managerContract.read.totalSupply({ blockNumber }),
managerContract.read.wants({ blockNumber }),
strategyContract.read.range({ blockNumber }),
strategyContract.read.price({ blockNumber }),
]);

// special rule to exclude out of range liquidity for concentrated liquidity vaults
const isLiquidityEligible = price >= range[0] && price <= range[1];

return {
vault,
blockNumber,
vaultTotalSupply,
isLiquidityEligible,
balances: [
{
tokenAddress: wants[0].toLocaleLowerCase() as Hex,
vaultBalance: balances[0],
},
{
tokenAddress: wants[1].toLocaleLowerCase() as Hex,
vaultBalance: balances[1],
},
],
};
};
1 change: 1 addition & 0 deletions adapters/beefy/src/sdk/breakdown/protocol_type/gamma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const getGammaVaultBreakdown = async (
vault,
blockNumber,
vaultTotalSupply,
isLiquidityEligible: true,
balances: [
{
tokenAddress: token0.toLocaleLowerCase() as Hex,
Expand Down
1 change: 1 addition & 0 deletions adapters/beefy/src/sdk/breakdown/protocol_type/ichi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const getGammaVaultBreakdown = async (
vault,
blockNumber,
vaultTotalSupply,
isLiquidityEligible: true,
balances: [
{
tokenAddress: token0.toLocaleLowerCase() as Hex,
Expand Down
1 change: 1 addition & 0 deletions adapters/beefy/src/sdk/breakdown/protocol_type/mendi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const getMendiVaultBreakdown = async (
vault,
blockNumber,
vaultTotalSupply,
isLiquidityEligible: true,
balances: [
{
tokenAddress: vault.undelying_lp_address.toLocaleLowerCase() as Hex,
Expand Down
1 change: 1 addition & 0 deletions adapters/beefy/src/sdk/breakdown/protocol_type/solidly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const getSolidlyVaultBreakdown = async (
vault,
blockNumber,
vaultTotalSupply,
isLiquidityEligible: true,
balances: [
{
tokenAddress: t0.toLocaleLowerCase() as Hex,
Expand Down
1 change: 1 addition & 0 deletions adapters/beefy/src/sdk/breakdown/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type BeefyVaultBreakdown = {
vault: BeefyVault;
blockNumber: bigint;
vaultTotalSupply: bigint;
isLiquidityEligible: boolean;
balances: {
tokenAddress: Hex;
vaultBalance: bigint;
Expand Down
13 changes: 11 additions & 2 deletions adapters/beefy/src/sdk/vault/getBeefyVaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@ export type BeefyVault = {
id: string;
vault_address: Hex;
undelying_lp_address: Hex;
strategy_address: Hex;
chain: string;
protocol_type: BeefyProtocolType;
};

export type BeefyProtocolType = "gamma" | "ichi" | "mendi" | "solidly";
export type BeefyProtocolType =
| "gamma"
| "ichi"
| "mendi"
| "solidly"
| "beefy_clm";

type ApiPlatformId = "gamma" | "ichi" | "lynex" | "mendi" | "nile"; // and more but we don't use those on linea
type ApiPlatformId = "gamma" | "ichi" | "lynex" | "mendi" | "nile" | "beefy"; // and more but we don't use those on linea

type ApiVault = {
id: string;
Expand All @@ -21,6 +27,7 @@ type ApiVault = {
chain: string;
platformId: ApiPlatformId;
tokenAddress: Hex;
strategy: Hex;
};

const protocol_map: Record<ApiPlatformId, BeefyProtocolType> = {
Expand All @@ -29,6 +36,7 @@ const protocol_map: Record<ApiPlatformId, BeefyProtocolType> = {
lynex: "solidly",
mendi: "mendi",
nile: "solidly",
beefy: "beefy_clm",
};

export const getBeefyVaultConfig = memoize(
Expand All @@ -49,6 +57,7 @@ export const getBeefyVaultConfig = memoize(
vault_address: vault.earnedTokenAddress.toLocaleLowerCase() as Hex,
chain: vault.chain,
protocol_type,
strategy_address: vault.strategy.toLocaleLowerCase() as Hex,
undelying_lp_address: vault.tokenAddress.toLocaleLowerCase() as Hex,
};
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,56 +1,45 @@
import { Hex } from "viem";
import { BEEFY_SUBGRAPH_URL, SUBGRAPH_PAGE_SIZE } from "../../config";

type ShareTokenBalance = {
type TokenBalance = {
user_address: Hex;
vault_address: Hex;
shares_balance: bigint;
token_address: Hex;
balance: bigint;
};

type QueryResult = {
investorPositions: {
investor: {
tokenBalances: {
account: {
id: Hex;
};
vault: {
sharesToken: {
id: Hex;
};
underlyingToken: {
id: Hex;
symbol: string;
};
token: {
id: Hex;
};
rawSharesBalance: string;
amount: string;
}[];
};

export const getVaultShareTokenBalances = async (
export const getTokenBalances = async (
blockNumber: bigint
): Promise<ShareTokenBalance[]> => {
let allPositions: ShareTokenBalance[] = [];
): Promise<TokenBalance[]> => {
let allPositions: TokenBalance[] = [];
let skip = 0;
while (true) {
const query = `
query LineaUser($blockNumber: Int!, $skip: Int!, $first: Int!) {
investorPositions(
tokenBalances(
block: {number: $blockNumber}
first: $first
where: { rawSharesBalance_gt: 0 }
where: { amount_gt: 0 }
skip: $skip
) {
investor {
account {
id
}
vault {
sharesToken {
id
}
underlyingToken {
id
}
token {
id
}
rawSharesBalance
amount
}
}
`;
Expand Down Expand Up @@ -80,17 +69,16 @@ export const getVaultShareTokenBalances = async (
}

allPositions = allPositions.concat(
res.data.investorPositions.map(
(position): ShareTokenBalance => ({
shares_balance: BigInt(position.rawSharesBalance),
user_address: position.investor.id.toLocaleLowerCase() as Hex,
vault_address:
position.vault.sharesToken.id.toLocaleLowerCase() as Hex,
res.data.tokenBalances.map(
(position): TokenBalance => ({
balance: BigInt(position.amount),
user_address: position.account.id.toLocaleLowerCase() as Hex,
token_address: position.token.id.toLocaleLowerCase() as Hex,
})
)
);

if (res.data.investorPositions.length < SUBGRAPH_PAGE_SIZE) {
if (res.data.tokenBalances.length < SUBGRAPH_PAGE_SIZE) {
break;
}

Expand Down

0 comments on commit 9828159

Please sign in to comment.