diff --git a/modules/delegates/api/fetchChainDelegates.ts b/modules/delegates/api/fetchChainDelegates.ts index 510f8bf41..9f5e9186a 100644 --- a/modules/delegates/api/fetchChainDelegates.ts +++ b/modules/delegates/api/fetchChainDelegates.ts @@ -19,7 +19,7 @@ export async function fetchChainDelegates( const chainId = networkNameToChainId(network); const data = await gqlRequest({ chainId, - query: allDelegates + query: allDelegates(chainId) }); return data.delegates.map(d => { @@ -30,9 +30,8 @@ export async function fetchChainDelegates( return { blockTimestamp, address: d.ownerAddress, - voteDelegateAddress: d.id, + voteDelegateAddress: d.address, skyDelegated: formatEther(BigInt(totalDelegated)), - delegations: d.delegations || [], // Include current delegations from subgraph lastVoteDate: d.voter?.lastVotedTimestamp ? Number(d.voter.lastVotedTimestamp) : null }; }); diff --git a/modules/delegates/api/fetchDelegateAddresses.ts b/modules/delegates/api/fetchDelegateAddresses.ts index 4f2372f60..d8ba81b40 100644 --- a/modules/delegates/api/fetchDelegateAddresses.ts +++ b/modules/delegates/api/fetchDelegateAddresses.ts @@ -17,13 +17,13 @@ export async function fetchDelegateAddresses(network: SupportedNetworks): Promis const data = await gqlRequest({ chainId, - query: allDelegates + query: allDelegates(chainId) }); const delegates = data.delegates.map(delegate => ({ blockTimestamp: new Date(Number(delegate?.blockTimestamp || 0) * 1000), delegate: delegate?.ownerAddress, - voteDelegate: delegate?.id + voteDelegate: delegate?.address })) as AllDelegatesEntry[]; cacheSet(allDelegateAddressesKey, JSON.stringify(delegates), network, ONE_HOUR_IN_MS); diff --git a/modules/delegates/api/fetchDelegatePaginatedDelegations.ts b/modules/delegates/api/fetchDelegatePaginatedDelegations.ts index 39ba6eb92..838833bc0 100644 --- a/modules/delegates/api/fetchDelegatePaginatedDelegations.ts +++ b/modules/delegates/api/fetchDelegatePaginatedDelegations.ts @@ -28,35 +28,37 @@ export async function fetchDelegatePaginatedDelegations( const delegateId = delegateAddress.toLowerCase(); const chainId = networkNameToChainId(network); const stakingEngineAddresses = [stakingEngineAddressMainnet, stakingEngineAddressTestnet]; - + const response = await gqlRequest({ chainId, - query: delegateWithPaginatedDelegations, - variables: { - id: delegateId, - first: limit, - skip: offset, - orderBy: 'amount', - orderDirection: 'desc', - excludeAddresses: stakingEngineAddresses, + query: delegateWithPaginatedDelegations( + chainId, + delegateId, + limit, + offset, + 'amount', + 'desc', + stakingEngineAddresses, stakingEngineAddresses - } + ) }); - if (!response.delegate || !response.delegate.delegations) { + const delegate = response.delegate?.[0]; + + if (!delegate || !delegate.delegations) { return { delegations: [], total: 0 }; } - const formattedDelegations = formatCurrentDelegations(response.delegate.delegations); - const totalDelegators = response.delegate.delegators || 0; - const hasStakingEngine = response.delegate.stakingEngineDelegations?.length > 0; + const formattedDelegations = formatCurrentDelegations(delegate.delegations); + const totalDelegators = delegate.delegators || 0; + const hasStakingEngine = delegate.stakingEngineDelegations?.length > 0; const adjustedTotal = hasStakingEngine ? Math.max(0, totalDelegators - 1) : totalDelegators; return { delegations: formattedDelegations, total: adjustedTotal }; -} \ No newline at end of file +} diff --git a/modules/delegates/api/fetchDelegatedTo.ts b/modules/delegates/api/fetchDelegatedTo.ts index 1bccc9fbc..dbac0bcee 100644 --- a/modules/delegates/api/fetchDelegatedTo.ts +++ b/modules/delegates/api/fetchDelegatedTo.ts @@ -24,19 +24,18 @@ export async function fetchDelegatedTo( const chainId = networkNameToChainId(network); const delegatesData = await gqlRequest({ chainId, - query: allDelegates + query: allDelegates(chainId) }); const delegates = delegatesData.delegates; // Returns the records with the aggregated delegated data const data = await gqlRequest({ - chainId: networkNameToChainId(network), - query: delegatorHistory, - variables: { address: address.toLowerCase() } + chainId, + query: delegatorHistory(chainId, address.toLowerCase()) }); const res: SKYDelegatedToResponse[] = data.delegationHistories.map(x => { return { - delegateContractAddress: x.delegate.id, + delegateContractAddress: x.delegate.address, lockAmount: x.amount, blockTimestamp: new Date(parseInt(x.timestamp) * 1000).toISOString(), hash: x.txnHash, @@ -63,7 +62,7 @@ export async function fetchDelegatedTo( }); } else { const delegatingTo = delegates.find( - i => i?.id?.toLowerCase() === delegateContractAddress.toLowerCase() + i => i?.address?.toLowerCase() === delegateContractAddress.toLowerCase() ); if (!delegatingTo) { diff --git a/modules/delegates/api/fetchDelegates.ts b/modules/delegates/api/fetchDelegates.ts index ff4321b3a..7c9502791 100644 --- a/modules/delegates/api/fetchDelegates.ts +++ b/modules/delegates/api/fetchDelegates.ts @@ -62,7 +62,6 @@ function mergeDelegateInfo({ skyDelegated: onChainDelegate.skyDelegated, proposalsSupported: onChainDelegate.proposalsSupported, execSupported: undefined, - delegations: onChainDelegate.delegations, // Include current delegations from subgraph blockTimestamp: onChainDelegate.blockTimestamp }; } @@ -172,6 +171,11 @@ export async function fetchDelegatesInfo( return delegatesInfo; } +// Helper to build Hasura where condition strings for delegate filters +function buildDelegateWhereConditions(baseConditions: string[], additionalConditions: string[]): string[] { + return [...baseConditions, ...additionalConditions]; +} + export async function fetchDelegatesPaginated({ network, pageSize, @@ -195,60 +199,70 @@ export async function fetchDelegatesPaginated({ const { alignedDelegatesCount, shadowDelegatesCount, totalDelegatesCount } = getDelegatesCounts(filteredDelegateEntries); - // If there are no aligned delegates, the id_not_in filter will filter out everything if we give it an empty array + // If there are no aligned delegates, the _nin filter will filter out everything if we give it an empty array const alignedDelegatesAddressesForNotInQuery = alignedDelegatesAddresses.length > 0 ? alignedDelegatesAddresses : ['0x0000000000000000000000000000000000000000']; - const baseDelegatesQueryFilter: any = { and: [{ version: '3' }] }; + // Build Hasura where conditions + // Note: Envio entity IDs are prefixed with chainId (e.g. "1-0xabc..."), so we must prefix addresses when filtering by id + // We use _ilike/_nilike for case-insensitive address matching since Envio stores addresses with inconsistent casing + const ilikeId = (a: string) => `{ id: { _ilike: "${chainId}-${a}" } }`; + const nilikeId = (a: string) => `{ id: { _nilike: "${chainId}-${a}" } }`; + const baseConditions: string[] = ['{ version: { _eq: "3" } }']; if (searchTerm) { - baseDelegatesQueryFilter.and.push({ id_in: filteredDelegateAddresses }); + const addrs = filteredDelegateAddresses.map(ilikeId).join(', '); + baseConditions.push(`{ _or: [${addrs}] }`); if (delegateType === DelegateTypeEnum.ALIGNED) { - baseDelegatesQueryFilter.and.push({ id_in: alignedDelegatesAddresses }); - baseDelegatesQueryFilter.and.push({ id_not_in: alignedDelegatesAddressesForNotInQuery }); + const aligned = alignedDelegatesAddresses.map(ilikeId).join(', '); + baseConditions.push(`{ _or: [${aligned}] }`); + const notIn = alignedDelegatesAddressesForNotInQuery.map(nilikeId).join(', '); + baseConditions.push(`{ _and: [${notIn}] }`); } } else if (delegateType === DelegateTypeEnum.ALIGNED) { - baseDelegatesQueryFilter.and.push({ id_in: alignedDelegatesAddresses }); + const aligned = alignedDelegatesAddresses.map(ilikeId).join(', '); + baseConditions.push(`{ _or: [${aligned}] }`); } else if (delegateType === DelegateTypeEnum.SHADOW) { - baseDelegatesQueryFilter.and.push({ id_not_in: alignedDelegatesAddressesForNotInQuery }); + const notIn = alignedDelegatesAddressesForNotInQuery.map(nilikeId).join(', '); + baseConditions.push(`{ _and: [${notIn}] }`); } - //get all aligned delegates (that match the filter)for the first page - const alignedFilterFirstPage = { - and: [...(baseDelegatesQueryFilter.and || []), { id_in: alignedDelegatesAddresses }] - }; - //use this for subsequent pages as well as part of the first page - const shadowFilterFirstPage = { - and: [...(baseDelegatesQueryFilter.and || []), { id_not_in: alignedDelegatesAddressesForNotInQuery }] - }; + const alignedCondition = `{ _or: [${alignedDelegatesAddresses.map(ilikeId).join(', ')}] }`; + const shadowCondition = `{ _and: [${alignedDelegatesAddressesForNotInQuery + .map(nilikeId) + .join(', ')}] }`; - const queryOrderBy = orderBy === DelegateOrderByEnum.RANDOM ? DelegateOrderByEnum.SKY : orderBy; + const alignedWhereConditions = buildDelegateWhereConditions(baseConditions, [alignedCondition]); + const shadowWhereConditions = buildDelegateWhereConditions(baseConditions, [shadowCondition]); - const delegatesQueryFirstPageVariables = { - first: pageSize, - orderBy: queryOrderBy, - orderDirection, - alignedFilter: alignedFilterFirstPage, - shadowFilter: shadowFilterFirstPage, - alignedDelegates: alignedDelegatesAddresses - }; + const queryOrderBy = orderBy === DelegateOrderByEnum.RANDOM ? DelegateOrderByEnum.SKY : orderBy; - const delegatesQuerySubsequentPagesVariables = { - first: pageSize, - skip: (page - 1) * pageSize, - orderBy: queryOrderBy, - orderDirection, - filter: shadowFilterFirstPage - }; + const query = + page === 1 + ? delegatesQueryFirstPage({ + chainId, + limit: pageSize, + orderBy: queryOrderBy, + orderDirection, + shadowWhereConditions, + alignedWhereConditions + }) + : delegatesQuerySubsequentPages({ + chainId, + limit: pageSize, + offset: (page - 1) * pageSize, + orderBy: queryOrderBy, + orderDirection, + whereConditions: shadowWhereConditions + }); const [githubExecutives, delegatesExecSupport, delegatesQueryRes, delegationMetrics] = await Promise.all([ getGithubExecutives(network), fetchDelegatesExecSupport(network), gqlRequest({ chainId, - query: page === 1 ? delegatesQueryFirstPage : delegatesQuerySubsequentPages, - variables: page === 1 ? delegatesQueryFirstPageVariables : delegatesQuerySubsequentPagesVariables + query }), fetchDelegationMetrics(network) ]); @@ -264,14 +278,15 @@ export async function fetchDelegatesPaginated({ delegate.ownerAddress.toLowerCase() ); + const gaslessChainId = networkNameToChainId(getGaslessNetwork(network)); const lastVotedArbitrumArray = await gqlRequest({ - chainId: networkNameToChainId(getGaslessNetwork(network)), - query: lastVotedArbitrum, - variables: { argAddresses: combinedDelegateOwnerAddresses } + chainId: gaslessChainId, + query: lastVotedArbitrum(gaslessChainId, combinedDelegateOwnerAddresses) }); const lastVotedArbitrumObj = lastVotedArbitrumArray.arbitrumVoters.reduce((acc, voter) => { - acc[voter.id] = voter.pollVotes && voter.pollVotes.length > 0 ? Number(voter.pollVotes[0].blockTime) : 0; + const address = voter.address; + acc[address] = voter.pollVotes && voter.pollVotes.length > 0 ? Number(voter.pollVotes[0].blockTime) : 0; return acc; }, {}); @@ -295,12 +310,13 @@ export async function fetchDelegatesPaginated({ totalDelegators: delegationMetrics.delegatorCount }, delegates: combinedDelegates.map(delegate => { - const allDelegatesEntry = allDelegatesWithNamesAndLinks.find(del => del.voteDelegate === delegate.id); + const delegateId = delegate.address; + const allDelegatesEntry = allDelegatesWithNamesAndLinks.find(del => del.voteDelegate === delegateId); const githubDelegate = githubDelegates?.find(ghDelegate => ghDelegate.name === allDelegatesEntry?.name); const votedProposals = delegatesExecSupport.data?.find( - del => del.voteDelegate === delegate.id + del => del.voteDelegate === delegateId )?.votedProposals; const execSupported = githubExecutives.find(proposal => votedProposals?.find(vp => vp.toLowerCase() === proposal?.address?.toLowerCase()) @@ -335,21 +351,16 @@ export async function fetchDelegatesPaginated({ const lastVoteTimestamp = Math.max(lastVoteMainnet, lastVoteArbitrum); - const totalDelegated: bigint = delegate.delegations.reduce( - (acc, curr) => acc + BigInt(curr?.amount || 0n), - 0n - ); - return { name: githubDelegate?.name || 'Shadow Delegate', - voteDelegateAddress: delegate.id, + voteDelegateAddress: delegateId, address: delegate.ownerAddress, status: githubDelegate ? DelegateStatusEnum.aligned : DelegateStatusEnum.shadow, creationDate: finalCreationDate, picture: githubDelegate?.picture, communication: githubDelegate?.communication, combinedParticipation: githubDelegate?.combinedParticipation, - skyDelegated: formatEther(totalDelegated), + skyDelegated: formatEther(BigInt(delegate.totalDelegated || '0')), delegatorCount: delegate.delegators, lastVoteDate: lastVoteTimestamp > 0 ? new Date(lastVoteTimestamp * 1000) : null, proposalsSupported: votedProposals?.length || 0, diff --git a/modules/delegates/api/fetchDelegatesExecSupport.ts b/modules/delegates/api/fetchDelegatesExecSupport.ts index 36e865991..8e22d1d23 100644 --- a/modules/delegates/api/fetchDelegatesExecSupport.ts +++ b/modules/delegates/api/fetchDelegatesExecSupport.ts @@ -7,6 +7,7 @@ import { networkNameToChainId } from 'modules/web3/helpers/chain'; import logger from 'lib/logger'; import { DelegateExecSupport } from '../types'; import { TEN_MINUTES_IN_MS } from 'modules/app/constants/time'; +import { stripChainIdPrefix } from 'modules/gql/gqlUtils'; export async function fetchDelegatesExecSupport(network: SupportedNetworks): Promise<{ error: boolean; @@ -25,12 +26,12 @@ export async function fetchDelegatesExecSupport(network: SupportedNetworks): Pro const data = await gqlRequest({ chainId, - query: allDelegatesExecSupport + query: allDelegatesExecSupport(chainId) }); const delegatesExecSupport: DelegateExecSupport[] = data.delegates.map(delegate => ({ - voteDelegate: delegate.id, - votedProposals: delegate.voter.currentSpellsV2.map(spell => spell.id) + voteDelegate: delegate.address, + votedProposals: (delegate.voter?.currentSpellsV2 || []).map(stripChainIdPrefix) })); cacheSet(allDelegatesExecSupportKey, JSON.stringify(delegatesExecSupport), network, TEN_MINUTES_IN_MS); diff --git a/modules/delegates/api/fetchDelegationEventsByAddresses.ts b/modules/delegates/api/fetchDelegationEventsByAddresses.ts index c98703308..66b2979e0 100644 --- a/modules/delegates/api/fetchDelegationEventsByAddresses.ts +++ b/modules/delegates/api/fetchDelegationEventsByAddresses.ts @@ -22,19 +22,16 @@ export async function fetchDelegationEventsByAddresses( const engine = network === SupportedNetworks.TENDERLY ? stakingEngineAddressTestnet : stakingEngineAddressMainnet; try { + const chainId = networkNameToChainId(network); const data = await gqlRequest({ - chainId: networkNameToChainId(network), - query: delegateHistoryArray, - variables: { - delegates: addresses, - engines: [engine.toLowerCase()] - } + chainId, + query: delegateHistoryArray(chainId, addresses, [engine.toLowerCase()]) }); const flattenedData = data.delegates.flatMap(delegate => delegate.delegationHistory); const addressData: SkyLockedDelegateApiResponse[] = flattenedData.map(x => { return { - delegateContractAddress: x.delegate.id, + delegateContractAddress: x.delegate.address, immediateCaller: x.delegator, lockAmount: formatEther(x.amount), blockNumber: x.blockNumber, diff --git a/modules/delegates/api/fetchDelegationEventsByUser.ts b/modules/delegates/api/fetchDelegationEventsByUser.ts index 79c091fab..af6d66917 100644 --- a/modules/delegates/api/fetchDelegationEventsByUser.ts +++ b/modules/delegates/api/fetchDelegationEventsByUser.ts @@ -20,24 +20,23 @@ export async function fetchDelegationEventsByUser( network: SupportedNetworks ): Promise { try { + const chainId = networkNameToChainId(network); const data = await gqlRequest({ - chainId: networkNameToChainId(network), - query: userDelegationToDelegate, - variables: { - delegate: delegateAddress.toLowerCase(), - delegator: userAddress.toLowerCase() - } + chainId, + query: userDelegationToDelegate(chainId, delegateAddress.toLowerCase(), userAddress.toLowerCase()) }); - - if (!data.delegate) { + + const delegate = data.delegate?.[0]; + + if (!delegate) { return []; } - - const delegationHistory = data.delegate.delegationHistory; + + const delegationHistory = delegate.delegationHistory; const addressData: SkyLockedDelegateApiResponse[] = delegationHistory.map(x => { return { - delegateContractAddress: x.delegate.id, + delegateContractAddress: x.delegate.address, immediateCaller: x.delegator, lockAmount: formatEther(x.amount), blockNumber: x.blockNumber, @@ -52,4 +51,4 @@ export async function fetchDelegationEventsByUser( logger.error('fetchDelegationEventsByUser: Error fetching delegation events', e.message); return []; } -} \ No newline at end of file +} diff --git a/modules/delegates/api/fetchDelegationMetrics.ts b/modules/delegates/api/fetchDelegationMetrics.ts index eb1fda3fa..38b541c03 100644 --- a/modules/delegates/api/fetchDelegationMetrics.ts +++ b/modules/delegates/api/fetchDelegationMetrics.ts @@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ import { gqlRequest } from 'modules/gql/gqlRequest'; -import { allDelegationsPaginated } from 'modules/gql/queries/subgraph/allDelegations'; +import { allDelegates } from 'modules/gql/queries/subgraph/allDelegates'; import { SupportedNetworks } from 'modules/web3/constants/networks'; import { networkNameToChainId } from 'modules/web3/helpers/chain'; import { formatEther } from 'viem'; @@ -17,44 +17,26 @@ interface DelegationMetrics { delegatorCount: number; } -interface Delegation { - delegator: string; - delegate: { - id: string; - version: string; - }; - amount: string; +interface Delegate { + totalDelegated: string; + delegators: number; } export async function fetchDelegationMetrics(network: SupportedNetworks): Promise { const chainId = networkNameToChainId(network); - const pageSize = 1000; - let skip = 0; - let hasMore = true; - const allDelegations: Delegation[] = []; - - // Fetch all delegations using pagination - while (hasMore) { - const res = await gqlRequest({ - chainId, - query: allDelegationsPaginated, - variables: { - first: pageSize, - skip - } - }); - - const delegations = res.delegations || []; - allDelegations.push(...delegations); - - // Check if there are more results to fetch - hasMore = delegations.length === pageSize; - skip += pageSize; - } - - // Calculate metrics from all delegations - const totalSkyDelegated = formatEther(allDelegations.reduce((acc, cur) => acc + BigInt(cur.amount), 0n)); - const delegatorCount = allDelegations.filter(d => BigInt(d.amount) > 0n).length; + + const res = await gqlRequest<{ delegates: Delegate[] }>({ + chainId, + query: allDelegates(chainId) + }); + + const delegates = res.delegates || []; + + // Sum totalDelegated and delegators across all delegates + const totalSkyDelegated = formatEther( + delegates.reduce((acc, cur) => acc + BigInt(cur.totalDelegated || '0'), 0n) + ); + const delegatorCount = delegates.reduce((acc, cur) => acc + (cur.delegators || 0), 0); return { totalSkyDelegated, diff --git a/modules/delegates/types/delegate.d.ts b/modules/delegates/types/delegate.d.ts index 7d2a64419..3e1bb63b4 100644 --- a/modules/delegates/types/delegate.d.ts +++ b/modules/delegates/types/delegate.d.ts @@ -53,7 +53,6 @@ export type DelegateContractInformation = { blockTimestamp: string; skyDelegated: string; proposalsSupported: number; - delegations?: { delegator: string; amount: string }[]; // current delegations from subgraph lastVoteDate: number | null; }; @@ -72,7 +71,6 @@ export type Delegate = { skyDelegated: string; proposalsSupported: number; execSupported: CMSProposal | undefined; - delegations?: { delegator: string; amount: string }[]; // current delegations from subgraph blockTimestamp: string; }; diff --git a/modules/executive/api/fetchExecutiveVoteTallyWithSubgraph.ts b/modules/executive/api/fetchExecutiveVoteTallyWithSubgraph.ts index 0fc182825..f1bc89f1a 100644 --- a/modules/executive/api/fetchExecutiveVoteTallyWithSubgraph.ts +++ b/modules/executive/api/fetchExecutiveVoteTallyWithSubgraph.ts @@ -14,37 +14,37 @@ import { formatEther } from 'viem'; export async function fetchExecutiveVoteTallyWithSubgraph(network: SupportedNetworks): Promise>> { + const chainId = networkNameToChainId(network); const pageSize = 1000; let allData: any[] = []; let skip = 0; let hasMoreData = true; - + while (hasMoreData) { const response = await gqlRequest({ - chainId: networkNameToChainId(network), - query: allSpellVotes, - variables: { argSkip: skip, argFirst: pageSize } + chainId, + query: allSpellVotes(chainId, skip, pageSize) }); - + const currentPageData = response.executiveVoteV2S || []; allData = [...allData, ...currentPageData]; - + if (currentPageData.length < pageSize) { - hasMoreData = false; + hasMoreData = false; } else { skip += pageSize; } } - + // Find most recent vote(s) for each voter const latestVotesByVoter: Record = {}; - + for (const vote of allData) { - const voterId = vote.voter?.id; + const voterId = vote.voter?.address; const blockTime = vote.blockTime || '0'; - + if (!voterId) continue; - + if (!latestVotesByVoter[voterId] || blockTime > latestVotesByVoter[voterId].blockTime) { // This is a newer vote, replace previous votes latestVotesByVoter[voterId] = { @@ -57,24 +57,24 @@ export async function fetchExecutiveVoteTallyWithSubgraph(network: SupportedNetw } // Older votes are ignored } - + const mostRecentVotes = Object.values(latestVotesByVoter).flatMap(item => item.votes); - + //group by spell with voter details const formattedData: Record> = {}; - + for (const vote of mostRecentVotes) { - const spellId = vote.spell?.id; - const voterId = vote.voter?.id; + const spellId = vote.spell?.address; + const voterId = vote.voter?.address; const newBalance = vote.voter?.v2VotingPowerChanges?.[0]?.newBalance || '0'; - + const formattedDeposit = formatEther(BigInt(newBalance)); - + if (spellId && voterId && newBalance !== undefined) { if (!formattedData[spellId]) { formattedData[spellId] = []; } - + formattedData[spellId].push({ address: voterId, deposits: formattedDeposit, @@ -82,16 +82,16 @@ export async function fetchExecutiveVoteTallyWithSubgraph(network: SupportedNetw }); } } - + // Calculate percentage for each voter for (const spellId in formattedData) { const voters = formattedData[spellId]; - + // Calculate total deposits for this spell using regular numbers const totalDeposits = voters.reduce((sum, voter) => { return sum + Number(voter.deposits); }, 0); - + // Add percentage to each voter if (totalDeposits > 0) { for (const voter of voters) { @@ -100,12 +100,12 @@ export async function fetchExecutiveVoteTallyWithSubgraph(network: SupportedNetw voter.percent = ((voterDeposits * 100) / totalDeposits).toFixed(2); } } - + // Sort voters by deposit amount in descending order formattedData[spellId].sort((a, b) => { return Number(b.deposits) - Number(a.deposits); }); - + } return formattedData; } diff --git a/modules/gql/gql.constants.ts b/modules/gql/gql.constants.ts index 3639e5953..071d3d5f4 100644 --- a/modules/gql/gql.constants.ts +++ b/modules/gql/gql.constants.ts @@ -6,20 +6,12 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -/* Subgraph URLs */ +/* Envio HyperIndex URLs */ -export const TENDERLY_SUBGRAPH_URL = - 'https://query-subgraph-staging.sky.money/subgraphs/name/jetstreamgg/sky-subgraph-testnet'; -export const MAINNET_STAGING_SUBGRAPH_URL = - 'https://query-subgraph-staging.sky.money/subgraphs/name/jetstreamgg/sky-subgraph-mainnet'; -export const MAINNET_PROD_SUBGRAPH_URL = - 'https://query-subgraph.sky.money/subgraphs/name/jetstreamgg/sky-subgraph-mainnet'; -export const ARBITRUM_TENDERLY_SUBGRAPH_URL = - 'https://query-subgraph-staging.sky.money/subgraphs/name/jetstreamgg/sky-subgraph-arbitrum-testnet'; -export const ARBITRUM_STAGING_SUBGRAPH_URL = - 'https://query-subgraph-staging.sky.money/subgraphs/name/jetstreamgg/sky-subgraph-arbitrum'; -export const ARBITRUM_PROD_SUBGRAPH_URL = - 'https://query-subgraph.sky.money/subgraphs/name/jetstreamgg/sky-subgraph-arbitrum'; +const ENVIO_HYPERINDEX_URL = 'https://indexer.dev.hyperindex.xyz/8f55a37/v1/graphql'; + +export const STAGING_SUBGRAPH_URL = ENVIO_HYPERINDEX_URL; +export const PROD_SUBGRAPH_URL = ENVIO_HYPERINDEX_URL; export const stakingEngineAddressMainnet = '0xce01c90de7fd1bcfa39e237fe6d8d9f569e8a6a3'; export const stakingEngineAddressTestnet = '0xce01c90de7fd1bcfa39e237fe6d8d9f569e8a6a3'; diff --git a/modules/gql/gqlUtils.ts b/modules/gql/gqlUtils.ts new file mode 100644 index 000000000..af3ba83c3 --- /dev/null +++ b/modules/gql/gqlUtils.ts @@ -0,0 +1,16 @@ +/* + +SPDX-FileCopyrightText: © 2023 Dai Foundation + +SPDX-License-Identifier: AGPL-3.0-or-later + +*/ + +/** + * Strip the chainId prefix from an Envio entity ID. + * E.g., "1-0xabc123" -> "0xabc123" + */ +export function stripChainIdPrefix(id: string): string { + const idx = id.indexOf('-'); + return idx > -1 ? id.substring(idx + 1) : id; +} diff --git a/modules/gql/queries/allLocksSummed.ts b/modules/gql/queries/allLocksSummed.ts deleted file mode 100644 index 55e39fa56..000000000 --- a/modules/gql/queries/allLocksSummed.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -export const allLocksSummed = /* GraphQL */ ` - query allLocksSummed($unixtimeStart: Int!, $unixtimeEnd: Int!) { - allLocksSummed(unixtimeStart: $unixtimeStart, unixtimeEnd: $unixtimeEnd) { - nodes { - fromAddress - immediateCaller - lockAmount - blockNumber - blockTimestamp - lockTotal - hash - } - } - } -`; diff --git a/modules/gql/queries/subgraph/allArbitrumVoters.ts b/modules/gql/queries/subgraph/allArbitrumVoters.ts index 856fd7152..81cdc6f7a 100644 --- a/modules/gql/queries/subgraph/allArbitrumVoters.ts +++ b/modules/gql/queries/subgraph/allArbitrumVoters.ts @@ -6,19 +6,20 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const allArbitrumVoters = /* GraphQL */ ` - query allArbitrumVoters($argPollId: String) { - arbitrumPoll(id: $argPollId) { - startDate - endDate - votes { - voter { - id - } - blockTime - choice - txnHash +export const allArbitrumVoters = (chainId: number, pollId: string) => /* GraphQL */ ` +{ + arbitrumPoll: ArbitrumPoll_by_pk(id: "${chainId}-${pollId}") { + startDate + endDate + votes { + voter { + id + address } + blockTime + choice + txnHash } } +} `; diff --git a/modules/gql/queries/subgraph/allArbitrumVotes.ts b/modules/gql/queries/subgraph/allArbitrumVotes.ts index 7a500428a..c5a11c6b9 100644 --- a/modules/gql/queries/subgraph/allArbitrumVotes.ts +++ b/modules/gql/queries/subgraph/allArbitrumVotes.ts @@ -6,15 +6,23 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const allArbitrumVotes = /* GraphQL */ ` - query allArbitrumVotes($argAddress: String!, $startUnix: BigInt) { - arbitrumPollVotes(where: {voter: $argAddress, blockTime_gt: $startUnix}, first: 1000) { - poll { - id - } - choice - blockTime - txnHash +export const allArbitrumVotes = (chainId: number, address: string, startUnix: number) => /* GraphQL */ ` +{ + arbitrumPollVotes: ArbitrumPollVote( + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { voter: { id: { _ilike: "${chainId}-${address}" } } }, + { blockTime: { _gt: "${startUnix}" } } + ] } + limit: 1000 + ) { + poll { + id + pollId } + choice + blockTime + txnHash } +} `; diff --git a/modules/gql/queries/subgraph/allDelegates.ts b/modules/gql/queries/subgraph/allDelegates.ts index b2ef527fa..3cfce2115 100644 --- a/modules/gql/queries/subgraph/allDelegates.ts +++ b/modules/gql/queries/subgraph/allDelegates.ts @@ -6,23 +6,24 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const allDelegates = /* GraphQL */ ` +export const allDelegates = (chainId: number) => /* GraphQL */ ` { - delegates(first: 1000, where: {version: "3"}) { + delegates: Delegate( + limit: 1000, + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { version: { _eq: "3" } } + ] } + ) { blockTimestamp ownerAddress id + address totalDelegated + delegators voter { lastVotedTimestamp } - delegations( - first: 1000 - where: {delegator_not_in: ["0xce01c90de7fd1bcfa39e237fe6d8d9f569e8a6a3", "0xb1fc11f03b084fff8dae95fa08e8d69ad2547ec1"], amount_gt: 0} - ) { - delegator - amount - } } } `; diff --git a/modules/gql/queries/subgraph/allDelegatesExecSupport.ts b/modules/gql/queries/subgraph/allDelegatesExecSupport.ts index 266d95266..c2330a76e 100644 --- a/modules/gql/queries/subgraph/allDelegatesExecSupport.ts +++ b/modules/gql/queries/subgraph/allDelegatesExecSupport.ts @@ -6,19 +6,24 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const allDelegatesExecSupport = /* GraphQL */ ` - { - delegates(first: 1000, where: {version: "3"}) { - blockTimestamp - ownerAddress - id - totalDelegated - voter { - lastVotedTimestamp - currentSpellsV2 { - id - } - } +export const allDelegatesExecSupport = (chainId: number) => /* GraphQL */ ` +{ + delegates: Delegate( + limit: 1000, + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { version: { _eq: "3" } } + ] } + ) { + blockTimestamp + ownerAddress + id + address + totalDelegated + voter { + lastVotedTimestamp + currentSpellsV2 } } +} `; diff --git a/modules/gql/queries/subgraph/allDelegations.ts b/modules/gql/queries/subgraph/allDelegations.ts deleted file mode 100644 index e6a413960..000000000 --- a/modules/gql/queries/subgraph/allDelegations.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* -SPDX-FileCopyrightText: © 2023 Dai Foundation -SPDX-License-Identifier: AGPL-3.0-or-later -*/ - -export const allDelegationsPaginated = /* GraphQL */ ` - query delegations($first: Int!, $skip: Int!) { - delegations( - first: $first - skip: $skip - where: { delegate_: { version: "3" }, delegator_not_in: ["0xce01c90de7fd1bcfa39e237fe6d8d9f569e8a6a3", "0xb1fc11f03b084fff8dae95fa08e8d69ad2547ec1"] } - ) { - delegator - delegate { - id - version - } - amount - } - } -`; diff --git a/modules/gql/queries/subgraph/allMainnetVoters.ts b/modules/gql/queries/subgraph/allMainnetVoters.ts index 75aea75e1..15a61465a 100644 --- a/modules/gql/queries/subgraph/allMainnetVoters.ts +++ b/modules/gql/queries/subgraph/allMainnetVoters.ts @@ -6,16 +6,22 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const allMainnetVoters = /* GraphQL */ ` - query allMainnetVoters($argPollId: String) { - pollVotes(where: { poll: $argPollId }) { +export const allMainnetVoters = (chainId: number, pollId: string) => /* GraphQL */ ` +{ + pollVotes: PollVote( + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { poll: { id: { _eq: "${chainId}-${pollId}" } } } + ] } + ) { + id + voter { id - voter { - id - } - blockTime - choice - txnHash + address } + blockTime + choice + txnHash } +} `; diff --git a/modules/gql/queries/subgraph/allMainnetVotes.ts b/modules/gql/queries/subgraph/allMainnetVotes.ts index e4b5647b8..a89e733b3 100644 --- a/modules/gql/queries/subgraph/allMainnetVotes.ts +++ b/modules/gql/queries/subgraph/allMainnetVotes.ts @@ -6,15 +6,23 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const allMainnetVotes = /* GraphQL */ ` - query allMainnetVotes($argAddress: String!, $startUnix: BigInt) { - pollVotes(where: {voter: $argAddress, blockTime_gt: $startUnix}, first: 1000) { - poll { - id - } - choice - blockTime - txnHash +export const allMainnetVotes = (chainId: number, address: string, startUnix: number) => /* GraphQL */ ` +{ + pollVotes: PollVote( + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { voter: { id: { _ilike: "${chainId}-${address}" } } }, + { blockTime: { _gt: "${startUnix}" } } + ] } + limit: 1000 + ) { + poll { + id + pollId } + choice + blockTime + txnHash } +} `; diff --git a/modules/gql/queries/subgraph/allSpellVotes.ts b/modules/gql/queries/subgraph/allSpellVotes.ts index 6fd678ced..f238ab19e 100644 --- a/modules/gql/queries/subgraph/allSpellVotes.ts +++ b/modules/gql/queries/subgraph/allSpellVotes.ts @@ -3,19 +3,26 @@ SPDX-FileCopyrightText: © 2023 Dai Foundation SPDX-License-Identifier: AGPL-3.0-or-later */ -export const allSpellVotes = /* GraphQL */ ` - query allSpellVotes($argSkip: Int, $argFirst: Int) { - executiveVoteV2S(first: $argFirst, skip: $argSkip, orderBy: id, orderDirection: desc) { - blockTime - spell { - id - } - voter { - id - v2VotingPowerChanges(first: 1, orderDirection: desc, orderBy: blockTimestamp) { - newBalance - } +export const allSpellVotes = (chainId: number, skip: number, first: number) => /* GraphQL */ ` +{ + executiveVoteV2S: ExecutiveVoteV2( + limit: ${first} + offset: ${skip} + order_by: { id: desc } + where: { chainId: { _eq: ${chainId} } } + ) { + blockTime + spell { + id + address + } + voter { + id + address + v2VotingPowerChanges(limit: 1, order_by: { blockTimestamp: desc }) { + newBalance } } } +} `; diff --git a/modules/gql/queries/subgraph/arbitrumPolls.ts b/modules/gql/queries/subgraph/arbitrumPolls.ts index 3870a10ab..03c1bdd04 100644 --- a/modules/gql/queries/subgraph/arbitrumPolls.ts +++ b/modules/gql/queries/subgraph/arbitrumPolls.ts @@ -6,39 +6,46 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const arbitrumPollsQueryWithWhitelist = /* GraphQL */ ` - query ArbitrumPollsWithWhitelist($argsSkip: Int!, $creatorWhitelist: [String!]!) { - arbitrumPolls( - first: 1000 - skip: $argsSkip - where: { - url_not: null, - blockCreated_not: null, - blockWithdrawn: null, - creator_in: $creatorWhitelist - } - ) { - id - url - multiHash - } +export const arbitrumPollsQueryWithWhitelist = (chainId: number, skip: number, creatorWhitelist: string[]) => { + const formattedWhitelist = creatorWhitelist.map(w => `{ creator: { _ilike: "${w}" } }`).join(', '); + return /* GraphQL */ ` +{ + arbitrumPolls: ArbitrumPoll( + limit: 1000 + offset: ${skip} + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { url: { _is_null: false } }, + { blockCreated: { _is_null: false } }, + { blockWithdrawn: { _is_null: true } }, + { _or: [${formattedWhitelist}] } + ] } + ) { + id + pollId + url + multiHash } +} `; +}; -export const arbitrumPollsQuery = /* GraphQL */ ` - query ArbitrumPolls($argsSkip: Int!) { - arbitrumPolls( - first: 1000 - skip: $argsSkip - where: { - url_not: null, - blockCreated_not: null, - blockWithdrawn: null - } - ) { - id - url - multiHash - } +export const arbitrumPollsQuery = (chainId: number, skip: number) => /* GraphQL */ ` +{ + arbitrumPolls: ArbitrumPoll( + limit: 1000 + offset: ${skip} + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { url: { _is_null: false } }, + { blockCreated: { _is_null: false } }, + { blockWithdrawn: { _is_null: true } } + ] } + ) { + id + pollId + url + multiHash } +} `; diff --git a/modules/gql/queries/subgraph/delegateHistoryArray.ts b/modules/gql/queries/subgraph/delegateHistoryArray.ts index af00e5168..72d99036c 100644 --- a/modules/gql/queries/subgraph/delegateHistoryArray.ts +++ b/modules/gql/queries/subgraph/delegateHistoryArray.ts @@ -6,21 +6,32 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const delegateHistoryArray = /* GraphQL */ ` - query delegateHistoryArray($delegates: [String!]!, $engines: [String!]) { - delegates(where: { id_in: $delegates, version: "3" }) { - delegationHistory(first: 1000, where: {delegator_not_in: $engines}) { - amount - accumulatedAmount - delegator - blockNumber - timestamp - txnHash - delegate { - id - } - isStakingEngine +export const delegateHistoryArray = (chainId: number, delegates: string[], engines: string[]) => { + const prefixedDelegates = delegates.map(d => `{ id: { _ilike: "${chainId}-${d}" } }`).join(', '); + const formattedEngines = engines.map(e => `{ delegator: { _nilike: "${e}" } }`).join(', '); + return /* GraphQL */ ` +{ + delegates: Delegate( + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { _or: [${prefixedDelegates}] }, + { version: { _eq: "3" } } + ] } + ) { + delegationHistory(limit: 1000, where: { _and: [${formattedEngines}] }) { + amount + accumulatedAmount + delegator + blockNumber + timestamp + txnHash + delegate { + id + address } + isStakingEngine } } +} `; +}; diff --git a/modules/gql/queries/subgraph/delegateWithPaginatedDelegations.ts b/modules/gql/queries/subgraph/delegateWithPaginatedDelegations.ts index 21a919c57..8c7fa5687 100644 --- a/modules/gql/queries/subgraph/delegateWithPaginatedDelegations.ts +++ b/modules/gql/queries/subgraph/delegateWithPaginatedDelegations.ts @@ -6,38 +6,43 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const delegateWithPaginatedDelegations = /* GraphQL */ ` - query delegateWithPaginatedDelegations( - $id: ID! - $first: Int! - $skip: Int! - $orderBy: String - $orderDirection: String - $excludeAddresses: [String!] - $stakingEngineAddresses: [String!]! - ) { - delegate(id: $id) { - id - blockTimestamp - blockNumber - ownerAddress - delegators - voter { - lastVotedTimestamp - } - delegations( - first: $first - skip: $skip - orderBy: $orderBy - orderDirection: $orderDirection - where: { delegator_not_in: $excludeAddresses } - ) { - delegator - amount - } - stakingEngineDelegations: delegations(where: { delegator_in: $stakingEngineAddresses }) { - delegator - } +export const delegateWithPaginatedDelegations = ( + chainId: number, + id: string, + first: number, + skip: number, + orderBy: string, + orderDirection: string, + excludeAddresses: string[], + stakingEngineAddresses: string[] +) => { + const formattedExclude = excludeAddresses.map(a => `{ delegator: { _nilike: "${a}" } }`).join(', '); + const formattedEngines = stakingEngineAddresses.map(a => `{ delegator: { _ilike: "${a}" } }`).join(', '); + return /* GraphQL */ ` +{ + delegate: Delegate(where: { id: { _ilike: "${chainId}-${id}" } }, limit: 1) { + id + address + blockTimestamp + blockNumber + ownerAddress + delegators + voter { + lastVotedTimestamp + } + delegations( + limit: ${first} + offset: ${skip} + order_by: { ${orderBy}: ${orderDirection} } + where: { _and: [${formattedExclude}] } + ) { + delegator + amount + } + stakingEngineDelegations: delegations(where: { _or: [${formattedEngines}] }) { + delegator } } +} `; +}; diff --git a/modules/gql/queries/subgraph/delegates.ts b/modules/gql/queries/subgraph/delegates.ts index 532130d4f..5fbf474df 100644 --- a/modules/gql/queries/subgraph/delegates.ts +++ b/modules/gql/queries/subgraph/delegates.ts @@ -6,88 +6,79 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const delegatesQuerySubsequentPages = /* GraphQL */ ` - query delegates( - $first: Int - $skip: Int - $orderBy: String - $orderDirection: String - $filter: Delegate_filter +const delegateFields = /* GraphQL */ ` + blockTimestamp + blockNumber + ownerAddress + totalDelegated + id + address + delegators + voter { + lastVotedTimestamp + } +`; + +interface DelegatesQueryParams { + chainId: number; + limit: number; + offset: number; + orderBy: string; + orderDirection: string; + whereConditions: string[]; +} + +export const delegatesQuerySubsequentPages = ({ + chainId, + limit, + offset, + orderBy, + orderDirection, + whereConditions +}: DelegatesQueryParams) => /* GraphQL */ ` +{ + delegates: Delegate( + where: { _and: [{ chainId: { _eq: ${chainId} } }, ${whereConditions.join(', ')}] } + limit: ${limit} + offset: ${offset} + order_by: { ${orderBy}: ${orderDirection} } ) { - delegates( - first: $first - skip: $skip - orderBy: $orderBy - orderDirection: $orderDirection - where: $filter - ) { - blockTimestamp - blockNumber - ownerAddress - delegations( - first: 1000 - where: {delegator_not_in: ["0xce01c90de7fd1bcfa39e237fe6d8d9f569e8a6a3", "0xb1fc11f03b084fff8dae95fa08e8d69ad2547ec1"], amount_gt: 0} - ) { - delegator - amount - } - id - delegators - voter { - lastVotedTimestamp - } - } + ${delegateFields} } +} `; -export const delegatesQueryFirstPage = /* GraphQL */ ` - query delegates( - $first: Int - $skip: Int - $orderBy: String - $orderDirection: String - $shadowFilter: Delegate_filter - $alignedFilter: Delegate_filter +interface DelegatesFirstPageQueryParams { + chainId: number; + limit: number; + orderBy: string; + orderDirection: string; + shadowWhereConditions: string[]; + alignedWhereConditions: string[]; +} + +export const delegatesQueryFirstPage = ({ + chainId, + limit, + orderBy, + orderDirection, + shadowWhereConditions, + alignedWhereConditions +}: DelegatesFirstPageQueryParams) => /* GraphQL */ ` +{ + delegates: Delegate( + where: { _and: [{ chainId: { _eq: ${chainId} } }, ${shadowWhereConditions.join(', ')}] } + limit: ${limit} + offset: 0 + order_by: { ${orderBy}: ${orderDirection} } + ) { + ${delegateFields} + } + alignedDelegates: Delegate( + where: { _and: [{ chainId: { _eq: ${chainId} } }, ${alignedWhereConditions.join(', ')}] } + order_by: { ${orderBy}: ${orderDirection} } ) { - delegates( - first: $first - skip: $skip - orderBy: $orderBy - orderDirection: $orderDirection - where: $shadowFilter - ) { - blockTimestamp - blockNumber - ownerAddress - delegations( - first: 1000 - where: {delegator_not_in: ["0xce01c90de7fd1bcfa39e237fe6d8d9f569e8a6a3", "0xb1fc11f03b084fff8dae95fa08e8d69ad2547ec1"], amount_gt: 0} - ) { - delegator - amount - } - id - delegators - voter { - lastVotedTimestamp - } - } - alignedDelegates: delegates(orderBy: $orderBy, orderDirection: $orderDirection, where: $alignedFilter) { - blockTimestamp - blockNumber - ownerAddress - delegations( - first: 1000 - where: {delegator_not_in: ["0xce01c90de7fd1bcfa39e237fe6d8d9f569e8a6a3", "0xb1fc11f03b084fff8dae95fa08e8d69ad2547ec1"], amount_gt: 0} - ) { - delegator - amount - } - id - delegators - voter { - lastVotedTimestamp - } - } + ${delegateFields} } +} `; diff --git a/modules/gql/queries/subgraph/delegatorDelegateHistory.ts b/modules/gql/queries/subgraph/delegatorDelegateHistory.ts index 46d7cc5fd..446ff614a 100644 --- a/modules/gql/queries/subgraph/delegatorDelegateHistory.ts +++ b/modules/gql/queries/subgraph/delegatorDelegateHistory.ts @@ -6,23 +6,27 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const delegatorDelegateHistory = /* GraphQL */ ` - query delegatorDelegateHistory($delegator: String!, $delegate: String!) { - delegationHistories( - first: 1000 - where: { delegator: $delegator, delegate: $delegate } - orderBy: timestamp - orderDirection: desc - ) { - amount - accumulatedAmount - delegate { - id - } - timestamp - txnHash - blockNumber - isStakingEngine +export const delegatorDelegateHistory = (chainId: number, delegator: string, delegate: string) => /* GraphQL */ ` +{ + delegationHistories: DelegationHistory( + limit: 1000, + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { delegator: { _ilike: "${delegator}" } }, + { delegate: { id: { _ilike: "${chainId}-${delegate}" } } } + ] } + order_by: { timestamp: desc } + ) { + amount + accumulatedAmount + delegate { + id + address } + timestamp + txnHash + blockNumber + isStakingEngine } -`; \ No newline at end of file +} +`; diff --git a/modules/gql/queries/subgraph/delegatorHistory.ts b/modules/gql/queries/subgraph/delegatorHistory.ts index 76b46844c..2c6e8000a 100644 --- a/modules/gql/queries/subgraph/delegatorHistory.ts +++ b/modules/gql/queries/subgraph/delegatorHistory.ts @@ -4,18 +4,25 @@ SPDX-FileCopyrightText: © 2023 Dai Foundation SPDX-License-Identifier: AGPL-3.0-or-later */ -export const delegatorHistory = /* GraphQL */ ` - query delegatorHistory($address: String!) { - delegationHistories(first: 1000, where: { delegator: $address }) { - amount - accumulatedAmount - delegate { - id - } - timestamp - txnHash - blockNumber - isStakingEngine +export const delegatorHistory = (chainId: number, address: string) => /* GraphQL */ ` +{ + delegationHistories: DelegationHistory( + limit: 1000, + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { delegator: { _ilike: "${address}" } } + ] } + ) { + amount + accumulatedAmount + delegate { + id + address } + timestamp + txnHash + blockNumber + isStakingEngine } +} `; diff --git a/modules/gql/queries/subgraph/lastVotedArbitrum.ts b/modules/gql/queries/subgraph/lastVotedArbitrum.ts index a5fee5d73..176c3744f 100644 --- a/modules/gql/queries/subgraph/lastVotedArbitrum.ts +++ b/modules/gql/queries/subgraph/lastVotedArbitrum.ts @@ -4,13 +4,22 @@ SPDX-FileCopyrightText: © 2023 Dai Foundation SPDX-License-Identifier: AGPL-3.0-or-later */ -export const lastVotedArbitrum = /* GraphQL */ ` - query lastVotedArbitrum($argAddresses: [String!]) { - arbitrumVoters(where: {id_in: $argAddresses}) { - id - pollVotes(orderBy: blockTime, orderDirection: desc, first: 1) { - blockTime - } +export const lastVotedArbitrum = (chainId: number, addresses: string[]) => { + const prefixedAddresses = addresses.map(a => `{ id: { _ilike: "${chainId}-${a}" } }`).join(', '); + return /* GraphQL */ ` +{ + arbitrumVoters: ArbitrumVoter( + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { _or: [${prefixedAddresses}] } + ] } + ) { + id + address + pollVotes(order_by: { blockTime: desc }, limit: 1) { + blockTime } + } } `; +}; diff --git a/modules/gql/queries/subgraph/pollTimes.ts b/modules/gql/queries/subgraph/pollTimes.ts index 56cd407cc..e2a5516c9 100644 --- a/modules/gql/queries/subgraph/pollTimes.ts +++ b/modules/gql/queries/subgraph/pollTimes.ts @@ -6,12 +6,21 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const pollTimes = /* GraphQL */ ` - query pollTimes($argPollIds: [String!]){ - arbitrumPolls(where: {id_in: $argPollIds}){ - startDate - endDate - id - } - } +export const pollTimes = (chainId: number, pollIds: string[]) => { + const prefixedIds = pollIds.map(id => `"${chainId}-${id}"`).join(', '); + return /* GraphQL */ ` +{ + arbitrumPolls: ArbitrumPoll( + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { id: { _in: [${prefixedIds}] } } + ] } + ) { + startDate + endDate + id + pollId + } +} `; +}; diff --git a/modules/gql/queries/subgraph/userDelegationToDelegate.ts b/modules/gql/queries/subgraph/userDelegationToDelegate.ts index 4f9e2eb56..d75d06933 100644 --- a/modules/gql/queries/subgraph/userDelegationToDelegate.ts +++ b/modules/gql/queries/subgraph/userDelegationToDelegate.ts @@ -6,21 +6,22 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const userDelegationToDelegate = /* GraphQL */ ` - query userDelegationToDelegate($delegate: String!, $delegator: String!) { - delegate(id: $delegate) { - delegationHistory(first: 1000, where: {delegator: $delegator}) { - amount - accumulatedAmount - delegator - blockNumber - timestamp - txnHash - delegate { - id - } - isStakingEngine +export const userDelegationToDelegate = (chainId: number, delegate: string, delegator: string) => /* GraphQL */ ` +{ + delegate: Delegate(where: { id: { _ilike: "${chainId}-${delegate}" } }, limit: 1) { + delegationHistory(limit: 1000, where: { delegator: { _ilike: "${delegator}" } }) { + amount + accumulatedAmount + delegator + blockNumber + timestamp + txnHash + delegate { + id + address } + isStakingEngine } } -`; \ No newline at end of file +} +`; diff --git a/modules/gql/queries/subgraph/voteAddressSkyWeightsAtTime.ts b/modules/gql/queries/subgraph/voteAddressSkyWeightsAtTime.ts index 10f10e2d5..c3be4a1a2 100644 --- a/modules/gql/queries/subgraph/voteAddressSkyWeightsAtTime.ts +++ b/modules/gql/queries/subgraph/voteAddressSkyWeightsAtTime.ts @@ -6,18 +6,26 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const voteAddressSkyWeightsAtTime = /* GraphQL */ ` - query voteAddressSkyWeightsAtTime($argVoters: [String!]!, $argUnix: BigInt!) { - voters(where: { id_in: $argVoters }) { - id - v2VotingPowerChanges( - first: 1 - orderDirection: desc - orderBy: blockTimestamp - where: { blockTimestamp_lte: $argUnix } - ) { - newBalance - } +export const voteAddressSkyWeightsAtTime = (chainId: number, voters: string[], unix: number) => { + const prefixedVoters = voters.map(v => `{ id: { _ilike: "${chainId}-${v}" } }`).join(', '); + return /* GraphQL */ ` +{ + voters: Voter( + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { _or: [${prefixedVoters}] } + ] } + ) { + id + address + v2VotingPowerChanges( + limit: 1 + order_by: { blockTimestamp: desc } + where: { blockTimestamp: { _lte: "${unix}" } } + ) { + newBalance } } +} `; +}; diff --git a/modules/gql/queries/subgraph/votingWeightHistory.ts b/modules/gql/queries/subgraph/votingWeightHistory.ts index dc84c36dd..b19c8078b 100644 --- a/modules/gql/queries/subgraph/votingWeightHistory.ts +++ b/modules/gql/queries/subgraph/votingWeightHistory.ts @@ -6,11 +6,16 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export const votingWeightHistory = /* GraphQL */ ` - query VotingWeightHistory($argAddress: String){ - executiveVotingPowerChangeV2S(where: {voter: $argAddress}){ - blockTimestamp - newBalance - } - } +export const votingWeightHistory = (chainId: number, address: string) => /* GraphQL */ ` +{ + executiveVotingPowerChangeV2S: ExecutiveVotingPowerChangeV2( + where: { _and: [ + { chainId: { _eq: ${chainId} } }, + { voter: { id: { _ilike: "${chainId}-${address}" } } } + ] } + ) { + blockTimestamp + newBalance + } +} `; diff --git a/modules/home/api/fetchAllLocksSummed.ts b/modules/home/api/fetchAllLocksSummed.ts deleted file mode 100644 index b9ab17d88..000000000 --- a/modules/home/api/fetchAllLocksSummed.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import { format } from 'date-fns'; -import logger from 'lib/logger'; -import { gqlRequest } from 'modules/gql/gqlRequest'; -import { allLocksSummed } from 'modules/gql/queries/allLocksSummed'; -import { SupportedNetworks } from 'modules/web3/constants/networks'; -import { networkNameToChainId } from 'modules/web3/helpers/chain'; -import { AllLocksResponse } from '../types/participation'; - -export default async function fetchAllLocksSummed( - network: SupportedNetworks, - unixtimeStart: number, - unixtimeEnd: number -): Promise { - try { - const data = await gqlRequest({ - chainId: networkNameToChainId(network), - query: allLocksSummed, - variables: { - unixtimeStart, - unixtimeEnd - } - }); - - const locks: AllLocksResponse[] = data?.allLocksSummed?.nodes.map(x => { - x.unixDate = Math.floor(new Date(x.blockTimestamp).getTime() / 1000); - x.total = (Number(x.lockTotal) / 1000).toFixed(0); - x.month = format(new Date(x.blockTimestamp), 'M'); - return x; - }); - - return locks; - } catch (e) { - logger.error( - 'fetchAllLocksSummed: Error fetching all lock events', - `Start: ${unixtimeStart}, End: ${unixtimeEnd}, Network: ${network}`, - e - ); - } - return []; -} diff --git a/modules/home/components/ParticipationChart.tsx b/modules/home/components/ParticipationChart.tsx deleted file mode 100644 index 713536437..000000000 --- a/modules/home/components/ParticipationChart.tsx +++ /dev/null @@ -1,129 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import { Box, Text, useThemeUI, get } from 'theme-ui'; -import { Tooltip, XAxis, YAxis, ResponsiveContainer, Legend, AreaChart, Area } from 'recharts'; -import { format, sub } from 'date-fns'; -import { AllLocksResponse } from '../types/participation'; - -const getPastMonths = (numMonths: number): string[] => { - const pastMonths: string[] = []; - const now = new Date(); - - while (numMonths > 0) { - pastMonths.push(format(sub(now, { months: numMonths }), 'M')); - numMonths--; - } - return pastMonths; -}; - -const ParticipationChart = ({ - data, - monthsPast -}: { - data: AllLocksResponse[]; - monthsPast: number; -}): React.ReactElement => { - const { theme } = useThemeUI(); - - const months = getPastMonths(monthsPast); - - const range = months - // filter out months with no data - .filter(m => data.find(({ month }) => month === m)) - .map(m => { - const myMonth = data.filter(({ month }) => month === m); - const lastDay = myMonth[myMonth.length - 1]; - - return { - total: lastDay.total, - blockTimestamp: lastDay.blockTimestamp, - unixDate: lastDay.unixDate, - lockTotal: lastDay.lockTotal - }; - }); - - const formatYAxis = tickSky => tickSky.toFixed(0); - - const formatXAxis = tickDate => { - const tickMonth = range.find(({ unixDate }) => unixDate === tickDate); - return tickMonth ? format(new Date(tickMonth.blockTimestamp), 'LLL') : 'd'; - }; - - const renderTooltip = item => { - const monthSKY = range ? range.find(i => i.unixDate === item.label) : null; - return ( - - {monthSKY && {format(new Date(monthSKY.blockTimestamp), 'LLL yyyy')}} - {monthSKY && {parseInt(monthSKY.lockTotal).toLocaleString()} SKY} - - ); - }; - - const formatLegend = () => ( - - SKY Locked in Chief - - ); - - return ( - - - - - - - - - - - - - - - - - - - - ); -}; - -export default ParticipationChart; diff --git a/modules/home/types/participation.d.ts b/modules/home/types/participation.d.ts index 31c79e650..d512e5a75 100644 --- a/modules/home/types/participation.d.ts +++ b/modules/home/types/participation.d.ts @@ -6,18 +6,6 @@ SPDX-License-Identifier: AGPL-3.0-or-later */ -export type AllLocksResponse = { - fromAddress: string; - immediateCaller: string; - lockAmount: string; - blockNumber: string; - blockTimestamp: string; - lockTotal: string; - unixDate: number; - total: string; - month: string; -}; - export type ForumPost = { title: string; summary: string; diff --git a/modules/polling/api/fetchAllCurrentVotes.ts b/modules/polling/api/fetchAllCurrentVotes.ts index aa2650a33..90d961b61 100644 --- a/modules/polling/api/fetchAllCurrentVotes.ts +++ b/modules/polling/api/fetchAllCurrentVotes.ts @@ -22,6 +22,7 @@ import { pollTimes } from 'modules/gql/queries/subgraph/pollTimes'; interface PollVoteResponse { poll: { id: string; + pollId: string; }; choice: string; blockTime: string; @@ -54,6 +55,7 @@ interface PollTimesResponse { startDate?: string; endDate?: string; id: string; + pollId: string; }[]; } @@ -65,8 +67,9 @@ function getSkyWeightAtTimestamp(weightHistory: VotingWeightHistoryResponse, tim return relevantEntry ? relevantEntry.newBalance : '0'; } -function isValidVote(vote: PollVoteResponse, pollTimes: PollTimesResponse): boolean { - const poll = pollTimes.arbitrumPolls.find(p => p.id === vote.poll.id); +function isValidVote(vote: PollVoteResponse, pollTimesData: PollTimesResponse): boolean { + const pollId = vote.poll.pollId; + const poll = pollTimesData.arbitrumPolls.find(p => p.pollId === pollId); const voteTime = Number(vote.blockTime); const pollStart = Number(poll?.startDate); const pollEnd = Number(poll?.endDate); @@ -81,32 +84,29 @@ async function fetchAllCurrentVotesWithSubgraph( ): Promise { const addressInfo = await getAddressInfo(address, network); const delegateOwnerAddress = addressInfo?.delegateInfo?.address; + const mainnetChainId = networkNameToChainId(network); const arbitrumChainId = networkNameToChainId(getGaslessNetwork(network)); const [mainnetVotes, arbitrumVotes, weightHistory] = await Promise.all([ gqlRequest({ - chainId: networkNameToChainId(network), - query: allMainnetVotes, - variables: { argAddress: address.toLowerCase(), startUnix } + chainId: mainnetChainId, + query: allMainnetVotes(mainnetChainId, address.toLowerCase(), startUnix) }), gqlRequest({ chainId: arbitrumChainId, - query: allArbitrumVotes, - variables: { - argAddress: delegateOwnerAddress ? delegateOwnerAddress.toLowerCase() : address.toLowerCase(), + query: allArbitrumVotes( + arbitrumChainId, + delegateOwnerAddress ? delegateOwnerAddress.toLowerCase() : address.toLowerCase(), startUnix - } + ) }), gqlRequest({ - chainId: networkNameToChainId(network), - query: votingWeightHistory, - variables: { - argAddress: address.toLowerCase() - } + chainId: mainnetChainId, + query: votingWeightHistory(mainnetChainId, address.toLowerCase()) }) ]); const mainnetVotesWithChainId = mainnetVotes.pollVotes.map(vote => ({ ...vote, - chainId: networkNameToChainId(network) + chainId: mainnetChainId })); const arbitrumVotesWithChainId = arbitrumVotes.arbitrumPollVotes.map(vote => ({ ...vote, @@ -116,7 +116,7 @@ async function fetchAllCurrentVotesWithSubgraph( const dedupedVotes = Object.values( combinedVotes.reduce((acc, vote) => { - const pollId = vote.poll.id; + const pollId = vote.poll.pollId; if (!acc[pollId] || Number(vote.blockTime) > Number(acc[pollId].blockTime)) { acc[pollId] = vote; } @@ -126,22 +126,22 @@ async function fetchAllCurrentVotesWithSubgraph( //get the poll times for all polls voted in //This is a separate request because we needed to know the arbitrum poll ids first to pass in to the query - const allPollIds = dedupedVotes.map(p => p.poll.id); + const allPollIds = dedupedVotes.map(p => p.poll.pollId); const pollTimesRes = await gqlRequest({ chainId: arbitrumChainId, - query: pollTimes, - variables: { argPollIds: allPollIds } + query: pollTimes(arbitrumChainId, allPollIds) }); const validVotes = dedupedVotes.filter(vote => isValidVote(vote, pollTimesRes)); const res: PollTallyVote[] = validVotes.map(o => { const ballot = parseRawOptionId(o.choice); - const poll = pollTimesRes.arbitrumPolls.find(p => p.id === o.poll.id); + const pollId = o.poll.pollId; + const poll = pollTimesRes.arbitrumPolls.find(p => p.pollId === pollId); const skySupport = getSkyWeightAtTimestamp(weightHistory, Number(poll?.endDate || o.blockTime)); return { - pollId: Number(o.poll.id), + pollId: Number(pollId), ballot, voter: address, hash: o.txnHash, diff --git a/modules/polling/api/fetchPolls.ts b/modules/polling/api/fetchPolls.ts index c3cd083fd..099d372ed 100644 --- a/modules/polling/api/fetchPolls.ts +++ b/modules/polling/api/fetchPolls.ts @@ -37,16 +37,12 @@ export async function refetchPolls(network: SupportedNetworks): Promise<{ let refetchSubgraph = true; let skip = 0; while (refetchSubgraph) { + const useWhitelist = network === SupportedNetworks.MAINNET && process.env.NEXT_PUBLIC_VERCEL_ENV !== 'development'; const response = await gqlRequest>({ chainId: arbitrumChainId, - query: - network === SupportedNetworks.MAINNET && process.env.NEXT_PUBLIC_VERCEL_ENV !== 'development' - ? arbitrumPollsQueryWithWhitelist - : arbitrumPollsQuery, - variables: - network === SupportedNetworks.MAINNET && process.env.NEXT_PUBLIC_VERCEL_ENV !== 'development' - ? { argsSkip: skip, creatorWhitelist: POLL_CREATOR_WHITELIST.map(w => w.toLowerCase()) } - : { argsSkip: skip } + query: useWhitelist + ? arbitrumPollsQueryWithWhitelist(arbitrumChainId, skip, POLL_CREATOR_WHITELIST.map(w => w.toLowerCase())) + : arbitrumPollsQuery(arbitrumChainId, skip) }); if (response.arbitrumPolls.length === 0) { @@ -88,7 +84,7 @@ export async function refetchPolls(network: SupportedNetworks): Promise<{ const pollList: PollListItem[] = subgraphPolls .map(poll => { - const { id, url, multiHash } = poll; + const { pollId: id, url, multiHash } = poll; const foundPollMetadata = pollsMetadata.find(entry => { // Decode both paths before comparing diff --git a/modules/polling/api/fetchVotesByAddress.ts b/modules/polling/api/fetchVotesByAddress.ts index ba07c32a1..ecaecda9f 100644 --- a/modules/polling/api/fetchVotesByAddress.ts +++ b/modules/polling/api/fetchVotesByAddress.ts @@ -19,6 +19,7 @@ import { SupportedChainId } from 'modules/web3/constants/chainID'; interface VoterData { id: string; + address: string; } interface VoteData { @@ -55,6 +56,7 @@ interface VotingPowerChange { interface VoterWithWeight { id: string; + address: string; v2VotingPowerChanges: VotingPowerChange[]; } @@ -67,23 +69,18 @@ export async function fetchVotesByAddressForPoll( delegateOwnerToAddress: Record, network: SupportedNetworks ): Promise { + const mainnetChainId = networkNameToChainId(network); const arbitrumChainId = network === SupportedNetworks.MAINNET ? SupportedChainId.ARBITRUM : SupportedChainId.ARBITRUMTESTNET; const [mainnetVotersResponse, arbitrumVotersResponse] = await Promise.all([ gqlRequest({ - chainId: networkNameToChainId(network), - query: allMainnetVoters, - variables: { - argPollId: pollId.toString() - } + chainId: mainnetChainId, + query: allMainnetVoters(mainnetChainId, pollId.toString()) }), gqlRequest({ chainId: arbitrumChainId, - query: allArbitrumVoters, - variables: { - argPollId: pollId.toString() - } + query: allArbitrumVoters(arbitrumChainId, pollId.toString()) }) ]); @@ -96,21 +93,24 @@ export async function fetchVotesByAddressForPoll( const isVoteWithinPollTimeframe = vote => vote.blockTime >= startUnix && vote.blockTime <= endUnix; const mapToDelegateAddress = (voterAddress: string) => delegateOwnerToAddress[voterAddress] || voterAddress; - const mainnetVoterAddresses = mainnetVotes.filter(isVoteWithinPollTimeframe).map(vote => vote.voter.id); + // Strip chainId prefix from voter IDs to get plain addresses + const mainnetVoterAddresses = mainnetVotes + .filter(isVoteWithinPollTimeframe) + .map(vote => vote.voter.address); const arbitrumVoterAddresses = arbitrumVotes .filter(isVoteWithinPollTimeframe) - .map(vote => mapToDelegateAddress(vote.voter.id)); + .map(vote => mapToDelegateAddress(vote.voter.address)); const allVoterAddresses = [...mainnetVoterAddresses, ...arbitrumVoterAddresses]; const addChainIdToVote = (vote, chainId) => ({ ...vote, chainId }); const mainnetVotesWithChainId = mainnetVotes.map(vote => - addChainIdToVote(vote, networkNameToChainId(network)) + addChainIdToVote(vote, mainnetChainId) ); const arbitrumVotesTaggedWithChainId = arbitrumVotes.map(vote => { - const mappedAddress = mapToDelegateAddress(vote.voter.id); + const mappedAddress = mapToDelegateAddress(vote.voter.address); return { ...vote, chainId: arbitrumChainId, @@ -121,24 +121,24 @@ export async function fetchVotesByAddressForPoll( const allVotes = [...mainnetVotesWithChainId, ...arbitrumVotesTaggedWithChainId]; const dedupedVotes = Object.values( allVotes.reduce((acc, vote) => { - const voter = vote.voter.id; - if (!acc[voter] || Number(vote.blockTime) > Number(acc[voter].blockTime)) { - acc[voter] = vote; + const voterAddr = vote.voter.address || vote.voter.id; + if (!acc[voterAddr] || Number(vote.blockTime) > Number(acc[voterAddr].blockTime)) { + acc[voterAddr] = vote; } return acc; }, {} as Record) ); const skyWeightsResponse = await gqlRequest({ - chainId: networkNameToChainId(network), - query: voteAddressSkyWeightsAtTime, - variables: { argVoters: allVoterAddresses, argUnix: endUnix } + chainId: mainnetChainId, + query: voteAddressSkyWeightsAtTime(mainnetChainId, allVoterAddresses, endUnix) }); const votersWithWeights = skyWeightsResponse.voters || []; const votesWithWeights = dedupedVotes.map((vote: (typeof allVotes)[0]) => { - const voterData = votersWithWeights.find(voter => voter.id === vote.voter.id); + const voterId = vote.voter.address || vote.voter.id; + const voterData = votersWithWeights.find(voter => voter.address === voterId); const votingPowerChanges = voterData?.v2VotingPowerChanges || []; const skySupport = votingPowerChanges.length > 0 ? votingPowerChanges[0].newBalance : '0'; @@ -147,7 +147,7 @@ export async function fetchVotesByAddressForPoll( skySupport, ballot, pollId, - voter: vote.voter.id, + voter: voterId, chainId: vote.chainId, blockTimestamp: vote.blockTime, hash: vote.txnHash diff --git a/modules/polling/types/poll.d.ts b/modules/polling/types/poll.d.ts index 6cfd075a4..8a6be3e9e 100644 --- a/modules/polling/types/poll.d.ts +++ b/modules/polling/types/poll.d.ts @@ -137,6 +137,7 @@ export type PartialActivePoll = { export type SubgraphPoll = { id: string; + pollId: string; url: string; multiHash: string; }; diff --git a/modules/web3/constants/networks.ts b/modules/web3/constants/networks.ts index 05f77ef31..aea6b6e72 100644 --- a/modules/web3/constants/networks.ts +++ b/modules/web3/constants/networks.ts @@ -11,14 +11,7 @@ import { SupportedChain } from '../types/chain'; import { SupportedChainId } from './chainID'; import tenderlyTestnetData from '../../../tenderlyTestnetData.json'; -import { - TENDERLY_SUBGRAPH_URL, - MAINNET_STAGING_SUBGRAPH_URL, - MAINNET_PROD_SUBGRAPH_URL, - ARBITRUM_PROD_SUBGRAPH_URL, - ARBITRUM_STAGING_SUBGRAPH_URL, - ARBITRUM_TENDERLY_SUBGRAPH_URL -} from 'modules/gql/gql.constants'; +import { STAGING_SUBGRAPH_URL, PROD_SUBGRAPH_URL } from 'modules/gql/gql.constants'; export enum SupportedConnectors { METAMASK = 'MetaMask', @@ -65,9 +58,7 @@ export const CHAIN_INFO: ChainInfo = { network: SupportedNetworks.MAINNET, defaultRpc: NodeProviders.TENDERLY, subgraphUrl: - process.env.NEXT_PUBLIC_VERCEL_ENV === 'development' - ? MAINNET_STAGING_SUBGRAPH_URL - : MAINNET_PROD_SUBGRAPH_URL, + process.env.NEXT_PUBLIC_VERCEL_ENV === 'development' ? STAGING_SUBGRAPH_URL : PROD_SUBGRAPH_URL, rpcs: { [NodeProviders.TENDERLY]: process.env.NEXT_PUBLIC_RPC_MAINNET || '' }, @@ -81,7 +72,7 @@ export const CHAIN_INFO: ChainInfo = { type: 'gasless', network: SupportedNetworks.ARBITRUMTESTNET, defaultRpc: NodeProviders.TENDERLY, - subgraphUrl: ARBITRUM_TENDERLY_SUBGRAPH_URL, + subgraphUrl: STAGING_SUBGRAPH_URL, rpcs: { [NodeProviders.TENDERLY]: process.env.NEXT_PUBLIC_RPC_ARBITRUM_TESTNET || '' }, @@ -96,9 +87,7 @@ export const CHAIN_INFO: ChainInfo = { network: SupportedNetworks.ARBITRUM, defaultRpc: NodeProviders.TENDERLY, subgraphUrl: - process.env.NEXT_PUBLIC_VERCEL_ENV === 'development' - ? ARBITRUM_STAGING_SUBGRAPH_URL - : ARBITRUM_PROD_SUBGRAPH_URL, + process.env.NEXT_PUBLIC_VERCEL_ENV === 'development' ? STAGING_SUBGRAPH_URL : PROD_SUBGRAPH_URL, rpcs: { [NodeProviders.TENDERLY]: process.env.NEXT_PUBLIC_RPC_ARBITRUM || '' }, @@ -112,7 +101,7 @@ export const CHAIN_INFO: ChainInfo = { type: 'normal', network: SupportedNetworks.TENDERLY, defaultRpc: NodeProviders.TENDERLY, - subgraphUrl: TENDERLY_SUBGRAPH_URL, + subgraphUrl: STAGING_SUBGRAPH_URL, rpcs: { [NodeProviders.TENDERLY]: config.USE_MOCK_WALLET && TENDERLY_RPC_URL diff --git a/pages/api/delegates/[address]/delegator/[delegatorAddress]/history.ts b/pages/api/delegates/[address]/delegator/[delegatorAddress]/history.ts index d74c6bdd3..b298d0877 100644 --- a/pages/api/delegates/[address]/delegator/[delegatorAddress]/history.ts +++ b/pages/api/delegates/[address]/delegator/[delegatorAddress]/history.ts @@ -113,15 +113,14 @@ export default withApiHandler(async (req: NextApiRequest, res: NextApiResponse) const chainId = networkNameToChainId(network); const result = await gqlRequest({ chainId, - query: delegatorDelegateHistory, - variables: { - delegator: delegatorAddress.toLowerCase(), - delegate: address.toLowerCase() - } + query: delegatorDelegateHistory(chainId, delegatorAddress.toLowerCase(), address.toLowerCase()) }); return res.status(200).json({ - delegationHistory: result.delegationHistories || [], + delegationHistory: (result.delegationHistories || []).map(entry => ({ + ...entry, + delegate: entry.delegate ? { ...entry.delegate, id: entry.delegate.address } : entry.delegate + })), delegateAddress: address.toLowerCase(), delegatorAddress: delegatorAddress.toLowerCase() }); diff --git a/pages/api/executive/all-locks.ts b/pages/api/executive/all-locks.ts deleted file mode 100644 index 7867fa388..000000000 --- a/pages/api/executive/all-locks.ts +++ /dev/null @@ -1,124 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -/** - * @swagger - * /api/executive/all-locks: - * get: - * summary: Returns the summary of all locks in the given time range for the specified network. - * description: Returns an array of objects containing summary of all lock events (deposits into Chief) in the given time range for the specified network. - * tags: - * - executive - * parameters: - * - name: network - * in: query - * required: false - * description: The network to fetch the data from. If not specified, will use the default network. - * schema: - * type: string - * enum: [tenderly, mainnet] - * default: mainnet - * - name: unixtimeStart - * in: query - * required: true - * description: The start of the time range for which to fetch the data. Unix timestamp in seconds. - * schema: - * type: number - * - name: unixtimeEnd - * in: query - * required: false - * description: The end of the time range for which to fetch the data. Unix timestamp in seconds. If not specified, will use the current time. - * schema: - * type: number - * responses: - * '200': - * description: OK - * content: - * application/json: - * schema: - * type: array - * items: - * type: object - * properties: - * fromAddress: - * type: string - * description: The address from which the lock originated (often the same as immediateCaller). - * immediateCaller: - * type: string - * description: The address that directly interacted with the contract for the lock. - * lockAmount: - * type: string - * description: The amount of SKY locked in this specific event. - * blockNumber: - * type: string - * description: The block number in which this lock event occurred. - * blockTimestamp: - * type: string - * description: The timestamp of the block for this lock event (ISO8601 format from GraphQL). - * lockTotal: - * type: string - * description: The total amount locked by the immediateCaller after this event. - * hash: - * type: string - * description: Transaction hash of the lock event. - * unixDate: - * type: number - * description: Derived Unix timestamp (seconds) of the blockTimestamp. - * total: - * type: string - * description: Derived; lockTotal divided by 1000, formatted to zero decimal places. - * month: - * type: string - * description: Derived; The month number (1-12) from blockTimestamp. - * '400': - * description: Bad request (e.g., missing unixtimeStart). - * '404': - * description: Not found (if data fetch returns nothing, though current code returns []). - * '500': - * description: Internal server error. - */ - -import { ApiError } from 'modules/app/api/ApiError'; -import validateQueryParam from 'modules/app/api/validateQueryParam'; -import withApiHandler from 'modules/app/api/withApiHandler'; -import fetchAllLocksSummed from 'modules/home/api/fetchAllLocksSummed'; -import { DEFAULT_NETWORK, SupportedNetworks } from 'modules/web3/constants/networks'; -import { NextApiRequest, NextApiResponse } from 'next'; -import invariant from 'tiny-invariant'; - -export default withApiHandler(async (req: NextApiRequest, res: NextApiResponse) => { - const network = validateQueryParam(req.query.network, 'string', { - defaultValue: DEFAULT_NETWORK.network, - validValues: [SupportedNetworks.TENDERLY, SupportedNetworks.MAINNET] - }) as SupportedNetworks; - - const unixtimeStart = validateQueryParam(req.query.unixtimeStart, 'number', { - defaultValue: 0, - minValue: 0 - }) as number; - - const unixtimeEnd = validateQueryParam(req.query.unixtimeEnd, 'number', { - defaultValue: 0, - minValue: 0 - }) as number; - - invariant(unixtimeStart, 'unixtimeStart is required'); - - const data = await fetchAllLocksSummed( - network, - unixtimeStart, - unixtimeEnd ? unixtimeEnd : Math.floor(Date.now() / 1000) - ); - - if (!data) { - throw new ApiError('Not found', 404); - } - - res.setHeader('Cache-Control', 's-maxage=15, stale-while-revalidate'); - res.status(200).json(data); -});