diff --git a/src/routes/v3/snax-testnet/votes.js b/src/routes/v3/snax-testnet/votes.js index 398287d..ea119ec 100644 --- a/src/routes/v3/snax-testnet/votes.js +++ b/src/routes/v3/snax-testnet/votes.js @@ -2,7 +2,7 @@ const express = require('express'); const router = express.Router(); const { log, postgresClient, getCache, setCache } = require('../../../utils'); -const cacheKey = 'snax-votes'; +const cacheKey = 'snax-votes-testnet'; fetchDataFromPostgres(); const cacheTime = @@ -20,7 +20,7 @@ setInterval(fetchDataFromPostgres, cacheTime < 30000 ? 30000 : cacheTime); * get: * tags: * - v3 - * description: Returns SNX buyback details on Base. + * description: Returns all the votes * responses: * 200: * description: Successful response. @@ -91,7 +91,7 @@ router.get('/', async (req, res, next) => { res.json(responseData); } } catch (error) { - log.error(`[v3SnaxVote] Error: ${error.message}`); + log.error(`[v3SnaxVote-Testnet] Error: ${error.message}`); next(error); } }); @@ -99,7 +99,7 @@ router.get('/', async (req, res, next) => { module.exports = router; async function fetchDataFromPostgres() { - log.debug('[v3SnaxVote] Fetching data from postgres..'); + log.debug('[v3SnaxVote-Testnet] Fetching data from postgres..'); const queryResultVotesCasted = await postgresClient.query( `select * from prod_raw_snax_testnet.gov_vote_recorded_snax_testnet;`, @@ -148,7 +148,7 @@ async function fetchDataFromPostgres() { }, {}); const responseData = allVotes; - log.debug('[v3SnaxVote] Setting cache..'); + log.debug('[v3SnaxVote-Testnet] Setting cache..'); await setCache(cacheKey, responseData, 60); return responseData; } diff --git a/src/routes/v3/snax/votes.js b/src/routes/v3/snax/votes.js new file mode 100644 index 0000000..5570049 --- /dev/null +++ b/src/routes/v3/snax/votes.js @@ -0,0 +1,241 @@ +const express = require('express'); +const router = express.Router(); +const { log, postgresClient, getCache, setCache } = require('../../../utils'); + +const cacheKey = 'snax-votes-mainnet'; + +fetchDataFromPostgres(); +const cacheTime = + ((process.env.CACHE_TIME = + typeof process.env.CACHE_TIME === 'string' + ? parseInt(process.env.CACHE_TIME) + : process.env.CACHE_TIME) - + 30) * + 1000; +setInterval(fetchDataFromPostgres, cacheTime < 30000 ? 30000 : cacheTime); +/** +@openapi +* /v3/snax/votes: +* get: +* tags: +* - v3 +* description: Returns all the votes categorized by councils. +* responses: +* 200: +* description: Successful response. +* content: +* application/json: +* schema: +* type: object +* properties: +* spartan: +* type: array +* items: +* type: object +* properties: +* eventName: +* type: string +* example: "VoteRecorded" +* chainId: +* type: number +* example: 13001 +* epochId: +* type: number +* example: 1 +* voter: +* type: string +* example: "0xc3Cf311e04c1f8C74eCF6a795Ae760dc6312F345" +* blockTimestamp: +* type: number +* example: 1231231231 +* id: +* type: string +* example: "093890428092342034-dsfb3-000000" +* transactionHash: +* type: string +* example: "0xbb9982fbae46a551f5e503a059251b51fdb2bc5b06c13ca15db8a61785b8d095" +* votingPower: +* type: string +* example: "10" +* blockNumber: +* type: number +* example: 580095 +* candidates: +* type: array +* items: +* type: string +* example: ["0x98591879709e2e3106941C818CBD94eD29475d1f"] +* contract: +* type: string +* example: "0xbc85f11300a8ef619592fd678418ec4ef26fbdfd" +* ambassador: +* type: array +* items: +* type: object +* properties: +* eventName: +* type: string +* example: "VoteRecorded" +* chainId: +* type: number +* example: 13001 +* epochId: +* type: number +* example: 1 +* voter: +* type: string +* example: "0xc3Cf311e04c1f8C74eCF6a795Ae760dc6312F345" +* blockTimestamp: +* type: number +* example: 1231231231 +* id: +* type: string +* example: "093890428092342034-dsfb3-000000" +* transactionHash: +* type: string +* example: "0xbb9982fbae46a551f5e503a059251b51fdb2bc5b06c13ca15db8a61785b8d095" +* votingPower: +* type: string +* example: "10" +* blockNumber: +* type: number +* example: 580095 +* candidates: +* type: array +* items: +* type: string +* example: ["0x98591879709e2e3106941C818CBD94eD29475d1f"] +* contract: +* type: string +* example: "0xbc85f11300a8ef619592fd678418ec4ef26fbdfd" +* treasury: +* type: array +* items: +* type: object +* properties: +* eventName: +* type: string +* example: "VoteRecorded" +* chainId: +* type: number +* example: 13001 +* epochId: +* type: number +* example: 1 +* voter: +* type: string +* example: "0xc3Cf311e04c1f8C74eCF6a795Ae760dc6312F345" +* blockTimestamp: +* type: number +* example: 1231231231 +* id: +* type: string +* example: "093890428092342034-dsfb3-000000" +* transactionHash: +* type: string +* example: "0xbb9982fbae46a551f5e503a059251b51fdb2bc5b06c13ca15db8a61785b8d095" +* votingPower: +* type: string +* example: "10" +* blockNumber: +* type: number +* example: 580095 +* candidates: +* type: array +* items: +* type: string +* example: ["0x98591879709e2e3106941C818CBD94eD29475d1f"] +* contract: +* type: string +* example: "0xbc85f11300a8ef619592fd678418ec4ef26fbdfd" +*/ + +router.get('/', async (req, res, next) => { + try { + log.debug('Checking cache..'); + const cachedResponse = await getCache(cacheKey); + if (cachedResponse) { + log.debug('Cache found'); + res.json(cachedResponse); + } else { + log.debug('Cache not found, executing..'); + const responseData = await fetchDataFromPostgres(); + res.json(responseData); + } + } catch (error) { + log.error(`[v3SnaxVote] Error: ${error.message}`); + next(error); + } +}); + +module.exports = router; + +async function fetchDataFromPostgres() { + log.debug('[v3SnaxVote] Fetching data from postgres..'); + const queryResultVotesCastedSpartan = await postgresClient.query( + `select * + from prod_raw_snax_mainnet.spartan_vote_recorded_snax_mainnet;`, + ); + + const queryResultVotesWithdrawnSpartan = await postgresClient.query( + `select * + from prod_raw_snax_mainnet.spartan_vote_withdrawn_snax_mainnet;`, + ); + + const queryResultVotesCastedAmbassador = await postgresClient.query( + `select * + from prod_raw_snax_mainnet.ambassador_vote_recorded_snax_mainnet;`, + ); + + const queryResultVotesWithdrawnAmbassador = await postgresClient.query( + `select * + from prod_raw_snax_mainnet.ambassador_vote_withdrawn_snax_mainnet;`, + ); + + const queryResultVotesCastedTreasury = await postgresClient.query( + `select * + from prod_raw_snax_mainnet.treasury_vote_recorded_snax_mainnet;`, + ); + + const queryResultVotesWithdrawnTreasury = await postgresClient.query( + `select * + from prod_raw_snax_mainnet.treasury_vote_withdrawn_snax_mainnet;`, + ); + + const responseData = { + spartan: queryResultVotesCastedSpartan.rows + .map(parseAndRenameKeys) + .concat(queryResultVotesWithdrawnSpartan.rows.map(parseAndRenameKeys)), + ambassador: queryResultVotesCastedAmbassador.rows + .map(parseAndRenameKeys) + .concat(queryResultVotesWithdrawnAmbassador.rows.map(parseAndRenameKeys)), + treasury: queryResultVotesCastedTreasury.rows + .map(parseAndRenameKeys) + .concat(queryResultVotesWithdrawnTreasury.rows.map(parseAndRenameKeys)), + }; + + log.debug('[v3SnaxVote] Setting cache..'); + await setCache(cacheKey, responseData, 60); + return responseData; +} + +function toCamelCase(str) { + return str.replace(/([-_][a-z])/gi, (group) => + group.toUpperCase().replace('-', '').replace('_', ''), + ); +} + +function parseAndRenameKeys(obj) { + const newObj = {}; + for (const key in obj) { + const camelCaseKey = toCamelCase(key); + if (key === 'block_timestamp') { + newObj[camelCaseKey] = Date.parse(obj[key]); + } else if (key === 'epoch_id' || key === 'chain_id') { + newObj[camelCaseKey] = Number(obj[key]); + } else { + newObj[camelCaseKey] = obj[key]; + } + } + return newObj; +} diff --git a/src/server.js b/src/server.js index c9d3010..b64f441 100644 --- a/src/server.js +++ b/src/server.js @@ -129,6 +129,9 @@ redisClient.on('ready', () => { const v3SnaxTestnetVotesRouter = require('./routes/v3/snax-testnet/votes.js'); app.use('/v3/snax-testnet/votes', v3SnaxTestnetVotesRouter); + const v3SnaxVotesRouter = require('./routes/v3/snax/votes.js'); + app.use('/v3/snax/votes', v3SnaxVotesRouter); + log.debug('[Express] Starting server..'); const port = typeof process.env.API_PORT === 'string'