From 61ea0b0b670cf794c6208cca53f7b248f3daf297 Mon Sep 17 00:00:00 2001 From: 1emu Date: Tue, 11 Jun 2024 13:33:22 -0300 Subject: [PATCH] chore: add endpoints for snapshot subgraph and update api url --- src/back/routes/snapshot.ts | 23 +++++++++++++++++++++++ src/back/utils/validations.ts | 15 +++++++++++++++ src/clients/SnapshotSubgraph.ts | 10 ++++------ src/entities/Snapshot/constants.ts | 2 +- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/back/routes/snapshot.ts b/src/back/routes/snapshot.ts index 4bd25df17..5413c92b0 100644 --- a/src/back/routes/snapshot.ts +++ b/src/back/routes/snapshot.ts @@ -3,10 +3,14 @@ import handleAPI from 'decentraland-gatsby/dist/entities/Route/handle' import routes from 'decentraland-gatsby/dist/entities/Route/routes' import { Request } from 'express' +import { SnapshotSubgraph } from '../../clients/SnapshotSubgraph' +import { getDelegations as getSnapshotDelegations } from '../../entities/Snapshot/utils' import { SnapshotService } from '../../services/SnapshotService' import { SnapshotStatusService } from '../../services/SnapshotStatusService' import { validateAddress, + validateAddresses, + validateBlockNumber, validateDates, validateProposalFields, validateProposalSnapshotId, @@ -22,6 +26,8 @@ export default routes((router) => { router.get('/snapshot/vp-distribution/:address/:proposalSnapshotId?', handleAPI(getVpDistribution)) router.post('/snapshot/scores', handleAPI(getScores)) router.get('/snapshot/proposal-scores/:proposalSnapshotId', handleAPI(getProposalScores)) + router.post('/snapshot/delegations', handleAPI(getDelegations)) + router.post('/snapshot/picked-by', handleAPI(getPickedBy)) }) async function getStatus() { @@ -77,3 +83,20 @@ async function getProposalScores(req: Request<{ proposalSnapshotId?: string }>) const proposalSnapshotId = validateProposalSnapshotId(req.params.proposalSnapshotId) return await SnapshotService.getProposalScores(proposalSnapshotId) } + +async function getDelegations(req: Request) { + const { address, blockNumber } = req.body + validateAddress(address) + validateBlockNumber(blockNumber) + return getSnapshotDelegations(address, blockNumber) +} + +async function getPickedBy(req: Request) { + const { addresses, space } = req.body + validateAddresses(addresses) + if (!space || typeof space !== 'string' || space.length === 0) { + throw new RequestError('Invalid snapshot space', RequestError.BadRequest) + } + + return await SnapshotSubgraph.get().getPickedBy(addresses, space) +} diff --git a/src/back/utils/validations.ts b/src/back/utils/validations.ts index 58b8292e0..adbe4d604 100644 --- a/src/back/utils/validations.ts +++ b/src/back/utils/validations.ts @@ -79,6 +79,15 @@ export function validateAddress(address?: string) { return address } +export function validateAddresses(addresses?: string[]) { + if (!Array.isArray(addresses)) { + throw new RequestError(`Invalid addresses ${addresses}`, RequestError.BadRequest) + } + addresses.forEach((address) => { + validateAddress(address) + }) +} + export const areValidAddresses = (addresses: string[]) => Array.isArray(addresses) && addresses.every((item) => isEthereumAddress(item)) @@ -154,3 +163,9 @@ export function validateEventTypesFilters(req: Request) { return parsedEventTypes.data } + +export function validateBlockNumber(blockNumber?: unknown | null) { + if (blockNumber !== null && blockNumber !== undefined && typeof blockNumber !== 'number') { + throw new Error('Invalid blockNumber: must be null, undefined, or a number') + } +} diff --git a/src/clients/SnapshotSubgraph.ts b/src/clients/SnapshotSubgraph.ts index 6a3d3df45..9a4ded3b1 100644 --- a/src/clients/SnapshotSubgraph.ts +++ b/src/clients/SnapshotSubgraph.ts @@ -72,10 +72,8 @@ export class SnapshotSubgraph { return delegations } - async getPickedBy(variables: { address: string[]; space: string }) { - const { address, space } = variables - - if (!address || !space) { + async getPickedBy(addresses: string[], space: string) { + if (!addresses || !space) { return [] } @@ -93,13 +91,13 @@ export class SnapshotSubgraph { const body = await response.json() return body?.data?.delegatedFrom || [] }, - { address, space }, + { address: addresses, space }, 500 ) const pickedBy = new Map>() - for (const addr of address) { + for (const addr of addresses) { const filteredDelegations = delegations.filter((deleg) => deleg.delegate === addr) pickedBy.set(addr, new Set()) diff --git a/src/entities/Snapshot/constants.ts b/src/entities/Snapshot/constants.ts index ed45b2d86..a9d17d43a 100644 --- a/src/entities/Snapshot/constants.ts +++ b/src/entities/Snapshot/constants.ts @@ -7,5 +7,5 @@ export const SNAPSHOT_SPACE = process.env.GATSBY_SNAPSHOT_SPACE || '' export const SNAPSHOT_ADDRESS = process.env.GATSBY_SNAPSHOT_ADDRESS || '' export const SNAPSHOT_DURATION = Number(process.env.GATSBY_SNAPSHOT_DURATION || '') export const SNAPSHOT_URL = process.env.GATSBY_SNAPSHOT_URL || 'https://testnet.snapshot.org/' -export const SNAPSHOT_QUERY_ENDPOINT = process.env.GATSBY_SNAPSHOT_QUERY_ENDPOINT || '' +export const SNAPSHOT_QUERY_ENDPOINT = `https://gateway-arbitrum.network.thegraph.com/api/${process.env.THE_GRAPH_API_KEY}/subgraphs/id/4YgtogVaqoM8CErHWDK8mKQ825BcVdKB8vBYmb4avAQo` export const SNAPSHOT_API = process.env.GATSBY_SNAPSHOT_API || ''