diff --git a/src/pools/constants/types.ts b/src/pools/constants/types.ts index e76c542..94c6c95 100644 --- a/src/pools/constants/types.ts +++ b/src/pools/constants/types.ts @@ -17,6 +17,7 @@ interface PoolMetrics { stakingTokenPrice: number; earningTokenPrice: number; apr: number; + alpApr?: number; endTimestamp: number; } diff --git a/src/pools/service/alpFee.ts b/src/pools/service/alpFee.ts new file mode 100644 index 0000000..4d9890c --- /dev/null +++ b/src/pools/service/alpFee.ts @@ -0,0 +1,75 @@ +import { ChainId } from "@pancakeswap/sdk"; +import BigNumber from "bignumber.js"; +import { Address } from "viem"; +import { getViemClients } from "../../utils/viem"; + +const WEEK = 7; +const YEAR = 365; +const API_URL = "https://perp.pancakeswap.finance/bapi/futures/v1/public/future/apx/fee/info?chain="; + +const CONTRACT_ADDRESS: Record = { + [ChainId.OPBNB]: "0x5A5454A6030FB50ceb3eb78977D140198A27be5e", + [ChainId.ARBITRUM_ONE]: "0xB3879E95a4B8e3eE570c232B19d520821F540E48", +}; + +const CHAIN_NAME_MAP: Record = { + [ChainId.OPBNB]: "OPBNB", + [ChainId.ARBITRUM_ONE]: "ARB", +}; + +export const alpFee = async (chainId: ChainId) => { + try { + const client = getViemClients({ chainId }); + const [totalValue] = await client.multicall({ + contracts: [ + { + abi: [ + { + inputs: [], + name: "totalValue", + outputs: [ + { + components: [ + { internalType: "address", name: "tokenAddress", type: "address" }, + { internalType: "int256", name: "value", type: "int256" }, + { internalType: "uint8", name: "decimals", type: "uint8" }, + { internalType: "int256", name: "valueUsd", type: "int256" }, + { internalType: "uint16", name: "targetWeight", type: "uint16" }, + { internalType: "uint16", name: "feeBasisPoints", type: "uint16" }, + { internalType: "uint16", name: "taxBasisPoints", type: "uint16" }, + { internalType: "bool", name: "dynamicFee", type: "bool" }, + ], + internalType: "struct IVault.LpItem[]", + name: "lpItems", + type: "tuple[]", + }, + ], + stateMutability: "view", + type: "function", + }, + ] as const, + address: CONTRACT_ADDRESS?.[chainId], + functionName: "totalValue", + }, + ], + allowFailure: false, + }); + + const totalValueUsd = totalValue + .map((i) => new BigNumber(i.valueUsd.toString()).div(1e18).toNumber()) + .reduce((a, b) => a + b, 0); + + const response = await fetch(`${API_URL}${CHAIN_NAME_MAP[chainId]}`); + const result = await response.json(); + + const { alpFundingFee, alpTradingFee, alpLipFee } = result.data; + const apr = new BigNumber(alpFundingFee).plus(alpTradingFee).plus(alpLipFee); + const totalApr = apr.div(totalValueUsd.toString()).div(WEEK); + + const apy = totalApr.plus(1).exponentiatedBy(YEAR).minus(1).times(100); + return apy.toNumber(); + } catch (error) { + console.info("Fetch ALP boosted fee error: ", error); + return 0; + } +}; diff --git a/src/pools/service/poolMetrics.ts b/src/pools/service/poolMetrics.ts index 2e591cc..b3e2f2b 100644 --- a/src/pools/service/poolMetrics.ts +++ b/src/pools/service/poolMetrics.ts @@ -5,6 +5,7 @@ import { fetchCakeTokenPrice } from "./cakeTokenPrice"; import { fetchEndTimestamp } from "./endTimestamp"; import { fetchTotalStaked } from "./totalStacked"; import { ChainId } from "@pancakeswap/sdk"; +import { alpFee } from "./alpFee"; export const calculatePoolMetrics = async (poolsConfigs: SerializedPool[], chainId: ChainId) => { return await Promise.all(poolsConfigs.map((value) => fillMetric(value, chainId))); @@ -21,11 +22,13 @@ const fillMetric = async (poolConfig: SerializedPool, chainId) => { poolConfig.tokenPerSecond ); const endTimestamp = await fetchEndTimestamp(poolConfig.contractAddress, chainId); + const alpApr = await alpFee(chainId); poolConfig.metrics.totalStaked = totalStaked; poolConfig.metrics.stakingTokenPrice = stakingTokenPrice; poolConfig.metrics.earningTokenPrice = earningTokenPrice; poolConfig.metrics.apr = apr; + poolConfig.metrics.alpApr = alpApr; poolConfig.metrics.endTimestamp = endTimestamp; return poolConfig;