Skip to content

Commit

Permalink
set up veAPR
Browse files Browse the repository at this point in the history
  • Loading branch information
vidvidvid committed Feb 3, 2025
1 parent 26ee145 commit 8386bbb
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 11 deletions.
14 changes: 12 additions & 2 deletions packages/ui/constants/veIon.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ChainId, MarketExclusionConfig } from '@ui/types/veION';

import { iveIonAbi, iVoterAbi } from '@ionicprotocol/sdk';
import { iveIonAbi, iVoterAbi, voterAbi } from '@ionicprotocol/sdk';

export const VEION_CONTRACTS: Partial<Record<ChainId, `0x${string}`>> = {
8453: '0x8865E0678E3b1BD0F5302e4C178a4B576F6aAA27' as `0x${string}`, // Base
Expand All @@ -25,7 +25,7 @@ export function getVeIonContract(chainId: number): {
};
}

export function getVoterContract(chainId: number): {
export function getiVoterContract(chainId: number): {
abi: typeof iVoterAbi;
address: `0x${string}`;
} {
Expand All @@ -35,6 +35,16 @@ export function getVoterContract(chainId: number): {
};
}

export function getVoterContract(chainId: number): {
abi: typeof voterAbi;
address: `0x${string}`;
} {
return {
abi: voterAbi,
address: VOTER_CONTRACTS[chainId as ChainId] as `0x${string}`
};
}

export function isVeIonSupported(chainId: number): boolean {
return (
chainId in VEION_CONTRACTS &&
Expand Down
22 changes: 20 additions & 2 deletions packages/ui/hooks/veion/useMarketRows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { multipliers } from '@ui/utils/multipliers';
import { useVoteData } from './useVoteData';

import type { FlywheelReward } from '@ionicprotocol/types';
import { useVeAPR } from './useVeAPR';

export const useMarketRows = (
chain: number | string,
Expand Down Expand Up @@ -116,6 +117,18 @@ export const useMarketRows = (
marketSides
});

// const {
// veAPRs,
// isLoading: isLoadingVeAPR,
// refresh: refreshVeAPR
// } = useVeAPR({
// chain: +chain,
// marketAddresses,
// marketSides
// });

// console.log('veAPRs', veAPRs);

const processMarketRows = useCallback(() => {
if (!poolData?.assets || poolData.assets.length === 0) return [];

Expand Down Expand Up @@ -159,6 +172,7 @@ export const useMarketRows = (
currentAmount: asset.totalSupplyFiat.toFixed(2),
incentives: mockIncentives,
veAPR: 0,
// veAPR: veAPRs[key] ?? 0,
totalVotes: voteData[key]?.totalVotes ?? {
percentage: 0,
limit: 0
Expand Down Expand Up @@ -208,7 +222,8 @@ export const useMarketRows = (
marketAddress: asset.cToken as `0x${string}`,
currentAmount: asset.totalBorrowFiat.toFixed(2),
incentives: mockIncentives,
veAPR: 0, // Changed from string to number
// veAPR: veAPRs[key] ?? 0,
veAPR: 0,
totalVotes: voteData[key]?.totalVotes ?? {
percentage: 0,
limit: 0
Expand Down Expand Up @@ -259,6 +274,7 @@ export const useMarketRows = (
rewards,
merklApr,
voteData
// veAPRs
]);

useEffect(() => {
Expand All @@ -268,7 +284,7 @@ export const useMarketRows = (
!isLoadingBorrowApys &&
!isLoadingFraxtalAprs &&
!isLoadingRewards &&
!isLoadingVoteData &&
// !isLoadingVoteData &&
!isLoadingMerklData
) {
try {
Expand All @@ -290,6 +306,7 @@ export const useMarketRows = (
isLoadingRewards,
isLoadingMerklData,
isLoadingVoteData,
// isLoadingVeAPR,
processMarketRows
]);

Expand All @@ -306,6 +323,7 @@ export const useMarketRows = (
isLoadingFraxtalAprs ||
isLoadingRewards ||
isLoadingVoteData ||
// isLoadingVeAPR ||
isLoadingMerklData,
error,
refetch
Expand Down
167 changes: 167 additions & 0 deletions packages/ui/hooks/veion/useVeAPR.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Address, createPublicClient, getContract, PublicClient } from 'viem';
import { usePublicClient } from 'wagmi';

import { getiVoterContract, getVoterContract } from '@ui/constants/veIon';
import { MarketSide } from '@ui/types/veION';
import { bribeRewardsAbi } from '@ionicprotocol/sdk/src/generated';

interface UseVeAPRParams {
chain: number;
marketAddresses: `0x${string}`[];
marketSides: MarketSide[];
}

export function useVeAPR({
chain,
marketAddresses,
marketSides
}: UseVeAPRParams) {
const publicClient = usePublicClient();
const [veAPRs, setVeAPRs] = useState<Record<string, number>>({});
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);

const voterContract = useMemo(() => getVoterContract(chain), [chain]);

const calculateVeAPR = useCallback(async () => {
// Initialize veAPRs with all markets set to 0
const initialVeAPRs: Record<string, number> = {};
marketAddresses.forEach((market, index) => {
const side = marketSides[index];
const key = `${market}-${side === MarketSide.Supply ? 'supply' : 'borrow'}`;
initialVeAPRs[key] = 0;
});

// Only proceed if we have all required data
if (!voterContract || !publicClient || !marketAddresses.length) {
setVeAPRs(initialVeAPRs);
setIsLoading(false);
return;
}

try {
setIsLoading(true);
const newVeAPRs = { ...initialVeAPRs };

// Process each market
await Promise.all(
marketAddresses.map(async (market, index) => {
const side = marketSides[index];
const key = `${market}-${side === MarketSide.Supply ? 'supply' : 'borrow'}`;

try {
// Get reward accumulator address for market and side
const rewardAccumulator = (await publicClient.readContract({
...voterContract,
functionName: 'marketToRewardAccumulators',
args: [market, side]
})) as Address;

if (!rewardAccumulator) {
console.log('No reward accumulator for market:', key);
return;
}

// Get bribe contract address
const bribeAddress = (await publicClient.readContract({
...voterContract,
functionName: 'rewardAccumulatorToBribe',
args: [rewardAccumulator]
})) as Address;

if (
!bribeAddress ||
bribeAddress === '0x0000000000000000000000000000000000000000'
) {
console.log('No bribe contract for market:', key);
return;
}

// Create bribe contract instance
const bribeContract = {
address: bribeAddress,
abi: bribeRewardsAbi
};

// Get reward tokens
const rewardTokens = (await publicClient.readContract({
...bribeContract,
functionName: 'getAllLpRewardTokens'
})) as Address[];
console.log('Reward tokens:', rewardTokens);

if (!rewardTokens.length) {
console.log('No reward tokens for market:', key);
return;
}

const currentEpoch = Math.floor(
Date.now() / 1000 / (7 * 24 * 60 * 60)
);

// Get total rewards per epoch for each token
const rewardAmounts = await Promise.all(
rewardTokens.map(async (token) => {
const amount = (await publicClient.readContract({
...bribeContract,
functionName: 'tokenRewardsPerEpoch',
args: [token, BigInt(currentEpoch)]
})) as bigint;
return amount;
})
);
// console.log('Reward amounts:', { key, rewardAmounts });

// Get total voting power for first token
const totalSupply = (await publicClient.readContract({
...bribeContract,
functionName: 'totalSupply',
args: [rewardTokens[0]]
})) as bigint;
// console.log('Total supply:', { key, totalSupply });

// Calculate APR
const totalWeeklyBribes = rewardAmounts.reduce(
(sum: bigint, amount: bigint) => sum + amount,
0n
);
const yearlyBribes = totalWeeklyBribes * 52n;

const veAPR =
totalSupply > 0n
? Number((yearlyBribes * 100n) / totalSupply)
: 0;

// console.log('Calculated veAPR:', { key, veAPR });
newVeAPRs[key] = veAPR;
} catch (err) {
console.error('Error processing market:', { key, error: err });
// Keep the initial 0 value for this market
}
})
);

console.log('Setting new veAPRs:', newVeAPRs);
setVeAPRs(newVeAPRs);
setError(null);
} catch (err) {
console.error('Error calculating veAPR:', err);
setError(
err instanceof Error ? err : new Error('Failed to calculate veAPR')
);
setVeAPRs(initialVeAPRs); // Set initial values on error
} finally {
setIsLoading(false);
}
}, [chain, marketAddresses, marketSides, publicClient, voterContract]);

// Only run when marketAddresses changes
useEffect(() => {
if (marketAddresses.length > 0) {
calculateVeAPR();
}
}, [marketAddresses, calculateVeAPR]);

return { veAPRs, isLoading, error, refresh: calculateVeAPR };
}
4 changes: 2 additions & 2 deletions packages/ui/hooks/veion/useVeIONVote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
useWalletClient
} from 'wagmi';

import { getVoterContract } from '@ui/constants/veIon';
import { getiVoterContract } from '@ui/constants/veIon';
import { useMarketDataContext } from '@ui/context/MarketDataContext';
import type { MarketSide } from '@ui/types/veION';
import { handleSwitchOriginChain } from '@ui/utils/NetworkChecker';
Expand Down Expand Up @@ -43,7 +43,7 @@ export const convertFromContractWeight = (weight: number): string => {
};

export function useVeIONVote(chain: number) {
const voterContract = getVoterContract(chain);
const voterContract = getiVoterContract(chain);
const publicClient = usePublicClient();
const { data: walletClient } = useWalletClient();
const { address, isConnected } = useAccount();
Expand Down
5 changes: 2 additions & 3 deletions packages/ui/hooks/veion/useVoteData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useEffect, useState, useCallback } from 'react';

import { usePublicClient } from 'wagmi';

import { getVoterContract } from '@ui/constants/veIon';
import { getiVoterContract } from '@ui/constants/veIon';
import { MarketSide } from '@ui/types/veION';

interface UseVoteDataParams {
Expand Down Expand Up @@ -38,9 +38,8 @@ export function useVoteData({
const [voteData, setVoteData] = useState<Record<string, VoteData>>({});
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
const [lastVoted, setLastVoted] = useState<number | null>(null);

const voterContract = getVoterContract(chain);
const voterContract = getiVoterContract(chain);

const formatValue = (value: bigint): number => {
return Number((value * BASIS_POINTS) / DECIMALS_SCALAR);
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/hooks/veion/useVotingPeriod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useMemo, useState, useEffect, useCallback } from 'react';

import { usePublicClient } from 'wagmi';

import { getVoterContract } from '@ui/constants/veIon';
import { getiVoterContract } from '@ui/constants/veIon';

export const EPOCH_ZERO = new Date('2025-01-27');
export const EPOCH_DURATION_DAYS = 8;
Expand Down Expand Up @@ -81,7 +81,7 @@ export function useVotingPeriod(

try {
setIsLoading(true);
const voterContract = getVoterContract(+chain);
const voterContract = getiVoterContract(+chain);
const lastVotedTimestamp = await publicClient.readContract({
...voterContract,
functionName: 'lastVoted',
Expand Down

0 comments on commit 8386bbb

Please sign in to comment.