Skip to content
This repository was archived by the owner on Jun 8, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/apollo/generated/graphql-balancer-v3-codegen-generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15856,7 +15856,7 @@ export type GetTokenPriceQuery = {
};

export type TokenGetCurrentPricesQueryVariables = Exact<{
chains?: InputMaybe<Array<GqlChain> | GqlChain>;
chains: Array<GqlChain> | GqlChain;
}>;

export type TokenGetCurrentPricesQuery = {
Expand All @@ -15871,6 +15871,7 @@ export type TokenGetCurrentPricesQuery = {

export type GetDynamicTokenPricesQueryVariables = Exact<{
addresses: Array<Scalars["String"]["input"]> | Scalars["String"]["input"];
chain: GqlChain;
}>;

export type GetDynamicTokenPricesQuery = {
Expand Down Expand Up @@ -17588,7 +17589,7 @@ export type GetTokenPriceQueryResult = Apollo.QueryResult<
GetTokenPriceQueryVariables
>;
export const TokenGetCurrentPricesDocument = gql`
query TokenGetCurrentPrices($chains: [GqlChain!]) {
query TokenGetCurrentPrices($chains: [GqlChain!]!) {
tokenGetCurrentPrices(chains: $chains) {
address
chain
Expand Down Expand Up @@ -17648,8 +17649,8 @@ export type TokenGetCurrentPricesQueryResult = Apollo.QueryResult<
TokenGetCurrentPricesQueryVariables
>;
export const GetDynamicTokenPricesDocument = gql`
query GetDynamicTokenPrices($addresses: [String!]!) {
tokenGetTokensDynamicData(addresses: $addresses) {
query GetDynamicTokenPrices($addresses: [String!]!, $chain: GqlChain!) {
tokenGetTokensDynamicData(addresses: $addresses, chain: $chain) {
price
tokenAddress
priceChange24h
Expand Down
3 changes: 2 additions & 1 deletion src/components/Tables/AuraPoolLeaderboardTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { deepPurple } from '@mui/material/colors';
import { generateIdenticon } from '../../../utils/generateIdenticon';
import {useContractRead, useEnsName} from "wagmi";
import {ethers} from "ethers";
import {DRPC_ETHEREUM_URL} from "../../../data/balancer/constants";
import isDev from "../../../constants";
import StyledTableCell from "../StyledTableCell";

Expand Down Expand Up @@ -187,7 +188,7 @@ export default function AuraPoolLeaderboardTable({ leaderboardInfo }:

React.useEffect(() => {
if (leaderboardInfo && leaderboardInfo.leaderboard.length > 0) {
const provider = new ethers.providers.JsonRpcProvider('https://eth.llamarpc.com');
const provider = new ethers.providers.JsonRpcProvider(DRPC_ETHEREUM_URL);

const updateENSMap = async () => {
const ensLocalMap = { ...localEnsMap };
Expand Down
3 changes: 2 additions & 1 deletion src/components/Tables/AuraPoolStakerTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { deepPurple } from '@mui/material/colors';
import { generateIdenticon } from '../../../utils/generateIdenticon';
import {useContractRead, useEnsName} from "wagmi";
import {ethers} from "ethers";
import {DRPC_ETHEREUM_URL} from "../../../data/balancer/constants";
import isDev from "../../../constants";
import StyledTableCell from "../StyledTableCell";

Expand Down Expand Up @@ -186,7 +187,7 @@ export default function AuraPoolStakerTable({ leaderboardInfo, pricePerBPT }: {

React.useEffect(() => {
if (leaderboardInfo && leaderboardInfo.leaderboard.length > 0) {
const provider = new ethers.providers.JsonRpcProvider('https://eth.llamarpc.com');
const provider = new ethers.providers.JsonRpcProvider(DRPC_ETHEREUM_URL);

const updateENSMap = async () => {
const ensLocalMap = { ...localEnsMap };
Expand Down
3 changes: 2 additions & 1 deletion src/components/Tables/LockerTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {formatDollarAmount, formatNumber} from "../../../utils/numbers";
import {generateIdenticon} from "../../../utils/generateIdenticon";
import {deepPurple} from "@mui/material/colors";
import {ethers} from "ethers";
import {DRPC_ETHEREUM_URL} from "../../../data/balancer/constants";
import isDev from "../../../constants";
import StyledTableCell from "../StyledTableCell";

Expand Down Expand Up @@ -218,7 +219,7 @@ export default function LockerTable({

React.useEffect(() => {
if (lockerAccounts && lockerAccounts.length > 0) {
const provider = new ethers.providers.JsonRpcProvider('https://eth.llamarpc.com');
const provider = new ethers.providers.JsonRpcProvider(DRPC_ETHEREUM_URL);

const updateENSMap = async () => {
const ensLocalMap = { ...localEnsMap };
Expand Down
19 changes: 19 additions & 0 deletions src/constants/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,25 @@ export const AvalancheNetworkInfo: NetworkInfo = {
blurb: 'Beta'
}

/**
* Maps a NetworkInfo's chainId to the corresponding GqlChain string
* used by the Balancer V3 API. Falls back to the v3NetworkID field.
*/
const CHAIN_ID_TO_GQL_CHAIN: Record<string, string> = {
'1': 'MAINNET',
'42161': 'ARBITRUM',
'137': 'POLYGON',
'100': 'GNOSIS',
'1101': 'POLYGONZKEVM',
'10': 'OPTIMISM',
'8453': 'BASE',
'43114': 'AVALANCHE',
};

export function chainIdToGqlChain(chainId: string): string {
return CHAIN_ID_TO_GQL_CHAIN[chainId] ?? 'MAINNET';
}

export const SUPPORTED_NETWORK_VERSIONS: NetworkInfo[] = [
EthereumNetworkInfo,
ArbitrumNetworkInfo,
Expand Down
3 changes: 2 additions & 1 deletion src/data/VotingIncentives/useGetEmissionPerVote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {useActiveNetworkVersion} from "../../state/application/hooks";
import useGetSimpleTokenPrices from "../balancer-api-v3/useGetSimpleTokenPrices";
import useGetHistoricalTokenPrice from "../balancer-api-v3/useGetHistoricalTokenPrice";
import {GqlChain} from "../../apollo/generated/graphql-codegen-generated";
import {chainIdToGqlChain} from "../../constants/networks";
import {unixToDate} from "../../utils/date";

const auraAddress = AURA_TOKEN_MAINNET;
Expand All @@ -27,7 +28,7 @@ export const useGetEmissionPerVote = (timestampCurrentRound: number) => {
const [emissionValuePerVote, setEmissionValuePerVote] = useState(0);
const [emissionsPerDollarSpent, setEmissionsPerDollarSpent] = useState(0)
//const coinData = useCoinGeckoSimpleTokenPrices([auraAddress, balAddress]);
const coinData = useGetSimpleTokenPrices([auraAddress, balAddress], activeNetwork.chainId);
const coinData = useGetSimpleTokenPrices([auraAddress, balAddress], chainIdToGqlChain(activeNetwork.chainId) as GqlChain);
const { data: auraCompletePrice } = useAuraPrice();
const { data: historicalBALCoinData } = useGetHistoricalTokenPrice(balAddress, GqlChain.Mainnet)
const auraGlobalStats = useAuraGlobalStats();
Expand Down
14 changes: 3 additions & 11 deletions src/data/balancer-api-v3/BalancerV3ApiQueries.gql
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,16 @@ query VeBalGetVotingGauges {
}
}

query GetTokenPrice($address: String!, $chain: GqlChain!){
tokenGetPriceChartData(address: $address, chain: $chain, range: NINETY_DAY)
{
price
timestamp
}
}

query TokenGetCurrentPrices($chains: [GqlChain!]) {
query TokenGetCurrentPrices($chains: [GqlChain!]!) {
tokenGetCurrentPrices(chains: $chains) {
address
chain
price
}
}

query GetDynamicTokenPrices($addresses: [String!]!) {
tokenGetTokensDynamicData(addresses: $addresses) {
query GetDynamicTokenPrices($addresses: [String!]!, $chain: GqlChain!) {
tokenGetTokensDynamicData(addresses: $addresses, chain: $chain) {
price
tokenAddress
priceChange24h
Expand Down
14 changes: 5 additions & 9 deletions src/data/balancer-api-v3/useGetSimpleTokenPrices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@
import { balancerV3APIClient } from "../../apollo/client";
import {TokenPrices} from "../balancer/balancerTypes";
import {useGetDynamicTokenPricesQuery} from "../../apollo/generated/graphql-balancer-v3-codegen-generated";
import {GqlChain} from "../../apollo/generated/graphql-codegen-generated";

export default function useGetSimpleTokenPrices(addresses: string[], chainId: string) {
export default function useGetSimpleTokenPrices(addresses: string[], chain: GqlChain) {
const { data, loading, error } = useGetDynamicTokenPricesQuery({
client: balancerV3APIClient,
variables: {
addresses: addresses
addresses: addresses,
chain: chain,
},
context: {
headers: {
chainId: chainId
}
}
});

// Transform the array of token data into an object indexed by tokenAddress
Expand All @@ -27,10 +24,9 @@ export default function useGetSimpleTokenPrices(addresses: string[], chainId: st
return acc;
}, {} as TokenPrices) ?? {};

//console.log("tokenData", tokenPrices);
return {
loading,
error,
data: tokenPrices, // Return the mapped data
data: tokenPrices,
};
}
36 changes: 36 additions & 0 deletions src/data/balancer-api-v3/useGetTokenPriceWithChange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { GqlChain } from "../../apollo/generated/graphql-codegen-generated";
import { balancerV3APIClient } from "../../apollo/client";
import { useGetDynamicTokenPricesQuery } from "../../apollo/generated/graphql-balancer-v3-codegen-generated";
import useGetCurrentTokenPrices from "./useGetCurrentTokenPrices";

export interface TokenPriceWithChange {
price: number;
priceChange24h: number; // percentage
}

export default function useGetTokenPriceWithChange(
address: string,
chain: GqlChain = "MAINNET" as GqlChain,
): TokenPriceWithChange | undefined {
const { data: currentPrices } = useGetCurrentTokenPrices([chain]);
const { data: dynamicData } = useGetDynamicTokenPricesQuery({
client: balancerV3APIClient,
variables: { addresses: [address], chain },
});

const basePrice = currentPrices?.find(
t => t.address.toLowerCase() === address.toLowerCase()
);
if (!basePrice) return undefined;

const dynamicToken = dynamicData?.tokenGetTokensDynamicData?.find(
d => d.tokenAddress.toLowerCase() === address.toLowerCase()
);

const absoluteChange = dynamicToken?.priceChange24h ?? 0;
const price24hAgo = basePrice.price - absoluteChange;
const priceChangePercent = price24hAgo !== 0
? (absoluteChange / price24hAgo) * 100 : 0;

return { price: basePrice.price, priceChange24h: priceChangePercent };
}
6 changes: 3 additions & 3 deletions src/data/balancer/useDecorateL1Gauges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import rootGaugeL2 from "../../constants/abis/rootGaugeL2.json";
import {useEffect, useState} from "react";
import {Multicall} from 'ethereum-multicall';
import {EthereumNetworkInfo} from "../../constants/networks";
import {DRPC_ETHEREUM_URL} from "./constants";
import {useAccount} from 'wagmi';

const useDecorateL1Gauges = (stakingGaugeData: BalancerStakingGauges[] | undefined): BalancerStakingGauges[] => {
Expand All @@ -19,14 +20,13 @@ const useDecorateL1Gauges = (stakingGaugeData: BalancerStakingGauges[] | undefin
if (gaugeData && gaugeData.length > 0) {
const multicalls = [];

const providerUrl = 'https://eth.llamarpc.com';
const multicall = new Multicall({
ethersProvider: new ethers.providers.JsonRpcProvider(providerUrl),
ethersProvider: new ethers.providers.JsonRpcProvider(DRPC_ETHEREUM_URL),
tryAggregate: true
});

const multicallRoots = new Multicall({
ethersProvider: new ethers.providers.JsonRpcProvider('https://eth.llamarpc.com'),
ethersProvider: new ethers.providers.JsonRpcProvider(DRPC_ETHEREUM_URL),
tryAggregate: true
});
//Obtain mainnet gauge working and total supplies
Expand Down
76 changes: 17 additions & 59 deletions src/data/balancer/useTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { BalancerChartDataItem, TokenData } from './balancerTypes';
import { useActiveNetworkVersion } from '../../state/application/hooks';
import { useState } from 'react';
import useGetSimpleTokenPrices from "../balancer-api-v3/useGetSimpleTokenPrices";
import {chainIdToGqlChain} from "../../constants/networks";
import {GqlChain} from "../../apollo/generated/graphql-codegen-generated";
import {CG_KEY} from "./constants";

//Coingecko Token price Interface
Expand Down Expand Up @@ -78,7 +80,7 @@ export function useBalancerTokens(first = 100) {
const [block24, block48, blockWeek] = blocks ?? [];
const [getTokenData, { data }] = useGetTokenDataLazyQuery();
const tokenAddresses = data?.tokens.map(token => token.address) ?? [];
const { data: tokenPrices, loading: pricesLoading, error: pricesError } = useGetSimpleTokenPrices(tokenAddresses, activeNetwork.chainId);
const { data: tokenPrices, loading: pricesLoading, error: pricesError } = useGetSimpleTokenPrices(tokenAddresses, chainIdToGqlChain(activeNetwork.chainId) as GqlChain);

useEffect(() => {
if (block24) {
Expand Down Expand Up @@ -154,8 +156,12 @@ export function useBalancerTokenSingleData(address: string): TokenData | null {
const { blocks, error: blockError } = useBlocksFromTimestamps([t24, t48, tWeek]);
const [block24, block48, blockWeek] = blocks ?? [];
const [getTokenData, { data }] = useGetTokenSingleDataLazyQuery();
const tokenAddresses: Array<string> = [];
const [coingeckoData, setCoingeckoData] = useState<CoingeckoRawData>();

// Use V3 API for real 24h price change
const { data: tokenPrices } = useGetSimpleTokenPrices(
[address],
chainIdToGqlChain(activeNetwork.chainId) as GqlChain
);

useEffect(() => {
if (block24) {
Expand All @@ -171,71 +177,23 @@ export function useBalancerTokenSingleData(address: string): TokenData | null {
}
}, [block24]);

useEffect(() => {
//V2: repopulate formatted token data with coingecko data
if (data && data.tokens.length === 1) {
data.tokens.forEach(token => {
tokenAddresses.push(token.address);
})

const getTokenPrices = async (addresses: string) => {
const baseURI = 'https://api.coingecko.com/api/v3/simple/token_price/';
const queryParams = activeNetwork.coingeckoId + '?contract_addresses=' + addresses +
'&vs_currencies=usd&include_24hr_change=true' + '&x_cg_demo_api_key=' + CG_KEY;
try {
const coingeckoResponse = await fetch(baseURI + queryParams);
const json = await coingeckoResponse.json();
//TODO: find way to append to interface object?
const spread = {
...coingeckoData,
json
}
setCoingeckoData(json);
} catch {
console.log("Coingecko: token_price API not reachable")
}
}
const tokenAddresses1 = tokenAddresses.slice(1, 150);
const tokenAddresses2 = tokenAddresses.slice(151, 300);
//raw batch call in hook:
let addressesString1 = '';
tokenAddresses1.forEach(el => {
addressesString1 = addressesString1 + el + ','
})

getTokenPrices(addressesString1);

let addressesString2 = '';
tokenAddresses2.forEach(el => {
addressesString2 = addressesString2 + el + ','
})

//getTokenPrices(addressesString2);
}
}, [data]);

if (!data || (data.tokens && data.tokens.length === 0)) {
return null;
}

const { tokens, tokens24 } = data;

//const singleToken = tokens.find(t => t.address === address)
//const singleToken24 = tokens.find(t => t.address === address)

let tokenData = getTokenValues(tokens[0].address, tokens);
let tokenData24 = getTokenValues(tokens[0].address, tokens24);

let priceData = { price: tokens[0].latestUSDPrice ? Number(tokens[0].latestUSDPrice) : 0 };
let priceData24 = getTokenPriceValues(tokens[0].address, tokens24);
//override:
let priceChange = 0
if (coingeckoData && coingeckoData[tokens[0].address]) {
tokenData = getTokenValues(tokens[0].address, tokens, coingeckoData);
tokenData24 = getTokenValues(tokens[0].address, tokens24, coingeckoData);
priceData = getTokenPriceValues(tokens[0].address, tokens24, coingeckoData);
priceData24 = getTokenPriceValues(tokens[0].address, tokens24, coingeckoData);
priceChange = coingeckoData[tokens[0].address].usd_24h_change;

// Override with V3 API price data if available
let priceChange = 0;
if (tokenPrices && tokenPrices[tokens[0].address]) {
const { price, priceChangePercentage24h } = tokenPrices[tokens[0].address];
priceData.price = price;
priceChange = priceChangePercentage24h;
}

const valueUSDCollected = 0;
Expand All @@ -255,7 +213,7 @@ export function useBalancerTokenSingleData(address: string): TokenData | null {
tvlUSDChange: (tokenData.tvl - tokenData24.tvl) / tokenData24.tvl,
priceUSD: priceData.price,
priceUSDChange: priceChange,
isCoingeckoPriceSource: priceChange !== 0 ? true : false,
isCoingeckoPriceSource: false,
};
}

Expand Down
3 changes: 2 additions & 1 deletion src/pages/AuraBAL/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import AuraBALMultiAreaChart from "../../components/Echarts/auraBAL/AuraBALMulti
import {ArbitrumNetworkInfo, EthereumNetworkInfo, PolygonNetworkInfo} from "../../constants/networks";
import React from "react";
import useGetSimpleTokenPrices from "../../data/balancer-api-v3/useGetSimpleTokenPrices";
import {GqlChain} from "../../apollo/generated/graphql-codegen-generated";
import {isMobile} from "react-device-detect";


Expand Down Expand Up @@ -72,7 +73,7 @@ export default function AuraBAL() {
startTimeStamp = 1690495200
}
//const coinData = useCoinGeckoSimpleTokenPrices([auraBALMainnet], true);
const coinData = useGetSimpleTokenPrices([auraBALMainnet], '1');
const coinData = useGetSimpleTokenPrices([auraBALMainnet], "MAINNET" as GqlChain);
//Image banner resources
const auraBalBannerDark = require('../../assets/png/aurabal-dark.png');
const auraBalBannerLight = require('../../assets/png/aurabal-light.png');
Expand Down
Loading