From 0ecae09714cbabc75ec0381c07e9412378b4e5b0 Mon Sep 17 00:00:00 2001 From: lza_menace Date: Mon, 23 Dec 2024 10:15:13 -0800 Subject: [PATCH] add web server to show data --- bun.lockb | Bin 83090 -> 106788 bytes package.json | 3 +- public/index.html | 186 ++++++++++++++++++++++++++++++++++++++++++++++ src/server.js | 104 ++++++++++++++++++++++++++ 4 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 public/index.html create mode 100644 src/server.js diff --git a/bun.lockb b/bun.lockb index 337d0967ad8e4aa630911765ed7ac30e53362673..177ff5b2d44af002e8c9478257112b15ecf7ee35 100755 GIT binary patch delta 27795 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

2VXPOG$VE z8PLd&voWT>o37spLM4{_r!t}# zO3^PWC>0hG6N5iZk{TBtsV0?DlAu;}7(c4I+6|)9e>MgYKk@bBD+~z5DhkL1g5PQ? zbb^8vc$A}Ox#e2n&&Q}j5)xw4R8i`f1bl1|4mEM9eZ{z6LKr?{QL_WtWwm1ln@#rorvR`*Qe(rkP{L25}SXF3Aq&|*$ z4b3IT60!v+L%E?hmkf7(eX^$+9GL^iO{vM)+$o133#7r|TpH7_XpiyXe1=?^C> zFA0y!9%INgu&dzR-rg^12o8=TNMoK;`0+o$1BZ+u2#g_1E2b V)0JDmW&cr+v)ozTgPT<2{{y7YpQ8W( delta 13703 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 bD3*xo)<3G?Kjp|%qF5~4{o*3=c&+~f-{nVo diff --git a/package.json b/package.json index 2aaa4fe..dbc28f6 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { "dependencies": { "alchemy-sdk": "^3.5.0", + "better-sqlite3": "^11.7.0", "ethers": "^6.13.4", + "express": "^4.21.2", "sqlite3": "^5.1.7" }, "name": "alchemy-nft-scraper", "module": "index.ts", - "type": "module", "devDependencies": { "@types/bun": "latest" }, diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..bfd7349 --- /dev/null +++ b/public/index.html @@ -0,0 +1,186 @@ + + + Art101 Sales Statistics + + + + + + + +

Art101 Sales Statistics

+

Source Code

+
+ Loading, please wait... +
+
+ + + diff --git a/src/server.js b/src/server.js new file mode 100644 index 0000000..9a33171 --- /dev/null +++ b/src/server.js @@ -0,0 +1,104 @@ +const ALL_CONTRACTS = require('./contracts'); + +const Database = require('better-sqlite3'); +const express = require('express'); + + +const app = express(); +const port = process.env.PORT || 3000; +const db = new Database('./state/sqlite.db', {readonly: true}); + + +app.use(express.json()); + +app.use('/', express.static('public')); + +app.use('/app', express.static('public')); + +app.get('/api/contracts', (req, res) => { + res.status(200).json(ALL_CONTRACTS) +}) + +app.get('/api/:contractAddress/events', (req, res) => { + const results = []; + const stmt = db.prepare(`select * + from events + where contract = '${req.params.contractAddress}' + collate nocase + order by block_number desc + limit 100 + `); + for (const entry of stmt.iterate()) { + results.push(entry); + } + res.status(200).json(results); +}); + +app.get('/api/token/:contractAddress/:tokenId/history', (req, res) => { + const results = []; + const stmt = db.prepare(`select * + from events + where token_id = ${req.params.tokenId} + and contract = '${req.params.contractAddress}' + collate nocase + order by block_number desc + `); + for (const entry of stmt.iterate()) { + results.push(entry); + } + res.status(200).json(results); +}); + +app.get('/api/latest', (req, res) => { + const stmt = db.prepare(`select * + from events + order by block_number desc + limit 1 + `); + res.status(200).json(stmt.get()); +}); + +app.get('/api/:contractAddress/data', (req, res) => { + const results = []; + const stmt = db.prepare(`select + block_number block, + sum(sale_price/1000000000000000000.0) volume, + avg(sale_price/1000000000000000000.0) average_price, + (select avg(sale_price/1000000000000000000.0) from (select * from events + where contract = '${req.params.contractAddress}' + collate nocase + order by sale_price + limit 10)) floor_price, + count(*) sales + from events ev + where contract = '${req.params.contractAddress}' + collate nocase + group by block + order by block + `); + for (const entry of stmt.iterate()) { + results.push(entry); + } + res.status(200).json(results); +}); + +app.get('/api/:contractAddress/platforms', (req, res) => { + const results = []; + const stmt = db.prepare(`select marketplace, + sum(sale_price/1000000000000000000.0) volume, + count(*) sales + from events + where contract = '${req.params.contractAddress}' + collate nocase + group by marketplace + order by sum(sale_price/1000000000000000000.0) desc + `); + for (const entry of stmt.iterate()) { + results.push(entry); + } + res.status(200).json(results); +}); + +app.listen(port, () => { + console.log(`Example app listening at http://localhost:${port}`); +}); \ No newline at end of file