diff --git a/.gitignore b/.gitignore index 985ef72..a5be68a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +# dependencies +/node_modules +/.pnp +.pnp.js + # dependencies (bun install) node_modules @@ -47,4 +52,4 @@ lerna-debug.log* *.ntvs* *.njsproj *.sln -*.sw? +*.sw? \ No newline at end of file diff --git a/README.md b/README.md index 9d5813d..d522a04 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,53 @@ +# Chain Indexer Notification and Leaderboard Builder API + +This API notifies a blockchain indexer about new submissions and triggers a leaderboard builder. + +## Features + +- Notify a chain indexer with submission data +- Trigger a leaderboard update +- Modular design with clear service responsibilities + +## Prerequisites + +- Node.js (v16+) +- npm or yarn + +## Installation + +1. Clone the repository: + ```bash + git clone https://github.com/yourusername/backend.git + cd chain-notifier + ``` + +2. Install dependencies: + npm install express + ``` + +3. Create a `.env` file in the root directory for environment variables if required. + +## Usage + +1. Start the server: + node app.js + ``` + +2. Use the `/api/notify` endpoint to notify the indexer and trigger the leaderboard. + +### Example Request +**Endpoint**: `POST /api/notify` + +**Body**: +```json +{ + "submissionData": { + "userId": "05421", + "submissionId": "fghij", + "score": 40 + } +} +======= # DeCleanup Network Backend Backend API for the DeCleanup Network application, providing wallet-based diff --git a/app.js b/app.js new file mode 100644 index 0000000..9ec7653 --- /dev/null +++ b/app.js @@ -0,0 +1,19 @@ +const express = require('express'); +const apiRoutes = require('./routes/apiRoutes'); + +const app = express(); +app.use(express.json()); + +// Use API routes +app.use('/api', apiRoutes); + +// Error handling middleware +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).json({ error: 'Something went wrong!' }); +}); + +const PORT = process.env.PORT || 3000; +app.listen(PORT, () => { + console.log(`Server running on port ${PORT}`); +}); \ No newline at end of file diff --git a/controllers/submissionController.js b/controllers/submissionController.js new file mode 100644 index 0000000..00a30fc --- /dev/null +++ b/controllers/submissionController.js @@ -0,0 +1,27 @@ +const { notifyIndexerService } = require('../services/indexerService'); +const { updateLeaderboard } = require('../services/leaderboardService'); + +exports.notifyIndexer = async (req, res) => { + try { + const { submissionData } = req.body; + + if (!submissionData) { + return res.status(400).json({ error: 'Submission data is required' }); + } + + // Notify the chain indexer + const indexerResponse = await notifyIndexerService(submissionData); + + // Trigger the leaderboard builder + const leaderboardResponse = await updateLeaderboard(); + + res.status(200).json({ + message: 'Indexer notified and leaderboard updated successfully.', + indexerResponse, + leaderboardResponse, + }); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'Failed to process the request.' }); + } +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1c5bbb4..a40bc3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,13 @@ { + "name": "backend", "name": "decleanup-network_backend", "lockfileVersion": 3, "requires": true, "packages": { "": { + "dependencies": { + "express": "^4.21.2" + "name": "decleanup-network_backend", "dependencies": { "@wagmi/core": "^2.16.5", @@ -1198,6 +1202,10 @@ "node": ">= 0.6" } }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" "node_modules/aes-js": { "version": "4.0.0-beta.5", "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", @@ -1289,6 +1297,10 @@ } }, "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", @@ -1302,6 +1314,12 @@ } }, "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", @@ -1321,6 +1339,7 @@ "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -1350,6 +1369,14 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, @@ -1565,6 +1592,11 @@ "node": ">= 0.4" } }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -1579,16 +1611,19 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" + }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, + "node_modules/env-paths": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", @@ -1631,6 +1666,10 @@ "node": ">= 0.4" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" "node_modules/esbuild": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", @@ -1692,6 +1731,7 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", + "engines": { "node": ">= 0.6" } @@ -1869,6 +1909,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-intrinsic": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", + "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "function-bind": "^1.1.2", + "get-proto": "^1.0.0", +======= "node_modules/gel": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/gel/-/gel-2.0.1.tgz", @@ -2005,6 +2057,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, @@ -2195,6 +2248,10 @@ "node": ">= 0.6" } }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" "node_modules/mipd": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/mipd/-/mipd-0.0.7.tgz", @@ -2230,6 +2287,10 @@ "node": ">= 0.6" } }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -2338,6 +2399,7 @@ "node_modules/path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "license": "MIT" }, @@ -2593,7 +2655,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2639,12 +2701,14 @@ "type": "consulting", "url": "https://feross.org/support" } + ] ], "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, @@ -2708,6 +2772,11 @@ "node": ">= 0.8" } }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/serve-static": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", @@ -2726,6 +2795,7 @@ "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, @@ -2941,6 +3011,9 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } "license": "MIT", "engines": { "node": ">= 0.8" diff --git a/package.json b/package.json index a52dc8d..a8b9fb2 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,7 @@ { + "dependencies": { + "express": "^4.21.2" + } "name": "decleanup-network_backend", "module": "index.ts", "type": "module", diff --git a/routes/apiRoutes.js b/routes/apiRoutes.js new file mode 100644 index 0000000..5f6e74b --- /dev/null +++ b/routes/apiRoutes.js @@ -0,0 +1,8 @@ +const express = require('express'); +const { notifyIndexer } = require('../controllers/submissionController'); +const router = express.Router(); + +// Endpoint to notify the indexer and trigger leaderboard update +router.post('/notify', notifyIndexer); + +module.exports = router; \ No newline at end of file diff --git a/services/indexerService.js b/services/indexerService.js new file mode 100644 index 0000000..49845c9 --- /dev/null +++ b/services/indexerService.js @@ -0,0 +1,12 @@ +exports.notifyIndexerService = async (submissionData) => { + try { + // Simulate notifying the blockchain indexer + console.log('Notifying chain indexer with submission:', submissionData); + + // Simulate a successful response + return { status: 'success', message: 'Indexer notified.' }; + } catch (error) { + console.error('Error notifying indexer:', error); + throw new Error('Failed to notify indexer.'); + } +}; \ No newline at end of file diff --git a/services/leaderboardService.js b/services/leaderboardService.js new file mode 100644 index 0000000..d0be6e3 --- /dev/null +++ b/services/leaderboardService.js @@ -0,0 +1,12 @@ +exports.updateLeaderboard = async () => { + try { + // Simulate leaderboard rebuilding + console.log('Rebuilding leaderboard...'); + + // Simulate a successful response + return { status: 'success', message: 'Leaderboard updated.' }; + } catch (error) { + console.error('Error updating leaderboard:', error); + throw new Error('Failed to update leaderboard.'); + } +}; \ No newline at end of file