Skip to content

Commit

Permalink
Merge pull request #29 from galacticcouncil/homepage_endpoint
Browse files Browse the repository at this point in the history
Add endpoint for Hydration homepage
  • Loading branch information
vgantchev authored May 29, 2024
2 parents 68670c7 + 064ebb6 commit f7ef21b
Show file tree
Hide file tree
Showing 15 changed files with 250 additions and 13 deletions.
29 changes: 29 additions & 0 deletions .gcp/jobs/cache_hydration-web_stats_job.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
apiVersion: run.googleapis.com/v1
kind: Job
metadata:
name: cache-hydration-web-stats-job
labels:
cloud.googleapis.com/location: europe-west3

spec:
template:
metadata:
annotations:
run.googleapis.com/vpc-access-connector: hydradx-api-connector
spec:
parallelism: 0
template:
spec:
maxRetries: "0"
timeoutSeconds: "300"
containers:
- image: europe-west3-docker.pkg.dev/rich-principle-383410/hydradx-api/hydradx-api-jobs:latest
env:
- name: JOB_NAME
value: cache-hydration-web-stats-job
- name: GOOGLE_CLOUD_RUN_JOB
value: "true"
resources:
limits:
cpu: "1"
memory: 512Mi
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,8 @@ jobs:
- name: deploy cache_hydradx-ui_stats_tvl_job
run: gcloud beta run jobs replace .gcp/jobs/cache_hydradx-ui_stats_tvl_job.yml

- name: deploy cache_hydration-web_stats_job
run: gcloud beta run jobs replace .gcp/jobs/cache_hydration-web_stats_job.yml

- name: deploy api-app
run: gcloud beta run services replace .gcp/hydradx_api_app.yml
39 changes: 39 additions & 0 deletions app/routes/hydration-web/v1/stats.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import yesql from "yesql";
import path from "path";
import { dirname } from "../../../../variables.mjs";
import { CACHE_SETTINGS } from "../../../../variables.mjs";
import { fetchFromCache } from "../../../../helpers/cache_helpers.mjs";

const sqlQueries = yesql(path.join(dirname(), "queries/hydration-web/v1"), {
type: "pg",
});

