diff --git a/api-schema.graphql b/api-schema.graphql index 0473771..796fade 100644 --- a/api-schema.graphql +++ b/api-schema.graphql @@ -362,6 +362,7 @@ type Query { anonFindOneCommunity(slug: String!): Community anonRequestIdentityChallenge(input: RequestIdentityChallengeInput!): IdentityChallenge appConfig: AppConfig! + currencies: [Currency!]! me: User solanaGetBalance(account: String!): String solanaGetTokenAccounts(account: String!): JSON diff --git a/libs/api/core/data-access/src/index.ts b/libs/api/core/data-access/src/index.ts index 5c4dc38..71bcac1 100644 --- a/libs/api/core/data-access/src/index.ts +++ b/libs/api/core/data-access/src/index.ts @@ -4,6 +4,7 @@ export * from './lib/api-core.service' export * from './lib/dto/paging.input' export * from './lib/entity/app-config.entity' export * from './lib/entity/app-context' +export * from './lib/entity/currency.entity' export * from './lib/entity/paging-meta.entity' export * from './lib/entity/paging-response.entity' export * from './lib/helpers/ellipsify' diff --git a/libs/api/price/data-access/src/lib/entity/currency.entity.ts b/libs/api/core/data-access/src/lib/entity/currency.entity.ts similarity index 100% rename from libs/api/price/data-access/src/lib/entity/currency.entity.ts rename to libs/api/core/data-access/src/lib/entity/currency.entity.ts diff --git a/libs/api/core/feature/src/lib/api-core.resolver.ts b/libs/api/core/feature/src/lib/api-core.resolver.ts index b30be20..f97481b 100644 --- a/libs/api/core/feature/src/lib/api-core.resolver.ts +++ b/libs/api/core/feature/src/lib/api-core.resolver.ts @@ -1,5 +1,5 @@ -import { ApiCoreService, AppConfig } from '@tokengator-mint/api-core-data-access' import { Float, Query, Resolver } from '@nestjs/graphql' +import { ApiCoreService, AppConfig, Currency } from '@tokengator-mint/api-core-data-access' @Resolver() export class ApiCoreResolver { @@ -10,6 +10,11 @@ export class ApiCoreResolver { return this.service.config.appConfig } + @Query(() => [Currency]) + async currencies(): Promise { + return this.service.data.currency.findMany({ orderBy: { name: 'asc' } }) + } + @Query(() => Float) uptime() { return this.service.uptime() diff --git a/libs/api/price/data-access/src/lib/entity/price.entity.ts b/libs/api/price/data-access/src/lib/entity/price.entity.ts index 6622520..5f7d988 100644 --- a/libs/api/price/data-access/src/lib/entity/price.entity.ts +++ b/libs/api/price/data-access/src/lib/entity/price.entity.ts @@ -1,6 +1,6 @@ import { Field, Int, ObjectType } from '@nestjs/graphql' +import { Currency } from '@tokengator-mint/api-core-data-access' import { Preset } from '@tokengator-mint/api-preset-data-access' -import { Currency } from './currency.entity' @ObjectType() export class Price { diff --git a/libs/sdk/src/generated/graphql-sdk.ts b/libs/sdk/src/generated/graphql-sdk.ts index 251301a..8820856 100644 --- a/libs/sdk/src/generated/graphql-sdk.ts +++ b/libs/sdk/src/generated/graphql-sdk.ts @@ -566,6 +566,7 @@ export type Query = { anonFindOneCommunity?: Maybe anonRequestIdentityChallenge?: Maybe appConfig: AppConfig + currencies: Array me?: Maybe solanaGetBalance?: Maybe solanaGetTokenAccounts?: Maybe @@ -1544,6 +1545,14 @@ export type AppConfigDetailsFragment = { authTwitterEnabled: boolean } +export type CurrencyDetailsFragment = { + __typename?: 'Currency' + decimals: number + mint: string + name: string + symbol: string +} + export type PagingMetaDetailsFragment = { __typename?: 'PagingMeta' currentPage: number @@ -1575,6 +1584,13 @@ export type AppConfigQuery = { } } +export type CurrenciesQueryVariables = Exact<{ [key: string]: never }> + +export type CurrenciesQuery = { + __typename?: 'Query' + items: Array<{ __typename?: 'Currency'; decimals: number; mint: string; name: string; symbol: string }> +} + export type IdentityDetailsFragment = { __typename?: 'Identity' createdAt: Date @@ -2145,14 +2161,6 @@ export type UserFindOnePresetQuery = { } | null } -export type CurrencyDetailsFragment = { - __typename?: 'Currency' - decimals: number - mint: string - name: string - symbol: string -} - export type PriceDetailsFragment = { __typename?: 'Price' createdAt?: Date | null @@ -3073,6 +3081,14 @@ export const AppConfigDocument = gql` } ${AppConfigDetailsFragmentDoc} ` +export const CurrenciesDocument = gql` + query currencies { + items: currencies { + ...CurrencyDetails + } + } + ${CurrencyDetailsFragmentDoc} +` export const AdminFindManyIdentityDocument = gql` query adminFindManyIdentity($input: AdminFindManyIdentityInput!) { items: adminFindManyIdentity(input: $input) { @@ -3567,6 +3583,7 @@ const AnonFindManyCommunityDocumentString = print(AnonFindManyCommunityDocument) const AnonFindOneCommunityDocumentString = print(AnonFindOneCommunityDocument) const UptimeDocumentString = print(UptimeDocument) const AppConfigDocumentString = print(AppConfigDocument) +const CurrenciesDocumentString = print(CurrenciesDocument) const AdminFindManyIdentityDocumentString = print(AdminFindManyIdentityDocument) const AdminCreateIdentityDocumentString = print(AdminCreateIdentityDocument) const AdminDeleteIdentityDocumentString = print(AdminDeleteIdentityDocument) @@ -4158,6 +4175,21 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = variables, ) }, + currencies( + variables?: CurrenciesQueryVariables, + requestHeaders?: GraphQLClientRequestHeaders, + ): Promise<{ data: CurrenciesQuery; errors?: GraphQLError[]; extensions?: any; headers: Headers; status: number }> { + return withWrapper( + (wrappedRequestHeaders) => + client.rawRequest(CurrenciesDocumentString, variables, { + ...requestHeaders, + ...wrappedRequestHeaders, + }), + 'currencies', + 'query', + variables, + ) + }, adminFindManyIdentity( variables: AdminFindManyIdentityQueryVariables, requestHeaders?: GraphQLClientRequestHeaders, diff --git a/libs/sdk/src/graphql/feature-core.graphql b/libs/sdk/src/graphql/feature-core.graphql index 630a052..8e7e31f 100644 --- a/libs/sdk/src/graphql/feature-core.graphql +++ b/libs/sdk/src/graphql/feature-core.graphql @@ -8,6 +8,13 @@ fragment AppConfigDetails on AppConfig { authTwitterEnabled } +fragment CurrencyDetails on Currency { + decimals + mint + name + symbol +} + fragment PagingMetaDetails on PagingMeta { currentPage isFirstPage @@ -27,3 +34,9 @@ query appConfig { ...AppConfigDetails } } + +query currencies { + items: currencies { + ...CurrencyDetails + } +} diff --git a/libs/sdk/src/graphql/feature-price.graphql b/libs/sdk/src/graphql/feature-price.graphql index 075720d..5a6bf84 100644 --- a/libs/sdk/src/graphql/feature-price.graphql +++ b/libs/sdk/src/graphql/feature-price.graphql @@ -1,9 +1,3 @@ -fragment CurrencyDetails on Currency { - decimals - mint - name - symbol -} fragment PriceDetails on Price { createdAt id diff --git a/libs/web/core/data-access/src/index.ts b/libs/web/core/data-access/src/index.ts index 97f5a24..cd23a1b 100644 --- a/libs/web/core/data-access/src/index.ts +++ b/libs/web/core/data-access/src/index.ts @@ -1,2 +1,3 @@ export * from './lib/app-config.provider' export * from './lib/sdk-provider' +export * from './lib/use-currencies' diff --git a/libs/web/core/data-access/src/lib/use-currencies.ts b/libs/web/core/data-access/src/lib/use-currencies.ts new file mode 100644 index 0000000..63e33eb --- /dev/null +++ b/libs/web/core/data-access/src/lib/use-currencies.ts @@ -0,0 +1,11 @@ +import { useQuery } from '@tanstack/react-query' +import { useSdk } from './sdk-provider' + +export function useCurrencies() { + const sdk = useSdk() + return useQuery({ + queryKey: ['currencies'], + queryFn: () => sdk.currencies().then((res) => res.data?.items ?? []), + retry: 0, + }) +} diff --git a/libs/web/solana/data-access/src/index.ts b/libs/web/solana/data-access/src/index.ts index 0e56a48..de40428 100644 --- a/libs/web/solana/data-access/src/index.ts +++ b/libs/web/solana/data-access/src/index.ts @@ -1,5 +1,6 @@ export * from './lib/cluster-provider' export * from './lib/create-transaction' +export * from './lib/solana-label-provider' export * from './lib/solana-provider' export * from './lib/ui-toast-link' export * from './lib/use-account' diff --git a/libs/web/solana/data-access/src/lib/solana-label-provider.tsx b/libs/web/solana/data-access/src/lib/solana-label-provider.tsx new file mode 100644 index 0000000..b28c234 --- /dev/null +++ b/libs/web/solana/data-access/src/lib/solana-label-provider.tsx @@ -0,0 +1,27 @@ +import { ellipsify } from '@tokengator-mint/sdk' +import { useCurrencies } from '@tokengator-mint/web-core-data-access' +import { createContext, ReactNode, useContext } from 'react' + +export interface SolanaLabelProviderContext { + map: Map + getLabel: (mint: string) => string +} + +const Context = createContext({} as SolanaLabelProviderContext) + +export function SolanaLabelProvider({ children }: { children: ReactNode }) { + const currencyQuery = useCurrencies() + const map = new Map() + currencyQuery.data?.forEach((currency) => { + map.set(currency.mint, currency.symbol) + }) + const value: SolanaLabelProviderContext = { + map, + getLabel: (mint: string) => map.get(mint) ?? ellipsify(mint), + } + return {children} +} + +export function useSolanaLabel() { + return useContext(Context) +} diff --git a/libs/web/solana/data-access/src/lib/solana-provider.tsx b/libs/web/solana/data-access/src/lib/solana-provider.tsx index aa458e8..c445d79 100644 --- a/libs/web/solana/data-access/src/lib/solana-provider.tsx +++ b/libs/web/solana/data-access/src/lib/solana-provider.tsx @@ -10,12 +10,15 @@ import { } from '@solana/wallet-adapter-react' import { ReactNode, useCallback, useMemo } from 'react' import { ClusterProvider, useCluster } from './cluster-provider' +import { SolanaLabelProvider } from './solana-label-provider' export function SolanaClusterProvider({ autoConnect, children }: { autoConnect?: boolean; children: ReactNode }) { return ( - - {children} - + + + {children} + + ) } diff --git a/libs/web/wallet/ui/src/lib/wallet-ui-sol-token-accounts.tsx b/libs/web/wallet/ui/src/lib/wallet-ui-sol-token-accounts.tsx index 43c8913..c53093f 100644 --- a/libs/web/wallet/ui/src/lib/wallet-ui-sol-token-accounts.tsx +++ b/libs/web/wallet/ui/src/lib/wallet-ui-sol-token-accounts.tsx @@ -3,14 +3,14 @@ import { UiError, UiInfo, UiStack } from '@pubkey-ui/core' import { AccountInfo, ParsedAccountData, PublicKey } from '@solana/web3.js' import { IconRefresh } from '@tabler/icons-react' import { useQueryClient } from '@tanstack/react-query' -import { ellipsify, Wallet } from '@tokengator-mint/sdk' -import { useSolanaGetTokenAccounts } from '@tokengator-mint/web-solana-data-access' +import { Wallet } from '@tokengator-mint/sdk' +import { useSolanaGetTokenAccounts, useSolanaLabel } from '@tokengator-mint/web-solana-data-access' import { SolanaUiExplorerLink } from '@tokengator-mint/web-solana-ui' import { useMemo, useState } from 'react' export function WalletUiSolTokenAccounts({ wallet }: { wallet: Wallet }) { const query = useSolanaGetTokenAccounts({ account: wallet.publicKey }) - + const { getLabel } = useSolanaLabel() const [showAll, setShowAll] = useState(false) const client = useQueryClient() const items: { account: AccountInfo; pubkey: PublicKey }[] = useMemo(() => { @@ -71,14 +71,14 @@ export function WalletUiSolTokenAccounts({ wallet }: { wallet: Wallet }) {