Skip to content

Commit 8cb8e76

Browse files
fschoell0237h
authored andcommitted
Add OHLC SOL prices by pool for SVM (#193)
Also disable the validation for the pagination since the endpoint SQL doesn't use `LIMIT`/`OFFSET`.
1 parent c4a9ce9 commit 8cb8e76

File tree

5 files changed

+77
-58
lines changed

5 files changed

+77
-58
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { Hono } from 'hono';
22
import evm from './evm.js';
3+
import svm from './svm.js';
34

45
const router = new Hono();
56

67
router.route('/evm', evm);
7-
// router.route('/svm', svm);
8+
router.route('/svm', svm);
89

910
export default router;

src/routes/token/ohlc/pools/svm.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ const responseSchema = apiUsageResponse.extend({
4848

4949
const openapi = describeRoute(
5050
withErrorResponses({
51-
summary: 'OHLCV by Pool',
52-
description: 'Provides pricing data in the Open/High/Low/Close/Volume (OHCLV) format.',
51+
summary: 'Solana OHLCV prices (SOL) by Pool',
52+
description: 'Provides pricing data in native SOL in the Open/High/Low/Close/Volume (OHCLV) format.',
5353
tags: ['SVM'],
5454
security: [{ bearerAuth: [] }],
5555
responses: {
@@ -63,18 +63,20 @@ const openapi = describeRoute(
6363
value: {
6464
data: [
6565
{
66-
datetime: '2025-06-20 00:00:00',
67-
pool: '58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2',
68-
token0: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
66+
datetime: '2025-09-15 00:00:00',
67+
amm: 'pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA',
68+
pool: 'AmmpSnW5xVeKHTAU9fMjyKEMPgrzmUj3ah5vgvHhAB5J',
69+
token0: '9BB6NFEcjBCtnNLFko2FqVQBq8HHM13kCyYcdQbgpump',
70+
token0_decimals: 6,
6971
token1: 'So11111111111111111111111111111111111111112',
70-
open: 146.64474747474748,
71-
high: 147.71993287074972,
72-
low: 145.0099569301824,
73-
close: 147.36215787385962,
74-
volume: 551499356.7426533,
75-
uaw: 337,
76-
transactions: 1021110,
77-
network_id: 'solana',
72+
token1_decimals: 9,
73+
open: 0.003648785031942177,
74+
high: 0.0036724218787403977,
75+
low: 0.0034598947533987442,
76+
close: 0.0035191405556241413,
77+
volume: 3.521022449,
78+
uaw: 76,
79+
transactions: 159,
7880
},
7981
],
8082
},
@@ -101,9 +103,10 @@ route.get(
101103
if (!dbConfig) {
102104
return c.json({ error: `Network not found: ${params.network_id}` }, 400);
103105
}
104-
const query = sqlQueries.ohlcv_prices_for_pool?.[dbConfig.type];
106+
let query = sqlQueries.ohlcv_prices_for_pool?.[dbConfig.type];
105107
if (!query) return c.json({ error: 'Query for OHLC pool data could not be loaded' }, 500);
106108

109+
query = query.replaceAll('{svm_metadata_db}', config.tokenDatabases[params.network_id]?.database || '');
107110
const response = await makeUsageQueryJson(
108111
c,
109112
[query],

src/sql/balances_for_account/svm.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,4 @@ SELECT
8282
{network_id:String} AS network_id
8383
FROM filtered_balances AS b
8484
LEFT JOIN metadata USING mint
85-
ORDER BY timestamp DESC
85+
ORDER BY timestamp DESC
Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,49 @@
1-
WITH decimals AS (
1+
WITH ohlc AS
2+
(
23
SELECT
3-
pool,
4-
if(decimals0 = 0, 9, decimals0) AS decimals0,
5-
if(decimals1 = 0, 9, decimals1) AS decimals1,
6-
pow(10, -abs(decimals0 - decimals1)) AS decimals_factor
7-
FROM ohlc_prices
8-
WHERE pool = {pool: String}
4+
if(
5+
toTime(toStartOfInterval(o.timestamp, INTERVAL {interval:UInt64} MINUTE)) = toDateTime('1970-01-02 00:00:00'),
6+
toDate(toStartOfInterval(o.timestamp, INTERVAL {interval:UInt64} MINUTE)),
7+
toStartOfInterval(o.timestamp, INTERVAL {interval:UInt64} MINUTE)
8+
) AS datetime,
9+
toString(o.amm) AS amm,
10+
toString(o.amm_pool) AS pool,
11+
toString(o.mint0) AS token0,
12+
toString(o.mint1) AS token1,
13+
argMinMerge(open0) AS open_raw,
14+
quantileDeterministicMerge({high_quantile:Float64})(quantile0) AS high_raw,
15+
quantileDeterministicMerge({low_quantile:Float64})(quantile0) AS low_raw,
16+
argMaxMerge(close0) AS close_raw,
17+
sum(gross_volume1) AS volume,
18+
uniqMerge(uaw) AS uaw,
19+
sum(transactions) AS transactions,
20+
token0 IN {stablecoin_contracts: Array(String)} AS is_stablecoin
21+
FROM ohlc_prices AS o
22+
WHERE pool = {pool:String}
23+
AND timestamp >= today() - toIntervalMinute(({offset:UInt64} + {limit:UInt64} - 1) * {interval:UInt64})
24+
AND timestamp <= today() - toIntervalMinute({offset:UInt64} * {interval:UInt64})
25+
GROUP BY token0, token1, amm, amm_pool, datetime
926
)
1027
SELECT
11-
if(
12-
toTime(toStartOfInterval(o.timestamp, INTERVAL {interval: UInt64} MINUTE)) = toDateTime('1970-01-02 00:00:00'),
13-
toDate(toStartOfInterval(o.timestamp, INTERVAL {interval: UInt64} MINUTE)),
14-
toStartOfInterval(o.timestamp, INTERVAL {interval: UInt64} MINUTE)
15-
) AS datetime,
16-
toString(pool) AS pool,
17-
toString(token0) AS token0,
18-
toString(token1) AS token1,
19-
decimals_factor * argMinMerge(o.open0) AS open,
20-
decimals_factor * quantileDeterministicMerge({high_quantile: Float32})(o.quantile0) AS high,
21-
decimals_factor * quantileDeterministicMerge({low_quantile: Float32})(o.quantile0) AS low,
22-
decimals_factor * argMaxMerge(o.close0) AS close,
23-
sum(o.gross_volume0) AS volume,
24-
uniqMerge(o.uaw) AS uaw,
25-
sum(o.transactions) AS transactions,
26-
{network_id: String} AS network_id
27-
FROM ohlc_prices AS o
28-
JOIN decimals USING pool
29-
WHERE pool = {pool: String} AND timestamp BETWEEN {startTime: UInt64} AND {endTime: UInt64}
30-
GROUP BY token0, token1, decimals_factor, pool, datetime
31-
ORDER BY datetime DESC
32-
LIMIT {limit:UInt64}
33-
OFFSET {offset:UInt64}
28+
datetime,
29+
amm,
30+
pool,
31+
token0,
32+
coalesce(
33+
(SELECT decimals FROM `{svm_metadata_db}`.mints WHERE mint IN (SELECT token0 FROM ohlc) AND decimals != 0),
34+
9
35+
) AS token0_decimals,
36+
token1,
37+
coalesce(
38+
(SELECT decimals FROM `{svm_metadata_db}`.mints WHERE mint IN (SELECT token1 FROM ohlc) AND decimals != 0),
39+
9
40+
) AS token1_decimals,
41+
pow(10, -(token1_decimals - token0_decimals)) * if(is_stablecoin, 1/open_raw, open_raw) AS open,
42+
pow(10, -(token1_decimals - token0_decimals)) * if(is_stablecoin, 1/low_raw, high_raw) AS high,
43+
pow(10, -(token1_decimals - token0_decimals)) * if(is_stablecoin, 1/high_raw, low_raw) AS low,
44+
pow(10, -(token1_decimals - token0_decimals)) * if(is_stablecoin, 1/close_raw, close_raw) AS close,
45+
pow(10, -(token1_decimals)) * toFloat64(volume) * if(is_stablecoin, close, 1) AS volume,
46+
uaw,
47+
transactions
48+
FROM ohlc AS o
49+
ORDER BY datetime DESC;

src/types/zod.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -301,18 +301,17 @@ export const statisticsSchema = z.object({
301301
bytes_read: z.optional(z.number()),
302302
});
303303

304-
export const paginationSchema = z
305-
.object({
306-
previous_page: z.coerce.number().int().min(1),
307-
current_page: z.coerce.number().int().min(1),
308-
next_page: z.coerce.number().int().min(1),
309-
total_pages: z.coerce.number().int().min(1),
310-
})
311-
.refine(
312-
({ previous_page, current_page, next_page, total_pages }) =>
313-
previous_page <= current_page && current_page <= next_page && next_page <= total_pages,
314-
"Requested page doesn't exist"
315-
);
304+
export const paginationSchema = z.object({
305+
previous_page: z.coerce.number().int().min(1),
306+
current_page: z.coerce.number().int().min(1),
307+
next_page: z.coerce.number().int().min(1),
308+
total_pages: z.coerce.number().int().min(1),
309+
});
310+
// .refine(
311+
// ({ previous_page, current_page, next_page, total_pages }) =>
312+
// previous_page <= current_page && current_page <= next_page && next_page <= total_pages,
313+
// "Requested page doesn't exist"
314+
// );
316315
export type PaginationSchema = z.infer<typeof paginationSchema>;
317316

318317
// ----------------------

0 commit comments

Comments
 (0)