diff --git a/packages/output-scan/.env.example b/packages/output-scan/.env.example index f563cfc07..aee2f0389 100644 --- a/packages/output-scan/.env.example +++ b/packages/output-scan/.env.example @@ -1,4 +1,5 @@ WS_ENDPOINT=wss://kusama-rpc.polkadot.io +ASSET_HUB_ENDPOINTS=wss://polkadot-asset-hub-rpc.polkadot.io;wss://statemint.api.onfinality.io/public-ws;wss://dot-rpc.stakeworld.io/assethub MONGO_URL=mongodb://127.0.0.1:27017 MONGO_DB_NAME=dotreasury-ksm diff --git a/packages/output-scan/package.json b/packages/output-scan/package.json index 9513f22ce..16823e808 100644 --- a/packages/output-scan/package.json +++ b/packages/output-scan/package.json @@ -13,6 +13,7 @@ "@osn/scan-common": "0.6.11", "@polkadot/api": "12.0.2", "bignumber.js": "^9.1.1", + "cron": "^3.1.7", "dotenv": "16.1.4", "lodash.findlast": "^4.6.0", "lodash.isempty": "^4.4.0", diff --git a/packages/output-scan/src/business/assethub/api.js b/packages/output-scan/src/business/assethub/api.js new file mode 100644 index 000000000..b3e1be6ea --- /dev/null +++ b/packages/output-scan/src/business/assethub/api.js @@ -0,0 +1,33 @@ +const { WsProvider, ApiPromise } = require("@polkadot/api"); + +let api = null; +let provider = null; + +function getEndPoints() { + const wsEndpoint = process.env.ASSET_HUB_ENDPOINTS; + if (!wsEndpoint) { + throw new Error("ASSET_HUB_ENDPOINTS not set"); + } + + if ((wsEndpoint || "").includes(";")) { + return wsEndpoint.split(";"); + } else { + return wsEndpoint; + } +} + +async function getAssetHubApi() { + if (api) { + return api; + } + + const endpoints = getEndPoints(); + provider = new WsProvider(endpoints, 1000); + api = await ApiPromise.create({ provider }); + console.log(`Connected to asset hub endpoint:`, process.env.WS_ENDPOINT); + return api; +} + +module.exports = { + getAssetHubApi, +} diff --git a/packages/output-scan/src/business/assethub/query.js b/packages/output-scan/src/business/assethub/query.js new file mode 100644 index 000000000..70b093d86 --- /dev/null +++ b/packages/output-scan/src/business/assethub/query.js @@ -0,0 +1,58 @@ +const { getAssetHubApi } = require("./api"); +require("bignumber.js") +const { getStatusCollection } = require("../../mongo"); +const { CronJob } = require("cron"); +const { + env: { currentChain }, + consts: { + CHAINS, + } +} = require("@osn/scan-common"); + +const account = "14xmwinmCEz6oRrFdczHKqHgWNMiCysE2KrA4jXXAAM1Eogk"; +const usdtAssetId = 1984; +const usdcAssetId = 1337; + +async function queryAsset(api, assetId) { + const optionalStorage = await api.query.assets.account(assetId, account); + if (optionalStorage.isNone) { + return 0; + } + + return optionalStorage.unwrap().balance.toString(); +} + +async function queryDot(api) { + const storage = await api.query.system.account(account); + const { free, reserved } = storage.data; + return (free.toBigInt() + reserved.toBigInt()).toString(); +} + +async function saveAssetHubStats(obj) { + const statusCol = await getStatusCollection(); + await statusCol.findOneAndUpdate( + { name: "assethub-treasury-stats" }, + { $set: { value: obj } }, + { upsert: true } + ); +} + +async function queryAndSaveAssetHubAssets() { + const api = await getAssetHubApi(); + const usdt = await queryAsset(api, usdtAssetId); + const usdc = await queryAsset(api, usdcAssetId); + const dot = await queryDot(api); + + await saveAssetHubStats({ usdt, usdc, dot }); +} + +function startAssetHubJob() { + if (CHAINS.POLKADOT === currentChain()) { + new CronJob("0 */1 * * * *", queryAndSaveAssetHubAssets, null, true, "Asia/Shanghai"); + } +} + +module.exports = { + queryAndSaveAssetHubAssets, + startAssetHubJob, +} diff --git a/packages/output-scan/src/index.js b/packages/output-scan/src/index.js index 82eaade9a..1c0ff066d 100644 --- a/packages/output-scan/src/index.js +++ b/packages/output-scan/src/index.js @@ -9,6 +9,7 @@ const { }, env: { isUseMetaDb }, } = require("@osn/scan-common"); +const { startAssetHubJob } = require("./business/assethub/query"); async function main() { await subscribeChainHeight(); @@ -16,6 +17,7 @@ async function main() { await updateSpecs(); checkSpecs(); } + startAssetHubJob(); await beginScan(); } diff --git a/packages/output-scan/src/play.js b/packages/output-scan/src/play.js index 57dc536e0..2637ce3d9 100644 --- a/packages/output-scan/src/play.js +++ b/packages/output-scan/src/play.js @@ -3,6 +3,7 @@ const { handleBlock } = require("./scan/block"); const { chain: { getApi, setSpecHeights } } = require("@osn/scan-common"); +const { queryAndSaveAssetHubAssets } = require("./business/assethub/query"); async function test() { const blockHeights = [ diff --git a/packages/server/src/features/assethub/routes.js b/packages/server/src/features/assethub/routes.js new file mode 100644 index 000000000..94ac96084 --- /dev/null +++ b/packages/server/src/features/assethub/routes.js @@ -0,0 +1,12 @@ +const Router = require("koa-router"); +const { getOutputStatusCollection } = require("../../mongo"); + +const router = new Router(); + +router.get("/assethub/assets", async (ctx) => { + const col = await getOutputStatusCollection(); + const record = await col.findOne({ name: "assethub-treasury-stats" }) + ctx.body = record?.value; +}); + +module.exports = router; diff --git a/packages/server/src/routes.js b/packages/server/src/routes.js index 2260ede52..af7965e56 100644 --- a/packages/server/src/routes.js +++ b/packages/server/src/routes.js @@ -19,6 +19,7 @@ const chainFeatureRouters = [ require("./features/overview/routes"), require("./features/period/routes"), require("./features/centrifuge/routes"), + require("./features/assethub/routes"), ]; const commonFeatureRouters = [ diff --git a/yarn.lock b/yarn.lock index 1a986878c..ed2bf1e63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1514,6 +1514,7 @@ __metadata: "@osn/scan-common": 0.6.11 "@polkadot/api": 12.0.2 bignumber.js: ^9.1.1 + cron: ^3.1.7 dotenv: 16.1.4 jest: 29.5.0 lodash.findlast: ^4.6.0