From 6a965e209302c23ffd7349f1eae4cb01c47f58c5 Mon Sep 17 00:00:00 2001 From: cokehill Date: Mon, 23 Feb 2026 14:00:45 -0500 Subject: [PATCH] feat: add circulating supply API endpoint --- backend/.env | 27 ++++++++++++++++++ backend/.env.example | 2 +- backend/nano | 0 backend/src/index.js | 7 +---- backend/src/models/subSchedule.js | 6 ---- backend/src/routes/token.js | 39 ++++++++++++++++++++++++++ backend/src/services/vestingService.js | 30 ++++---------------- 7 files changed, 74 insertions(+), 37 deletions(-) create mode 100644 backend/.env create mode 100644 backend/nano create mode 100644 backend/src/routes/token.js diff --git a/backend/.env b/backend/.env new file mode 100644 index 00000000..ba4d91e2 --- /dev/null +++ b/backend/.env @@ -0,0 +1,27 @@ +# Server Configuration +PORT=3000 +NODE_ENV=development + +# Database Configuration +DB_HOST=localhost +DB_PORT=5432 +DB_NAME=vesting_vault +DB_USER=postgres +DB_PASSWORD=1234 + +# JWT Configuration (if needed) +JWT_SECRET=your-super-secret-jwt-key-here + +# External Services (if needed) +# BLOCKCHAIN_RPC_URL=https://mainnet.infura.io/v3/YOUR_PROJECT_ID +# ETHEREUM_PRIVATE_KEY=your-private-key-here + +# Discord Bot Configuration +DISCORD_BOT_TOKEN=your-discord-bot-token-here +DISCORD_CHANNEL_ID=your-discord-channel-id-here + +# Redis Configuration +REDIS_URL=redis://localhost:6379 + +# Slack Webhook Configuration +SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL diff --git a/backend/.env.example b/backend/.env.example index 95b35f50..ba4d91e2 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -7,7 +7,7 @@ DB_HOST=localhost DB_PORT=5432 DB_NAME=vesting_vault DB_USER=postgres -DB_PASSWORD=password +DB_PASSWORD=1234 # JWT Configuration (if needed) JWT_SECRET=your-super-secret-jwt-key-here diff --git a/backend/nano b/backend/nano new file mode 100644 index 00000000..e69de29b diff --git a/backend/src/index.js b/backend/src/index.js index 73f716e8..a6660061 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -1,6 +1,4 @@ const express = require('express'); -const { ClaimGateway } = require('./websocket/claim.gateway'); -const { RedisIoAdapter } = require('./websocket/redis.adapter'); const cors = require('cors'); const dotenv = require('dotenv'); const http = require('http'); @@ -326,10 +324,7 @@ const startServer = async () => { if (graphQLServer) { console.log(`GraphQL API available at: http://localhost:${PORT}/graphql`); } - // Initialize WebSocket Gateway with Redis adapter - const redisIoAdapter = new RedisIoAdapter(httpServer); - const claimGateway = new ClaimGateway(); - claimGateway.server = redisIoAdapter.createIOServer(PORT, { transports: ['websocket'] }); + }); } catch (error) { console.error('Unable to start server:', error); diff --git a/backend/src/models/subSchedule.js b/backend/src/models/subSchedule.js index 45384af3..431cdc1b 100644 --- a/backend/src/models/subSchedule.js +++ b/backend/src/models/subSchedule.js @@ -16,15 +16,12 @@ const SubSchedule = sequelize.define('SubSchedule', { }, onUpdate: 'CASCADE', onDelete: 'CASCADE', - }, top_up_amount: { type: DataTypes.DECIMAL(36, 18), allowNull: false, comment: 'Amount of tokens added in this top-up', }, - - }, created_at: { type: DataTypes.DATE, defaultValue: DataTypes.NOW, @@ -42,9 +39,6 @@ const SubSchedule = sequelize.define('SubSchedule', { { fields: ['vault_id'], }, - { - - }, ], }); diff --git a/backend/src/routes/token.js b/backend/src/routes/token.js new file mode 100644 index 00000000..a02487d0 --- /dev/null +++ b/backend/src/routes/token.js @@ -0,0 +1,39 @@ +const express = require('express'); +const router = express.Router(); +const db = require('../db'); // adjust if your db import is different + +// GET /api/token/:address/supply +router.get('/:address/supply', async (req, res) => { + try { + const tokenAddress = req.params.address.toLowerCase(); + + // 1. Get total minted (from db or a model) + const totalMintedResult = await db.query( + 'SELECT SUM(amount) AS total_minted FROM tokens WHERE address = $1', + [tokenAddress] + ); + const totalMinted = totalMintedResult.rows[0]?.total_minted || 0; + + // 2. Sum unvested balances + const unvestedResult = await db.query( + 'SELECT SUM(unvested_balance) AS total_unvested FROM vesting_vaults WHERE token_address = $1 AND active = true', + [tokenAddress] + ); + const totalUnvested = unvestedResult.rows[0]?.total_unvested || 0; + + // 3. Calculate circulating + const circulatingSupply = totalMinted - totalUnvested; + + return res.json({ + token: tokenAddress, + circulatingSupply, + totalMinted, + totalUnvested + }); + } catch (err) { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + } +}); + +module.exports = router; diff --git a/backend/src/services/vestingService.js b/backend/src/services/vestingService.js index 5204282c..095f517a 100644 --- a/backend/src/services/vestingService.js +++ b/backend/src/services/vestingService.js @@ -1,34 +1,16 @@ +class VestingService { - throw error; - } - } - - - throw error; - } - } - - - throw error; - } - } - - - throw error; - } - } - - - }); - + async exampleFunction() { + try { return { success: true, - + message: "Vesting service is working" + }; + } catch (error) { throw error; } } - } module.exports = new VestingService();