There are three ways to do this.
exchange_rates
call.This is an example: https://www.seiscan.app/pacific-1/interact-contract?selectedType=query&contract=sei1e3gttzq5e5k49f9f5gzvrl0rltlav65xu6p9xc0aj7e84lantdjqp7cncc&msg=ewogICJleGNoYW5nZV9yYXRlcyI6IHt9Cn0=. You can put in "limit":30 to get the most records.
Here, you can take APR and * by 365 and that will give you the percent so for a reported APR of 0.000097441761553662
, annual is 3.55%. Technically should be compounded, so that is 3.62%.
You can also manually take the first/last record and diff them (the time is in seconds), but it should be fine.
Generally this is a bit volatile due to when people mint/redeem. It has gone down to 3% and up to 6%.
To do it directly, you use this endpoint: https://rest.pacific-1.sei.io/seichain/mint/v1beta1/params, and then map out what time period you are in:
import { atom } from 'jotai';
import { loadable } from 'jotai/utils';
import { fetchWithRetry } from '@/utils/helper.ts';
interface PoolResponse {
pool: {
not_bonded_tokens: string;
bonded_tokens: string;
};
}
interface TokenReleaseSchedule {
start_date: string;
end_date: string;
token_release_amount: string;
}
interface StakingParams {
mint_denom: string;
token_release_schedule: TokenReleaseSchedule[];
}
interface MintResponse {
params: StakingParams;
}
export const emissionsAtom = atom(async () => {
const apiUrl = '<https://rest.pacific-1.sei.io/seichain/mint/v1beta1/params>';
try {
const response = (await fetchWithRetry(apiUrl)) as MintResponse;
return response;
} catch (error) {
console.error('Failed to fetch staking APY:', error);
throw error;
}
});
export const stakingPoolAtom = atom(async () => {
const apiUrl = '<https://rest.pacific-1.sei.io/cosmos/staking/v1beta1/pool>';
try {
const response = (await fetchWithRetry(apiUrl)) as PoolResponse;
return response.pool;
} catch (error) {
console.error('Failed to fetch staking pool parameters:', error);
throw error;
}
});
export const stakingApyAtom = atom(async (get) => {
try {
const pool = await get(stakingPoolAtom);
const emissions = await get(emissionsAtom);
if (!pool || !emissions) {
throw new Error('Failed to fetch pool or emissions data');
}
const bondedTokens = parseFloat(pool.bonded_tokens);
const oneYearFromNow = new Date();
oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() + 1);
// Note that using the end date here may not be strictly correct
// in case the 1 year mark is between a start and end, but close enough
const totalEmissions = emissions.params.token_release_schedule.reduce(
(acc, schedule) => {
const releaseDate = new Date(schedule.end_date);
if (releaseDate <= oneYearFromNow && releaseDate >= new Date()) {
return acc + parseFloat(schedule.token_release_amount);
}
return acc;
},
0,
);
if (bondedTokens === 0) {
return 0;
}
const stakingApy = (totalEmissions / bondedTokens) * 100;
return stakingApy;
} catch (error) {
console.error('Failed to calculate staking APY:', error);
// Estimate
return 4.1;
}
});
export const loadableStakingApyAtom = loadable(stakingApyAtom);