diff --git a/src/api/stats/common/curve/getCurveApyData.js b/src/api/stats/common/curve/getCurveApyData.js index 64d9e35aa..bf567239a 100644 --- a/src/api/stats/common/curve/getCurveApyData.js +++ b/src/api/stats/common/curve/getCurveApyData.js @@ -1,6 +1,7 @@ const BigNumber = require('bignumber.js'); import { fetchPrice } from '../../../../utils/fetchPrice'; + const { fetchContract } = require('../../../rpc/client'); const { default: ICurveGauge } = require('../../../../abis/ICurveGauge'); const { default: ICurveRewards } = require('../../../../abis/ICurveRewards'); @@ -8,6 +9,7 @@ const { default: ICurveRewardStream } = require('../../../../abis/ICurveRewardSt const secondsPerYear = 31536000; +// TODO rename to getCurveSubgraphApys export const getCurveBaseApys = async (pools, url) => { let apys = {}; try { @@ -35,6 +37,25 @@ const getSubgraphDataApy = (apyData, poolAddress) => { } }; +// https://api.curve.fi/v1/getBaseApys/chain +export const getCurveGetBaseApys = async (pools, url) => { + let apys = {}; + try { + const response = await fetch(url).then(res => res.json()); + const apyData = response.data.baseApys; + pools.forEach(pool => { + let poolData = apyData.find(p => p.address.toLowerCase() === pool.pool.toLowerCase()); + let apy = 0; + if (pool) apy = Math.max(poolData.latestDailyApyPcent, poolData.latestWeeklyApyPcent); + apy = new BigNumber(Number(apy) / 100); + apys = { ...apys, ...{ [pool.name]: apy } }; + }); + } catch (err) { + console.error('Curve getBaseApys error ', url, err.message); + } + return apys; +}; + export const getCurveBaseApysOld = async (pools, url, factoryUrl) => { let factoryApyData = []; if (factoryUrl) { diff --git a/src/api/stats/fraxtal/getCurveApys.js b/src/api/stats/fraxtal/getCurveApys.js new file mode 100644 index 000000000..f8068de3a --- /dev/null +++ b/src/api/stats/fraxtal/getCurveApys.js @@ -0,0 +1,18 @@ +import getApyBreakdown from '../common/getApyBreakdown'; +import { getCurveGetBaseApys } from '../common/curve/getCurveApyData'; +import { getCurveApysCommon } from '../common/curve/getCurveApysCommon'; +import { FRAXTAL_CHAIN_ID as chainId } from '../../../constants'; + +const pools = require('../../../data/fraxtal/curvePools.json').filter(p => p.gauge && !p.convex); +const subgraphApyUrl = 'https://api.curve.fi/api/getSubgraphData/fraxtal'; +const baseApyUrl = 'https://api.curve.fi/v1/getBaseApys/fraxtal'; +const tradingFees = 0.0002; + +export const getCurveApys = async () => { + const [baseApys, farmApys] = await Promise.all([ + getCurveGetBaseApys(pools, baseApyUrl), + getCurveApysCommon(chainId, pools), + ]); + const poolsMap = pools.map(p => ({ name: p.name, address: p.name })); + return getApyBreakdown(poolsMap, baseApys, farmApys, tradingFees); +}; diff --git a/src/api/stats/fraxtal/index.js b/src/api/stats/fraxtal/index.js new file mode 100644 index 000000000..2acd8cc2f --- /dev/null +++ b/src/api/stats/fraxtal/index.js @@ -0,0 +1,53 @@ +const { getCurveApys } = require('./getCurveApys'); + +const getApys = [getCurveApys]; + +const getFraxtalApys = async () => { + const start = Date.now(); + let apys = {}; + let apyBreakdowns = {}; + + let promises = []; + getApys.forEach(getApy => promises.push(getApy())); + const results = await Promise.allSettled(promises); + + for (const result of results) { + if (result.status !== 'fulfilled') { + console.warn('getFraxtalApys error', result.reason); + continue; + } + + // Set default APY values + let mappedApyValues = result.value; + let mappedApyBreakdownValues = {}; + + // Loop through key values and move default breakdown format + // To require totalApy key + for (const [key, value] of Object.entries(result.value)) { + mappedApyBreakdownValues[key] = { + totalApy: value, + }; + } + + // Break out to apy and breakdowns if possible + let hasApyBreakdowns = 'apyBreakdowns' in result.value; + if (hasApyBreakdowns) { + mappedApyValues = result.value.apys; + mappedApyBreakdownValues = result.value.apyBreakdowns; + } + + apys = { ...apys, ...mappedApyValues }; + + apyBreakdowns = { ...apyBreakdowns, ...mappedApyBreakdownValues }; + } + + const end = Date.now(); + console.log(`> [APY] Fraxtal finished updating in ${(end - start) / 1000}s`); + + return { + apys, + apyBreakdowns, + }; +}; + +module.exports = { getFraxtalApys }; diff --git a/src/api/stats/getAmmPrices.ts b/src/api/stats/getAmmPrices.ts index 958315bfc..272f43ebe 100644 --- a/src/api/stats/getAmmPrices.ts +++ b/src/api/stats/getAmmPrices.ts @@ -613,6 +613,7 @@ const coinGeckoCoins: Record = { 'verified-usd-foundation-usdv': ['USDV'], 'stake-dao-crv': ['sdCRV'], 'kelp-dao-restaked-eth': ['rsETH'], + 'frax-ether': ['frxETH'], }; /** diff --git a/src/api/stats/getApys.js b/src/api/stats/getApys.js index 4a079f459..a60b90e2f 100644 --- a/src/api/stats/getApys.js +++ b/src/api/stats/getApys.js @@ -21,6 +21,7 @@ const { getBaseApys } = require('./base'); const { getGnosisApys } = require('./gnosis'); const { getLineaApys } = require('./linea'); const { getMantleApys } = require('./mantle'); +const { getFraxtalApys } = require('./fraxtal'); const { getKey, setKey } = require('../../utils/cache'); const { fetchBoostAprs } = require('./getBoostAprs'); @@ -70,6 +71,7 @@ const updateApys = async () => { getGnosisApys(), getLineaApys(), getMantleApys(), + getFraxtalApys(), ]); for (const result of results) { diff --git a/src/api/stats/getNonAmmPrices.ts b/src/api/stats/getNonAmmPrices.ts index 9c57ae242..ad6c7a23f 100644 --- a/src/api/stats/getNonAmmPrices.ts +++ b/src/api/stats/getNonAmmPrices.ts @@ -99,7 +99,7 @@ import getCurvePricesCommon from './common/curve/getCurvePricesCommon'; import getArbitrumSiloPrices from './arbitrum/getArbitrumSiloPrices'; import getAcrossPrices from './ethereum/getAcrossPrices'; import getGammaMoonbeamPrices from './moonbeam/getGammaMoonbeamPrices'; -import { GNOSIS_CHAIN_ID as GNO_CHAIN_ID } from '../../constants'; +import { FRAXTAL_CHAIN_ID as FRX_CHAIN_ID, GNOSIS_CHAIN_ID as GNO_CHAIN_ID } from '../../constants'; import getEthSiloPrices from './ethereum/getEthereumSiloPrices'; import getEthRangePrices from './ethereum/getEthRangePrices'; import getBscRangePrices from './bsc/getBscRangePrices'; @@ -210,6 +210,7 @@ export async function getNonAmmPrices(tokenPrices: Record): Prom getCurveKavaPrices(tokenPrices), getCurveCeloPrices(tokenPrices), getCurvePricesCommon(GNO_CHAIN_ID, require('../../data/gnosis/curvePools.json'), tokenPrices), + getCurvePricesCommon(FRX_CHAIN_ID, require('../../data/fraxtal/curvePools.json'), tokenPrices), getCurveBasePrices(tokenPrices), getConicPrices(), getRosePrices(tokenPrices), diff --git a/src/data/fraxtal/curvePools.json b/src/data/fraxtal/curvePools.json new file mode 100644 index 000000000..5c267e81a --- /dev/null +++ b/src/data/fraxtal/curvePools.json @@ -0,0 +1,91 @@ +[ + { + "name": "curve-fraxtal-crvusd-frax", + "pool": "0x63eb7846642630456707c3efbb50a03c79b89d81", + "gauge": "0x98a6c35546be6f7c545c99efb48f4673ed2c99fc", + "rewards": [ + { + "token": "0xFc00000000000000000000000000000000000002", + "oracleId": "FXS" + } + ], + "tokens": [ + { + "oracleId": "crvUSD", + "decimals": "1e18" + }, + { + "oracleId": "FRAX", + "decimals": "1e18" + } + ] + }, + { + "name": "curve-fraxtal-fraxusdc", + "pool": "0xa8eb7b41fe8df7ea3de982397ad183721784d987", + "gauge": "0xaa6ddba00de48d41e41543ef0a78ab31aae4de8d", + "rewards": [ + { + "token": "0xFc00000000000000000000000000000000000002", + "oracleId": "FXS" + } + ], + "tokens": [ + { + "oracleId": "FRAX", + "decimals": "1e18" + }, + { + "oracleId": "USDC", + "decimals": "1e6" + } + ] + }, + { + "name": "curve-fraxtal-trifxs", + "pool": "0xa0d3911349e701a1f49c1ba2dda34b4ce9636569", + "gauge": "0x8882eb84d0c4894753c0450f2d514e39883c0c82", + "rewards": [ + { + "token": "0xFc00000000000000000000000000000000000002", + "oracleId": "FXS" + } + ], + "tokens": [ + { + "oracleId": "FRAX", + "decimals": "1e18" + }, + { + "oracleId": "wfrxETH", + "decimals": "1e18" + }, + { + "oracleId": "FXS", + "decimals": "1e18" + } + ] + }, + { + "name": "curve-fraxtal-sfrxeth", + "pool": "0xf2f426fe123de7b769b2d4f8c911512f065225d3", + "gauge": "0xd1d981ddd0c9a0469e7d8cee877f83b5877d7260", + "rewards": [ + { + "token": "0xFc00000000000000000000000000000000000002", + "oracleId": "FXS" + } + ], + "getDy": ["v1", 0, 1], + "tokens": [ + { + "oracleId": "wfrxETH", + "decimals": "1e18" + }, + { + "oracleId": "sfrxETH", + "decimals": "1e18" + } + ] + } +] diff --git a/src/utils/fetchCurveTokenPrices.ts b/src/utils/fetchCurveTokenPrices.ts index e998d1b54..aabeb5b58 100644 --- a/src/utils/fetchCurveTokenPrices.ts +++ b/src/utils/fetchCurveTokenPrices.ts @@ -37,6 +37,7 @@ const tokens: Partial> = { }, ], optimism: toCurveTokens(ChainId.optimism, require('../data/optimism/curvePools.json')), + fraxtal: toCurveTokens(ChainId.fraxtal, require('../data/fraxtal/curvePools.json')), arbitrum: [ ...toCurveTokens(ChainId.arbitrum, require('../data/arbitrum/curvePools.json')), {