UNPKG

@fewcha/aptos

Version:
618 lines (565 loc) 19.4 kB
import { AnyNumber } from "../bcs/types"; import { HexString, MaybeHexString } from "../utils"; import { GetAccountTokensCountQuery, GetAccountCoinsDataQuery, GetAccountCurrentTokensQuery, GetAccountTransactionsCountQuery, GetAccountTransactionsDataQuery, GetNumberOfDelegatorsQuery, GetDelegatedStakingActivitiesQuery, GetIndexerLedgerInfoQuery, GetTokenActivitiesCountQuery, GetTokenActivitiesQuery, GetTokenDataQuery, GetTokenOwnersDataQuery, GetTopUserTransactionsQuery, GetUserTransactionsQuery, GetOwnedTokensQuery, GetTokenOwnedFromCollectionQuery, GetCollectionDataQuery, GetCollectionsWithOwnedTokensQuery, GetTokenCurrentOwnerDataQuery, } from "../indexer/generated/operations"; import { GetAccountTokensCount, GetAccountCoinsData, GetAccountCurrentTokens, GetAccountTransactionsCount, GetAccountTransactionsData, GetNumberOfDelegators, GetDelegatedStakingActivities, GetIndexerLedgerInfo, GetTokenActivities, GetTokenActivitiesCount, GetTokenData, GetTokenOwnersData, GetTopUserTransactions, GetUserTransactions, GetOwnedTokens, GetTokenOwnedFromCollection, GetCollectionData, GetCollectionsWithOwnedTokens, GetTokenCurrentOwnerData, } from "../indexer/generated/queries"; import { ClientConfig, post } from "../client"; import { ApiError } from "./aptos_client"; /** * Controls the number of results that are returned and the starting position of those results. * limit specifies the maximum number of items or records to return in a query result. * offset parameter specifies the starting position of the query result within the set of data. * For example, if you want to retrieve records 11-20, * you would set the offset parameter to 10 (i.e., the index of the first record to retrieve is 10) * and the limit parameter to 10 (i.e., the number of records to retrieve is 10)) */ interface PaginationArgs { offset?: AnyNumber; limit?: number; } type TokenStandard = "v1" | "v2"; type GraphqlQuery = { query: string; variables?: {}; }; /** * Provides methods for retrieving data from Aptos Indexer. * For more detailed Queries specification see * {@link https://cloud.hasura.io/public/graphiql?endpoint=https://indexer.mainnet.aptoslabs.com/v1/graphql} */ export class IndexerClient { readonly endpoint: string; readonly config: ClientConfig | undefined; /** * @param endpoint URL of the Aptos Indexer API endpoint. */ constructor(endpoint: string, config?: ClientConfig) { this.endpoint = endpoint; this.config = config; } /** * Indexer only accepts address in the long format, i.e a 66 chars long -> 0x<64 chars> * This method makes sure address is 66 chars long. * @param address */ static validateAddress(address: string): void { if (address.length < 66) { throw new Error(`${address} is less than 66 chars long.`); } } /** * Makes axios client call to fetch data from Aptos Indexer. * * @param graphqlQuery A GraphQL query to pass in the `data` axios call. */ async queryIndexer<T>(graphqlQuery: GraphqlQuery): Promise<T> { const response = await post<GraphqlQuery, any>({ url: this.endpoint, body: graphqlQuery, overrides: { WITH_CREDENTIALS: false, ...this.config }, }); if (response.data.errors) { throw new ApiError( response.data.errors[0].extensions.code, JSON.stringify({ message: response.data.errors[0].message, error_code: response.data.errors[0].extensions.code, }), ); } return response.data.data; } /** * Queries Indexer Ledger Info * * @returns GetLedgerInfoQuery response type */ async getIndexerLedgerInfo(): Promise<GetIndexerLedgerInfoQuery> { const graphqlQuery = { query: GetIndexerLedgerInfo, }; return this.queryIndexer(graphqlQuery); } /** * Queries an Aptos account's NFTs by owner address * * @param ownerAddress Hex-encoded 32 byte Aptos account address * @returns GetAccountCurrentTokensQuery response type */ async getAccountNFTs(ownerAddress: MaybeHexString, options?: PaginationArgs): Promise<GetAccountCurrentTokensQuery> { const address = HexString.ensure(ownerAddress).hex(); IndexerClient.validateAddress(address); const graphqlQuery = { query: GetAccountCurrentTokens, variables: { address, offset: options?.offset, limit: options?.limit }, }; return this.queryIndexer<GetAccountCurrentTokensQuery>(graphqlQuery); } /** * Queries a token activities by token id hash * * @param idHash token id hash * @returns GetTokenActivitiesQuery response type */ async getTokenActivities(idHash: string, options?: PaginationArgs): Promise<GetTokenActivitiesQuery> { const graphqlQuery = { query: GetTokenActivities, variables: { idHash, offset: options?.offset, limit: options?.limit }, }; return this.queryIndexer(graphqlQuery); } /** * Queries an account coin data * * @param ownerAddress Owner address * @returns GetAccountCoinsDataQuery response type */ async getAccountCoinsData(ownerAddress: MaybeHexString, options?: PaginationArgs): Promise<GetAccountCoinsDataQuery> { const address = HexString.ensure(ownerAddress).hex(); IndexerClient.validateAddress(address); const graphqlQuery = { query: GetAccountCoinsData, variables: { owner_address: address, offset: options?.offset, limit: options?.limit }, }; return this.queryIndexer(graphqlQuery); } /** * Gets the count of tokens owned by an account * * @param ownerAddress Owner address * @returns AccountTokensCountQuery response type */ async getAccountTokensCount(ownerAddress: MaybeHexString): Promise<GetAccountTokensCountQuery> { const address = HexString.ensure(ownerAddress).hex(); IndexerClient.validateAddress(address); const graphqlQuery = { query: GetAccountTokensCount, variables: { owner_address: address }, }; return this.queryIndexer(graphqlQuery); } /** * Gets the count of transactions submitted by an account * * @param address Account address * @returns GetAccountTransactionsCountQuery response type */ async getAccountTransactionsCount(accountAddress: MaybeHexString): Promise<GetAccountTransactionsCountQuery> { const address = HexString.ensure(accountAddress).hex(); IndexerClient.validateAddress(address); const graphqlQuery = { query: GetAccountTransactionsCount, variables: { address }, }; return this.queryIndexer(graphqlQuery); } /** * Queries an account transactions data * * @param address Account address * @returns GetAccountTransactionsDataQuery response type */ async getAccountTransactionsData( accountAddress: MaybeHexString, options?: PaginationArgs, ): Promise<GetAccountTransactionsDataQuery> { const address = HexString.ensure(accountAddress).hex(); IndexerClient.validateAddress(address); const graphqlQuery = { query: GetAccountTransactionsData, variables: { address, offset: options?.offset, limit: options?.limit }, }; return this.queryIndexer(graphqlQuery); } /** * Queries delegated staking activities * * @param delegatorAddress Delegator address * @param poolAddress Pool address * @returns GetDelegatedStakingActivitiesQuery response type */ async getDelegatedStakingActivities( delegatorAddress: MaybeHexString, poolAddress: MaybeHexString, ): Promise<GetDelegatedStakingActivitiesQuery> { const delegator = HexString.ensure(delegatorAddress).hex(); const pool = HexString.ensure(poolAddress).hex(); IndexerClient.validateAddress(delegator); IndexerClient.validateAddress(pool); const graphqlQuery = { query: GetDelegatedStakingActivities, variables: { delegatorAddress: delegator, poolAddress: pool, }, }; return this.queryIndexer(graphqlQuery); } /** * Gets the count of token's activities * * @param tokenId Token ID * @returns GetTokenActivitiesCountQuery response type */ async getTokenActivitiesCount(tokenId: string): Promise<GetTokenActivitiesCountQuery> { const graphqlQuery = { query: GetTokenActivitiesCount, variables: { token_id: tokenId }, }; return this.queryIndexer(graphqlQuery); } /** * Queries token data * * @param tokenId Token ID address * @returns GetTokenDataQuery response type */ async getTokenData( tokenId: string, extraArgs?: { tokenStandard?: TokenStandard; }, ): Promise<GetTokenDataQuery> { const tokenAddress = HexString.ensure(tokenId).hex(); IndexerClient.validateAddress(tokenAddress); const whereCondition: any = { token_data_id: { _eq: tokenAddress }, }; if (extraArgs?.tokenStandard) { whereCondition.token_standard = { _eq: extraArgs?.tokenStandard }; } const graphqlQuery = { query: GetTokenData, variables: { where_condition: whereCondition }, }; return this.queryIndexer(graphqlQuery); } /** * Queries token owners data. This query returns historical owners data * To fetch token v2 standard, pass in the optional `tokenStandard` parameter and * dont pass `propertyVersion` parameter (as propertyVersion only compatible with v1 standard) * * @param tokenId Token ID * @param propertyVersion Property version (optional) - only compatible with token v1 standard * @returns GetTokenOwnersDataQuery response type */ async getTokenOwnersData( tokenId: string, propertyVersion?: number, extraArgs?: { tokenStandard?: TokenStandard; }, ): Promise<GetTokenOwnersDataQuery> { const tokenAddress = HexString.ensure(tokenId).hex(); IndexerClient.validateAddress(tokenAddress); const whereCondition: any = { token_data_id: { _eq: tokenAddress }, }; if (propertyVersion) { whereCondition.property_version_v1 = { _eq: propertyVersion }; } if (extraArgs?.tokenStandard) { whereCondition.token_standard = { _eq: extraArgs?.tokenStandard }; } const graphqlQuery = { query: GetTokenOwnersData, variables: { where_condition: whereCondition }, }; return this.queryIndexer(graphqlQuery); } /** * Queries token current owner data. This query returns the current token owner data. * To fetch token v2 standard, pass in the optional `tokenStandard` parameter and * dont pass `propertyVersion` parameter (as propertyVersion only compatible with v1 standard) * * @param tokenId Token ID * @param propertyVersion Property version (optional) - only compatible with token v1 standard * @returns GetTokenCurrentOwnerDataQuery response type */ async getTokenCurrentOwnerData( tokenId: string, propertyVersion?: number, extraArgs?: { tokenStandard?: TokenStandard; }, ): Promise<GetTokenCurrentOwnerDataQuery> { const tokenAddress = HexString.ensure(tokenId).hex(); IndexerClient.validateAddress(tokenAddress); const whereCondition: any = { token_data_id: { _eq: tokenAddress }, amount: { _gt: "0" }, }; if (propertyVersion) { whereCondition.property_version_v1 = { _eq: propertyVersion }; } if (extraArgs?.tokenStandard) { whereCondition.token_standard = { _eq: extraArgs?.tokenStandard }; } const graphqlQuery = { query: GetTokenCurrentOwnerData, variables: { where_condition: whereCondition }, }; return this.queryIndexer(graphqlQuery); } /** * Queries top user transactions * * @param limit * @returns GetTopUserTransactionsQuery response type */ async getTopUserTransactions(limit: number): Promise<GetTopUserTransactionsQuery> { const graphqlQuery = { query: GetTopUserTransactions, variables: { limit }, }; return this.queryIndexer(graphqlQuery); } /** * Queries top user transactions * * @returns GetUserTransactionsQuery response type */ async getUserTransactions(startVersion?: number, options?: PaginationArgs): Promise<GetUserTransactionsQuery> { const graphqlQuery = { query: GetUserTransactions, variables: { start_version: startVersion, offset: options?.offset, limit: options?.limit }, }; return this.queryIndexer(graphqlQuery); } /** * Queries current number of delegators in a pool * * @returns GetNumberOfDelegatorsQuery response type */ async getNumberOfDelegators(poolAddress: MaybeHexString): Promise<GetNumberOfDelegatorsQuery> { const address = HexString.ensure(poolAddress).hex(); IndexerClient.validateAddress(address); const graphqlQuery = { query: GetNumberOfDelegators, variables: { poolAddress: address }, }; return this.queryIndexer(graphqlQuery); } /** * Queries account's current owned tokens. * This query returns all tokens (v1 and v2 standards) an account owns, including NFTs, fungible, soulbound, etc. * If you want to get only the token from a specific standrd, you can pass an optional tokenStandard param * @example An example of how to pass a specific token standard * ``` * { * tokenStandard:"v2" * } * ``` * @param ownerAddress The token owner address we want to get the tokens for * @returns GetOwnedTokensQuery response type */ async getOwnedTokens( ownerAddress: MaybeHexString, extraArgs?: { tokenStandard?: TokenStandard; options?: PaginationArgs; }, ): Promise<GetOwnedTokensQuery> { const address = HexString.ensure(ownerAddress).hex(); IndexerClient.validateAddress(address); const whereCondition: any = { owner_address: { _eq: address }, amount: { _gt: 0 }, }; if (extraArgs?.tokenStandard) { whereCondition.token_standard = { _eq: extraArgs?.tokenStandard }; } const graphqlQuery = { query: GetOwnedTokens, variables: { where_condition: whereCondition, offset: extraArgs?.options?.offset, limit: extraArgs?.options?.limit, }, }; return this.queryIndexer(graphqlQuery); } /** * Queries all tokens of a specific collection that an account owns by the collection address * * @param ownerAddress owner address that owns the tokens * @param collectionAddress the collection address * @returns GetTokenOwnedFromCollectionQuery response type */ async getTokenOwnedFromCollectionAddress( ownerAddress: MaybeHexString, collectionAddress: string, extraArgs?: { tokenStandard?: TokenStandard; options?: PaginationArgs; }, ): Promise<GetTokenOwnedFromCollectionQuery> { const ownerHexAddress = HexString.ensure(ownerAddress).hex(); IndexerClient.validateAddress(ownerHexAddress); const collectionHexAddress = HexString.ensure(collectionAddress).hex(); IndexerClient.validateAddress(collectionHexAddress); const whereCondition: any = { owner_address: { _eq: ownerHexAddress }, current_token_data: { collection_id: { _eq: collectionHexAddress } }, amount: { _gt: 0 }, }; if (extraArgs?.tokenStandard) { whereCondition.token_standard = { _eq: extraArgs?.tokenStandard }; } const graphqlQuery = { query: GetTokenOwnedFromCollection, variables: { where_condition: whereCondition, offset: extraArgs?.options?.offset, limit: extraArgs?.options?.limit, }, }; return this.queryIndexer(graphqlQuery); } /** * Queries all tokens of a specific collection that an account owns by the collection name and collection * creator address * * @param ownerAddress owner address that owns the tokens * @param collectionName the collection name * @param creatorAddress the collection creator address * @returns GetTokenOwnedFromCollectionQuery response type */ async getTokenOwnedFromCollectionNameAndCreatorAddress( ownerAddress: MaybeHexString, collectionName: string, creatorAddress: MaybeHexString, extraArgs?: { tokenStandard?: TokenStandard; options?: PaginationArgs; }, ): Promise<GetTokenOwnedFromCollectionQuery> { const collectionAddress = await this.getCollectionAddress(creatorAddress, collectionName, extraArgs); const tokens = await this.getTokenOwnedFromCollectionAddress(ownerAddress, collectionAddress, extraArgs); return tokens; } /** * Queries data of a specific collection by the collection creator address and the collection name. * * if, for some reason, a creator account has 2 collections with the same name in v1 and v2, * can pass an optional `tokenStandard` parameter to query a specific standard * * @param creatorAddress the collection creator address * @param collectionName the collection name * @returns GetCollectionDataQuery response type */ async getCollectionData( creatorAddress: MaybeHexString, collectionName: string, extraArgs?: { tokenStandard?: TokenStandard; options?: PaginationArgs; }, ): Promise<GetCollectionDataQuery> { const address = HexString.ensure(creatorAddress).hex(); IndexerClient.validateAddress(address); const whereCondition: any = { collection_name: { _eq: collectionName }, creator_address: { _eq: address }, }; if (extraArgs?.tokenStandard) { whereCondition.token_standard = { _eq: extraArgs?.tokenStandard }; } const graphqlQuery = { query: GetCollectionData, variables: { where_condition: whereCondition, offset: extraArgs?.options?.offset, limit: extraArgs?.options?.limit, }, }; return this.queryIndexer(graphqlQuery); } /** * Queries a collection address. * * @param creatorAddress the collection creator address * @param collectionName the collection name * @returns the collection address */ async getCollectionAddress( creatorAddress: MaybeHexString, collectionName: string, extraArgs?: { tokenStandard?: TokenStandard; }, ): Promise<string> { return (await this.getCollectionData(creatorAddress, collectionName, extraArgs)).current_collections_v2[0] .collection_id; } /** * Queries for all collections that an account has tokens for. * * @param ownerAddress the account address that owns the tokens * @returns GetCollectionsWithOwnedTokensQuery response type */ async getCollectionsWithOwnedTokens( ownerAddress: MaybeHexString, extraArgs?: { tokenStandard?: TokenStandard; options?: PaginationArgs; }, ): Promise<GetCollectionsWithOwnedTokensQuery> { const ownerHexAddress = HexString.ensure(ownerAddress).hex(); IndexerClient.validateAddress(ownerHexAddress); const whereCondition: any = { owner_address: { _eq: ownerHexAddress }, }; if (extraArgs?.tokenStandard) { whereCondition.current_collection = { token_standard: { _eq: extraArgs?.tokenStandard } }; } const graphqlQuery = { query: GetCollectionsWithOwnedTokens, variables: { where_condition: whereCondition, offset: extraArgs?.options?.offset, limit: extraArgs?.options?.limit, }, }; return this.queryIndexer(graphqlQuery); } }