diff --git a/indexer/migrations/20250822193321-add-result-index-for-transactions.js b/indexer/migrations/20250822193321-add-result-index-for-transactions.js new file mode 100644 index 00000000..96c5a933 --- /dev/null +++ b/indexer/migrations/20250822193321-add-result-index-for-transactions.js @@ -0,0 +1,14 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface) { + await queryInterface.sequelize.query( + 'CREATE INDEX transactions_result_gin_idx ON public."Transactions" USING gin (result);', + ); + }, + + async down(queryInterface) { + await queryInterface.sequelize.query('DROP INDEX IF EXISTS transactions_result_gin_idx;'); + }, +}; diff --git a/indexer/src/kadena-server/config/graphql-types.ts b/indexer/src/kadena-server/config/graphql-types.ts index 8d120e7c..6b2bdbd9 100644 --- a/indexer/src/kadena-server/config/graphql-types.ts +++ b/indexer/src/kadena-server/config/graphql-types.ts @@ -770,6 +770,8 @@ export type Query = { graphConfiguration: GraphConfiguration; /** Get the height of the block with the highest height. */ lastBlockHeight?: Maybe; + /** Get last price for a specific token in KDA */ + lastTokenPriceInKda?: Maybe; /** Get user's liquidity positions */ liquidityPositions: LiquidityPositionsConnection; /** Get information about the network. */ @@ -904,6 +906,10 @@ export type QueryGasLimitEstimateArgs = { input: Array; }; +export type QueryLastTokenPriceInKdaArgs = { + moduleName: Scalars['String']['input']; +}; + export type QueryLiquidityPositionsArgs = { after?: InputMaybe; before?: InputMaybe; @@ -3054,6 +3060,12 @@ export type QueryResolvers< >; graphConfiguration?: Resolver; lastBlockHeight?: Resolver, ParentType, ContextType>; + lastTokenPriceInKda?: Resolver< + Maybe, + ParentType, + ContextType, + RequireFields + >; liquidityPositions?: Resolver< ResolversTypes['LiquidityPositionsConnection'], ParentType, diff --git a/indexer/src/kadena-server/config/schema.graphql b/indexer/src/kadena-server/config/schema.graphql index ffff5590..0096c1cd 100644 --- a/indexer/src/kadena-server/config/schema.graphql +++ b/indexer/src/kadena-server/config/schema.graphql @@ -431,6 +431,11 @@ type Query { protocolAddress: String ): DexMetrics! @complexity(value: 1) + """ + Get last price for a specific token in KDA + """ + lastTokenPriceInKda(moduleName: String!): Decimal + """ Get price for a specific token """ diff --git a/indexer/src/kadena-server/resolvers/index.ts b/indexer/src/kadena-server/resolvers/index.ts index b12fa8ea..3fc1d67b 100644 --- a/indexer/src/kadena-server/resolvers/index.ts +++ b/indexer/src/kadena-server/resolvers/index.ts @@ -104,6 +104,7 @@ import { transfersNonFungibleChainAccountResolver } from '@/kadena-server/resolv import { totalCountNonFungibleChainAccountTransfersConnectionResolver } from '@/kadena-server/resolvers/fields/non-fungible-chain-account/transfers-connection/total-count-non-fungible-chain-account-transfers-connection-resolver'; import { totalCountQueryBlocksFromHeightConnectionResolver } from '@/kadena-server/resolvers/fields/query-blocks-from-height-connection/total-count-query-blocks-from-height-connection-resolver'; import { transactionsByPactCodeQueryResolver } from '@/kadena-server/resolvers/query/transactions-by-pact-code-query-resolver'; +import { lastTokenPriceInKdaQueryResolver } from '@/kadena-server/resolvers/query/last-token-price-in-kda-resolver'; /** * Complete resolver map for the GraphQL API * @@ -157,6 +158,7 @@ export const resolvers: Resolvers = { transactionsByPublicKey: transactionsByPublicKeyQueryResolver, transfers: transfersQueryResolver, tokens: tokensQueryResolver, + lastTokenPriceInKda: lastTokenPriceInKdaQueryResolver, pool: poolQueryResolver, poolTransactions: poolTransactionsQueryResolver, liquidityPositions: liquidityPositionsQueryResolver, diff --git a/indexer/src/kadena-server/resolvers/query/last-token-price-in-kda-resolver.ts b/indexer/src/kadena-server/resolvers/query/last-token-price-in-kda-resolver.ts new file mode 100644 index 00000000..891f324c --- /dev/null +++ b/indexer/src/kadena-server/resolvers/query/last-token-price-in-kda-resolver.ts @@ -0,0 +1,33 @@ +import { rootPgPool } from '@/config/database'; +import { ResolverContext } from '@/kadena-server/config/apollo-server-config'; +import { QueryLastTokenPriceInKdaArgs, QueryResolvers } from '@/kadena-server/config/graphql-types'; +import Decimal from 'decimal.js'; + +export const lastTokenPriceInKdaQueryResolver: QueryResolvers['lastTokenPriceInKda'] = + async (_parent: unknown, args: QueryLastTokenPriceInKdaArgs) => { + const query = ` + SELECT t.result + FROM public."Transactions" t + WHERE t.result::text LIKE '%' || $1 || '%' + ORDER BY t.creationtime DESC, t.id DESC + LIMIT 1 + `; + + const res: any = await rootPgPool.query(query, [args.moduleName]); + + const data = res.rows?.[0]?.result?.data; + if (!data?.[0]?.token || !data?.[1]?.token) { + return null; + } + + const isFirstElementTheKdaToken = data?.[0]?.token === 'coin'; + const firstValue = + data?.[0]?.amount?.decimal ?? data?.[0]?.amount?.integer ?? data?.[0]?.amount; + const secondValue = + data?.[1]?.amount?.decimal ?? data?.[1]?.amount?.integer ?? data?.[1]?.amount; + + const kadenaValue = isFirstElementTheKdaToken ? firstValue : secondValue; + const tokenValue = isFirstElementTheKdaToken ? secondValue : firstValue; + const amount = new Decimal(kadenaValue).div(new Decimal(tokenValue)).toFixed(12); + return amount; + };