diff --git a/src/graphql/resolvers/index.ts b/src/graphql/resolvers/index.ts index 43fd8a8..b238e9f 100644 --- a/src/graphql/resolvers/index.ts +++ b/src/graphql/resolvers/index.ts @@ -449,16 +449,18 @@ export const resolvers = { }, radixTVL: async (...params: unknown[]) => { const { dataSources } = params[2] as ContextValue; - const result = commonHandler( - (await dataSources.radixPromAPI.getRadixTVL()) as Response, - ); + const { status, data } = await dataSources.radixAPI.getRadixTVL(); - if (!result) return; + if (status === "error") return; - return result.map((res) => ({ - metric: { instance: "radix", validator_address: res.metric.address }, - TVL: res.value[1], - })); + const { address, TVL } = data as NonNullable; + + return [ + { + metric: { instance: "radix", validator_address: address }, + TVL, + }, + ]; }, radixUsers: async (...params: unknown[]) => { const { dataSources } = params[2] as ContextValue; diff --git a/src/graphql/routes/radix-api.ts b/src/graphql/routes/radix-api.ts index 3eec163..cbc56d1 100644 --- a/src/graphql/routes/radix-api.ts +++ b/src/graphql/routes/radix-api.ts @@ -1,5 +1,8 @@ +import type { DataSourceConfig } from "@apollo/datasource-rest"; import { RESTDataSource } from "@apollo/datasource-rest"; +import { CoinGeckoDataSource } from "../utils/coingecko-data"; + const { RADIX_URL } = process.env; if (!RADIX_URL) { @@ -14,8 +17,22 @@ type RadixResponse = { }; }; +const validatorAddress = + "validator_rdx1swkmn6yvrqjzpaytvug5fp0gzfy9zdzq7j7nlxe8wgjpg76vdcma8p"; + +// https://dashboard.radixdlt.com/network-staking +// https://radix-babylon-gateway-api.redoc.ly/#tag/Status + export class RadixAPI extends RESTDataSource { override baseURL = `${(RADIX_URL as string).replace(/\/$/, "")}/`; + private baseGatewayURL = "https://mainnet-gateway.radixdlt.com/"; + private gecko: CoinGeckoDataSource; + + constructor(options: DataSourceConfig) { + super(options); + + this.gecko = new CoinGeckoDataSource(options); + } async getTotalRadixSupply(): Promise { return this.post("token/native", { @@ -30,6 +47,47 @@ export class RadixAPI extends RESTDataSource { }); } + async getRadixTVL() { + const [radixResponse, coinPrice] = await Promise.all([ + this.post(`${this.baseGatewayURL}state/validators/list`, { + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + network_identifier: { + network: "mainnet", + }, + validator_identifier: { + address: validatorAddress, + }, + }), + }), + this.gecko.getCoinPrice("radix"), + ]); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const validator = radixResponse.validators.items.find((i: any) => + (i.address as string).includes(validatorAddress), + ); + + if (!validator) { + return { + status: "error", + }; + } + + const lockedUnit = validator.locked_owner_stake_unit_vault.balance; + const TVL = lockedUnit * Number(coinPrice); + + return { + status: "ok", + data: { + TVL, + address: validatorAddress, + }, + }; + } + async getRadixUnbondingTime() { const unbondingTime = "1-3 weeks (500 epochs)"; diff --git a/src/graphql/typedefs/index.ts b/src/graphql/typedefs/index.ts index dc7a9d0..866af1a 100644 --- a/src/graphql/typedefs/index.ts +++ b/src/graphql/typedefs/index.ts @@ -236,7 +236,7 @@ export const typeDefs = `#graphql TVL: String } - type RadixTVLResult { + type RadixTVLResult @cacheControl(maxAge: ${defaultMaxAge}) { metric: AddressAndInstanceMetric TVL: String }