export default async (fastify, opts) => {
fastify.route({
url: "/stats",
method: ["GET"],
schema: {
description: "Stats displayed on the Hydration homepage",
tags: ["hydration-web/v1"],
response: {
200: {
description: "Data displayed on Hydration homepage",
type: "object",
properties: {
tvl: { type: "number" },
vol_30d: { type: "number" },
xcm_vol_30d: { type: "number" },
assets_count: { type: "number" },
accounts_count: { type: "number" },
},
},
},
},
handler: async (request, reply) => {
let cacheSetting = { ...CACHE_SETTINGS["hydrationWebV1Stats"] };
let result = await fetchFromCache(fastify.redis, cacheSetting);

reply.send(JSON.parse(result));
},
});
};
35 changes: 28 additions & 7 deletions helpers/cache_helpers.mjs
Original file line number Diff line number Diff line change
@@ -1,19 +1,40 @@
export async function cachedFetch(sqlClient, redisClient, cacheSetting, qry) {
export async function fetchFromCache(redisClient, cacheSetting) {
let cachedResult = await redisClient.get(cacheSetting.key);
return cachedResult;
}

export async function updateCache(redisClient, cacheSetting, json) {
await redisClient.set(cacheSetting.key, json);
await redisClient.expire(cacheSetting.key, cacheSetting.expire_after);

return json;
}

export async function cachedFetch(sqlClient, redisClient, cacheSetting, qry) {
let cachedResult = await fetchFromCache(redisClient, cacheSetting);

if (cachedResult == null) {
cachedResult = await updateCache(sqlClient, redisClient, cacheSetting, qry);
cachedResult = await updateCacheFromSql(
sqlClient,
redisClient,
cacheSetting,
qry
);
}

return cachedResult;
}

export async function updateCache(sqlClient, redisClient, cacheSetting, qry) {
export async function updateCacheFromSql(
sqlClient,
redisClient,
cacheSetting,
qry
) {
const { rows } = await sqlClient.query(qry);
const cachedResult = JSON.stringify(rows);
const result = JSON.stringify(rows);

await redisClient.set(cacheSetting.key, cachedResult);
await redisClient.expire(cacheSetting.key, cacheSetting.expire_after);
await updateCache(redisClient, cacheSetting, result);

return cachedResult;
return result;
}
5 changes: 5 additions & 0 deletions helpers/sql_helpers.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export async function fetchFromSql(sqlClient, qry) {
const { rows } = await sqlClient.query(qry);

return rows;
}
5 changes: 5 additions & 0 deletions jobs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { JOB_NAME, CONTINUOUS_JOB } = process.env;

import { JOBS } from "./variables.mjs";
import { cacheCoingeckoTickersJob } from "./jobs/cache_coingecko_tickers_job.mjs";
import { cacheHydrationWebStatsJob } from "./jobs/cache_hydration-web_stats_job.mjs";
import { cacheHydradxUiStatsTvlJob } from "./jobs/cache_hydradx-ui_stats_tvl_job.mjs";
import { cacheCoinmarketcapSummaryJob } from "./jobs/cache_coinmarketcap_summary_job.mjs";
import { newSqlClient } from "./clients/sql.mjs";
Expand Down Expand Up @@ -36,6 +37,10 @@ async function executeJob(job_name) {
await cacheCoingeckoTickersJob(sqlClient, redisClient);
break;
}
case JOBS["cacheHydrationWebStatsJob"]: {
await cacheHydrationWebStatsJob(sqlClient, redisClient);
break;
}
case JOBS["cacheHydradxUiStatsTvlJob"]: {
await cacheHydradxUiStatsTvlJob(sqlClient, redisClient);
break;
Expand Down
4 changes: 2 additions & 2 deletions jobs/cache_coingecko_tickers_job.mjs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import yesql from "yesql";
import path from "path";
import { dirname, CACHE_SETTINGS } from "../variables.mjs";
import { updateCache } from "../helpers/cache_helpers.mjs";
import { updateCacheFromSql } from "../helpers/cache_helpers.mjs";

const sqlQueries = yesql(path.join(dirname(), "queries/coingecko/v1/"), {
type: "pg",
});

export async function cacheCoingeckoTickersJob(sqlClient, redisClient) {
await updateCache(
await updateCacheFromSql(
sqlClient,
redisClient,
CACHE_SETTINGS["coingeckoV1Tickers"],
Expand Down
4 changes: 2 additions & 2 deletions jobs/cache_coinmarketcap_summary_job.mjs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import yesql from "yesql";
import path from "path";
import { dirname, CACHE_SETTINGS } from "../variables.mjs";
import { updateCache } from "../helpers/cache_helpers.mjs";
import { updateCacheFromSql } from "../helpers/cache_helpers.mjs";

const sqlQueries = yesql(path.join(dirname(), "queries/coinmarketcap/v1/"), {
type: "pg",
});

export async function cacheCoinmarketcapSummaryJob(sqlClient, redisClient) {
await updateCache(
await updateCacheFromSql(
sqlClient,
redisClient,
CACHE_SETTINGS["coinmarketcapV1Summary"],
Expand Down
4 changes: 2 additions & 2 deletions jobs/cache_hydradx-ui_stats_tvl_job.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import yesql from "yesql";
import path from "path";
import { dirname, CACHE_SETTINGS } from "../variables.mjs";
import { getAssets } from "../helpers/asset_helpers.mjs";
import { updateCache } from "../helpers/cache_helpers.mjs";
import { updateCacheFromSql } from "../helpers/cache_helpers.mjs";

const sqlQueries = yesql(path.join(dirname(), "queries/hydradx-ui/v1/stats"), {
type: "pg",
Expand All @@ -24,7 +24,7 @@ async function cacheAsset(asset, sqlClient, redisClient) {
let cacheSetting = { ...CACHE_SETTINGS["hydradxUiV1StatsTvl"] };
cacheSetting.key = cacheSetting.key + "_" + asset;

await updateCache(
await updateCacheFromSql(
sqlClient,
redisClient,
cacheSetting,
Expand Down
53 changes: 53 additions & 0 deletions jobs/cache_hydration-web_stats_job.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import yesql from "yesql";
import path from "path";
import { dirname, CACHE_SETTINGS } from "../variables.mjs";
import { updateCache } from "../helpers/cache_helpers.mjs";
import { fetchFromSql } from "../helpers/sql_helpers.mjs";

const sqlQueries = yesql(
path.join(dirname(), "queries/hydration-web/v1/stats"),
{
type: "pg",
}
);

export async function cacheHydrationWebStatsJob(sqlClient, redisClient) {
let cacheSetting = { ...CACHE_SETTINGS["hydrationWebV1Stats"] };

let result = {};

// tvl
const tvlQuery = await fetchFromSql(
sqlClient,
sqlQueries.statsTvl({ asset: null })
);
const tvl = tvlQuery.map((x) => x["tvl_usd"]).reduce((sum, x) => sum + x);
result["tvl"] = tvl;

// vol_30d
const vol_30dQuery = await fetchFromSql(sqlClient, sqlQueries.statsVol30d());
const vol_30d = vol_30dQuery[0]["volume_usd"];
result["vol_30d"] = vol_30d;

// xcm_vol_30d
const xcm_vol_30d = JSON.parse(vol_30d) / 2;
result["xcm_vol_30d"] = xcm_vol_30d;

// assets_count
const assetsCount = await fetchFromSql(
sqlClient,
sqlQueries.statsAssetsCount()
);
result["assets_count"] = assetsCount[0]["count"];

// accounts_count
const accountsCount = await fetchFromSql(
sqlClient,
sqlQueries.statsAccountsCount()
);
result["accounts_count"] = accountsCount[0]["count"];

await updateCache(redisClient, cacheSetting, JSON.stringify(result));

return true;
}
12 changes: 12 additions & 0 deletions queries/hydration-web/v1/stats/accountsCount.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- statsAccountsCount
WITH accounts AS (
SELECT args -> 'who' AS account_id
FROM event
WHERE name = 'Tokens.Endowed'
UNION
SELECT args -> 'account' AS account_id
FROM event
WHERE name = 'Balances.Endowed'
)
SELECT COUNT(DISTINCT account_id)
FROM accounts;
20 changes: 20 additions & 0 deletions queries/hydration-web/v1/stats/assetsCount.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- statsAssetsCount
WITH pools AS (
SELECT args -> 'assetA' AS asset_1, args -> 'assetB' AS asset_2
FROM event
WHERE name = 'XYK.PoolCreated'
),
omnipool_assets AS (
SELECT asset_id::text
FROM omnipool_asset
WHERE block = (SELECT MAX(block) FROM omnipool_asset)
)
SELECT COUNT(*)
FROM event
WHERE name = 'AssetRegistry.Registered'
AND args -> 'assetType' ->> '__kind' IN ('External', 'Token')
AND (
args -> 'assetId' IN (SELECT asset_1 FROM pools)
OR args -> 'assetId' IN (SELECT asset_2 FROM pools)
OR args ->> 'assetId' IN (SELECT asset_id FROM omnipool_assets)
);
25 changes: 25 additions & 0 deletions queries/hydration-web/v1/stats/tvl.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-- statsTvl

/* Returns actual TVL */

SELECT
asset_id,
round(sum(oa.hub_reserve/10^12 * leb.last_lrna_price)) as tvl_usd
FROM
lrna_every_block leb
JOIN (
SELECT
LEAST(max_leb.max_height, max_oa.max_block) AS joined_height
FROM
(SELECT MAX(height) as max_height FROM lrna_every_block) max_leb,
(SELECT MAX(block) as max_block FROM omnipool_asset) max_oa
) subq ON leb.height = subq.joined_height
JOIN omnipool_asset oa ON leb.height = oa.block
JOIN token_metadata tm ON oa.asset_id = tm.id
WHERE CASE
WHEN :asset::text IS NOT NULL
THEN asset_id = :asset
ELSE
true
END
GROUP BY 1
20 changes: 20 additions & 0 deletions queries/hydration-web/v1/stats/vol30d.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- statsVol30d
SELECT
ROUND(SUM(volume_roll_24_usd)) as volume_usd
FROM (
SELECT
symbol,
asset_id,
volume_roll_24_usd,
timestamp,
ROW_NUMBER() OVER (
PARTITION BY symbol, timestamp::date
ORDER BY timestamp DESC
) AS rn
FROM
stats_historical
) a
WHERE
rn = 1
AND
timestamp > now () - interval '30d'
5 changes: 5 additions & 0 deletions variables.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const sqlDatabase = () => "squid";

export const JOBS = {
cacheCoingeckoTickersJob: "cache-coingecko-tickers-job",
cacheHydrationWebStatsJob: "cache-hydration-web-stats-job",
cacheHydradxUiStatsTvlJob: "cache-hydradx-ui-stats-tvl-job",
cacheCoinmarketcapSummaryJob: "cache-coinmarketcap-summary-job",
};
Expand All @@ -46,6 +47,10 @@ export const CACHE_SETTINGS = {
key: "coingecko_v1_tickers",
expire_after: 12 * 60,
},
hydrationWebV1Stats: {
key: "hydration-web_v1_stats",
expire_after: 4 * 60 * 60,
},
hydradxUiV1StatsTvl: {
key: "hydradx-ui_v1_stats_tvl",
expire_after: 60 * 60,
Expand Down

0 comments on commit f7ef21b

Please sign in to comment.