diff --git a/apps/dapp/next.config.js b/apps/dapp/next.config.js index 1a9fb0f62a..41fce1ee96 100644 --- a/apps/dapp/next.config.js +++ b/apps/dapp/next.config.js @@ -87,6 +87,7 @@ const config = { domains: [ 'ipfs.stargaze.zone', 'ipfs-gw.stargaze-apis.com', + 'i.stargaze-apis.com', 'nftstorage.link', 'img-proxy.ekez.workers.dev', 'raw.githubusercontent.com', diff --git a/apps/sda/next.config.js b/apps/sda/next.config.js index e6670e7d64..0ab4c52e47 100644 --- a/apps/sda/next.config.js +++ b/apps/sda/next.config.js @@ -81,6 +81,7 @@ const config = { domains: [ 'ipfs.stargaze.zone', 'ipfs-gw.stargaze-apis.com', + 'i.stargaze-apis.com', 'nftstorage.link', 'img-proxy.ekez.workers.dev', 'raw.githubusercontent.com', diff --git a/packages/state/graphql/__generated__/gql.ts b/packages/state/graphql/__generated__/gql.ts index 0d3b8345d8..b678a78b6e 100644 --- a/packages/state/graphql/__generated__/gql.ts +++ b/packages/state/graphql/__generated__/gql.ts @@ -15,8 +15,8 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ const documents = { "\n query collectionTokensQuery(\n $collectionAddr: String!\n $limit: Int\n $offset: Int\n ) {\n tokens(collectionAddr: $collectionAddr, limit: $limit, offset: $offset) {\n pageInfo {\n limit\n offset\n total\n }\n tokens {\n tokenId\n }\n }\n }\n": types.CollectionTokensQueryDocument, "\n query collectionTokensForOwnerQuery(\n $collectionAddr: String!\n $ownerAddrOrName: String!\n $limit: Int\n $offset: Int\n ) {\n tokens(\n collectionAddr: $collectionAddr,\n ownerAddrOrName: $ownerAddrOrName,\n limit: $limit,\n offset: $offset\n ) {\n pageInfo {\n limit\n offset\n total\n }\n tokens {\n tokenId\n }\n }\n }\n": types.CollectionTokensForOwnerQueryDocument, - "\n query tokenQuery($collectionAddr: String!, $tokenId: String!) {\n token(collectionAddr: $collectionAddr, tokenId: $tokenId) {\n tokenId\n collection {\n contractAddress\n name\n }\n media {\n url\n }\n name\n description\n }\n }\n": types.TokenQueryDocument, - "\n query tokensForOwnerQuery(\n $ownerAddrOrName: String!\n $limit: Int\n $offset: Int\n ) {\n tokens(\n ownerAddrOrName: $ownerAddrOrName,\n limit: $limit,\n offset: $offset\n ) {\n pageInfo {\n limit\n offset\n total\n }\n tokens {\n tokenId\n collection {\n contractAddress\n name\n }\n media {\n url\n }\n name\n description\n }\n }\n }\n": types.TokensForOwnerQueryDocument, + "\n query tokenQuery($collectionAddr: String!, $tokenId: String!) {\n token(collectionAddr: $collectionAddr, tokenId: $tokenId) {\n tokenId\n collection {\n contractAddress\n name\n }\n media {\n url\n visualAssets {\n lg {\n url\n }\n }\n }\n name\n description\n }\n }\n": types.TokenQueryDocument, + "\n query tokensForOwnerQuery(\n $ownerAddrOrName: String!\n $limit: Int\n $offset: Int\n ) {\n tokens(\n ownerAddrOrName: $ownerAddrOrName,\n limit: $limit,\n offset: $offset\n ) {\n pageInfo {\n limit\n offset\n total\n }\n tokens {\n tokenId\n collection {\n contractAddress\n name\n }\n media {\n url\n visualAssets {\n lg {\n url\n }\n }\n }\n name\n description\n }\n }\n }\n": types.TokensForOwnerQueryDocument, }; /** @@ -44,11 +44,11 @@ export function gql(source: "\n query collectionTokensForOwnerQuery(\n $coll /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "\n query tokenQuery($collectionAddr: String!, $tokenId: String!) {\n token(collectionAddr: $collectionAddr, tokenId: $tokenId) {\n tokenId\n collection {\n contractAddress\n name\n }\n media {\n url\n }\n name\n description\n }\n }\n"): (typeof documents)["\n query tokenQuery($collectionAddr: String!, $tokenId: String!) {\n token(collectionAddr: $collectionAddr, tokenId: $tokenId) {\n tokenId\n collection {\n contractAddress\n name\n }\n media {\n url\n }\n name\n description\n }\n }\n"]; +export function gql(source: "\n query tokenQuery($collectionAddr: String!, $tokenId: String!) {\n token(collectionAddr: $collectionAddr, tokenId: $tokenId) {\n tokenId\n collection {\n contractAddress\n name\n }\n media {\n url\n visualAssets {\n lg {\n url\n }\n }\n }\n name\n description\n }\n }\n"): (typeof documents)["\n query tokenQuery($collectionAddr: String!, $tokenId: String!) {\n token(collectionAddr: $collectionAddr, tokenId: $tokenId) {\n tokenId\n collection {\n contractAddress\n name\n }\n media {\n url\n visualAssets {\n lg {\n url\n }\n }\n }\n name\n description\n }\n }\n"]; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "\n query tokensForOwnerQuery(\n $ownerAddrOrName: String!\n $limit: Int\n $offset: Int\n ) {\n tokens(\n ownerAddrOrName: $ownerAddrOrName,\n limit: $limit,\n offset: $offset\n ) {\n pageInfo {\n limit\n offset\n total\n }\n tokens {\n tokenId\n collection {\n contractAddress\n name\n }\n media {\n url\n }\n name\n description\n }\n }\n }\n"): (typeof documents)["\n query tokensForOwnerQuery(\n $ownerAddrOrName: String!\n $limit: Int\n $offset: Int\n ) {\n tokens(\n ownerAddrOrName: $ownerAddrOrName,\n limit: $limit,\n offset: $offset\n ) {\n pageInfo {\n limit\n offset\n total\n }\n tokens {\n tokenId\n collection {\n contractAddress\n name\n }\n media {\n url\n }\n name\n description\n }\n }\n }\n"]; +export function gql(source: "\n query tokensForOwnerQuery(\n $ownerAddrOrName: String!\n $limit: Int\n $offset: Int\n ) {\n tokens(\n ownerAddrOrName: $ownerAddrOrName,\n limit: $limit,\n offset: $offset\n ) {\n pageInfo {\n limit\n offset\n total\n }\n tokens {\n tokenId\n collection {\n contractAddress\n name\n }\n media {\n url\n visualAssets {\n lg {\n url\n }\n }\n }\n name\n description\n }\n }\n }\n"): (typeof documents)["\n query tokensForOwnerQuery(\n $ownerAddrOrName: String!\n $limit: Int\n $offset: Int\n ) {\n tokens(\n ownerAddrOrName: $ownerAddrOrName,\n limit: $limit,\n offset: $offset\n ) {\n pageInfo {\n limit\n offset\n total\n }\n tokens {\n tokenId\n collection {\n contractAddress\n name\n }\n media {\n url\n visualAssets {\n lg {\n url\n }\n }\n }\n name\n description\n }\n }\n }\n"]; export function gql(source: string) { return (documents as any)[source] ?? {}; diff --git a/packages/state/graphql/__generated__/graphql.ts b/packages/state/graphql/__generated__/graphql.ts index c19cbabcec..94aeae97d9 100644 --- a/packages/state/graphql/__generated__/graphql.ts +++ b/packages/state/graphql/__generated__/graphql.ts @@ -20,20 +20,38 @@ export type Scalars = { UnixNanoseconds: { input: any; output: any; } }; +export type Activity = { + activityPrice?: Maybe; + date?: Maybe; + expires?: Maybe; + from?: Maybe; + id: Scalars['ID']['output']; + isValid?: Maybe; + to?: Maybe; + txId?: Maybe; + type?: Maybe; +}; + /** Enumerates different types of token-related activities. */ export enum ActivityType { + AcceptCollectionOffer = 'ACCEPT_COLLECTION_OFFER', Airdrop = 'AIRDROP', - Bid = 'BID', + AuctionBid = 'AUCTION_BID', + AuctionSale = 'AUCTION_SALE', CancelAuction = 'CANCEL_AUCTION', + CollectionOffer = 'COLLECTION_OFFER', CreateAuction = 'CREATE_AUCTION', - List = 'LIST', - Mint = 'MINT', - Offer = 'OFFER', + NameMint = 'NAME_MINT', + NameOffer = 'NAME_OFFER', PriceChange = 'PRICE_CHANGE', - RejectOffer = 'REJECT_OFFER', - RemoveOffer = 'REMOVE_OFFER', + RejectTokenOffer = 'REJECT_TOKEN_OFFER', + RemoveCollectionOffer = 'REMOVE_COLLECTION_OFFER', + RemoveTokenOffer = 'REMOVE_TOKEN_OFFER', Sale = 'SALE', - Transfer = 'TRANSFER', + TokenList = 'TOKEN_LIST', + TokenMint = 'TOKEN_MINT', + TokenOffer = 'TOKEN_OFFER', + TokenTransfer = 'TOKEN_TRANSFER', Unlist = 'UNLIST' } @@ -227,6 +245,7 @@ export type CoinAmount = { export type Collection = { __typename?: 'Collection'; + activity?: Maybe>; categories?: Maybe; contractAddress: Scalars['ID']['output']; contractUri?: Maybe; @@ -254,6 +273,11 @@ export type Collection = { }; +export type CollectionActivityArgs = { + filterByActivity?: InputMaybe>; +}; + + export type CollectionHighestOfferArgs = { filterByAddr?: InputMaybe; }; @@ -268,6 +292,27 @@ export type CollectionOffersArgs = { filterByAddr?: InputMaybe; }; +export type CollectionActivity = Activity & { + __typename?: 'CollectionActivity'; + activityPrice?: Maybe; + collection?: Maybe; + date?: Maybe; + expires?: Maybe; + from?: Maybe; + id: Scalars['ID']['output']; + isValid?: Maybe; + to?: Maybe; + token?: Maybe; + txId?: Maybe; + type?: Maybe; +}; + +export type CollectionActivityResult = CursorPaginatedQuery & { + __typename?: 'CollectionActivityResult'; + collectionActivity: Array; + pageInfo?: Maybe; +}; + export type CollectionCategories = { __typename?: 'CollectionCategories'; private?: Maybe>; @@ -861,6 +906,7 @@ export type Query = { /** Retrieve a list of badges owned by a specific wallet. */ badges?: Maybe; collection?: Maybe; + collectionActivity?: Maybe; collectionCategories?: Maybe>; collectionCounts?: Maybe; collectionOffers?: Maybe; @@ -898,6 +944,13 @@ export type QueryCollectionArgs = { }; +export type QueryCollectionActivityArgs = { + address: Scalars['String']['input']; + filterByActivity?: InputMaybe>; + limit?: InputMaybe; +}; + + export type QueryCollectionCountsArgs = { filterForSale?: InputMaybe; limit?: InputMaybe; @@ -1547,7 +1600,7 @@ export type TokenQueryQueryVariables = Exact<{ }>; -export type TokenQueryQuery = { __typename?: 'Query', token?: { __typename?: 'Token', tokenId: string, name?: string | null, description?: string | null, collection: { __typename?: 'Collection', contractAddress: string, name?: string | null }, media?: { __typename?: 'Media', url?: string | null } | null } | null }; +export type TokenQueryQuery = { __typename?: 'Query', token?: { __typename?: 'Token', tokenId: string, name?: string | null, description?: string | null, collection: { __typename?: 'Collection', contractAddress: string, name?: string | null }, media?: { __typename?: 'Media', url?: string | null, visualAssets?: { __typename?: 'SizedVisualAssets', lg?: { __typename?: 'VisualAsset', url?: string | null } | null } | null } | null } | null }; export type TokensForOwnerQueryQueryVariables = Exact<{ ownerAddrOrName: Scalars['String']['input']; @@ -1556,10 +1609,10 @@ export type TokensForOwnerQueryQueryVariables = Exact<{ }>; -export type TokensForOwnerQueryQuery = { __typename?: 'Query', tokens?: { __typename?: 'TokensResult', pageInfo?: { __typename?: 'PageInfo', limit?: number | null, offset?: number | null, total?: number | null } | null, tokens: Array<{ __typename?: 'Token', tokenId: string, name?: string | null, description?: string | null, collection: { __typename?: 'Collection', contractAddress: string, name?: string | null }, media?: { __typename?: 'Media', url?: string | null } | null }> } | null }; +export type TokensForOwnerQueryQuery = { __typename?: 'Query', tokens?: { __typename?: 'TokensResult', pageInfo?: { __typename?: 'PageInfo', limit?: number | null, offset?: number | null, total?: number | null } | null, tokens: Array<{ __typename?: 'Token', tokenId: string, name?: string | null, description?: string | null, collection: { __typename?: 'Collection', contractAddress: string, name?: string | null }, media?: { __typename?: 'Media', url?: string | null, visualAssets?: { __typename?: 'SizedVisualAssets', lg?: { __typename?: 'VisualAsset', url?: string | null } | null } | null } | null }> } | null }; export const CollectionTokensQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"collectionTokensQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"collectionAddr"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tokens"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"collectionAddr"},"value":{"kind":"Variable","name":{"kind":"Name","value":"collectionAddr"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"limit"}},{"kind":"Field","name":{"kind":"Name","value":"offset"}},{"kind":"Field","name":{"kind":"Name","value":"total"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tokens"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tokenId"}}]}}]}}]}}]} as unknown as DocumentNode; export const CollectionTokensForOwnerQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"collectionTokensForOwnerQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"collectionAddr"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"ownerAddrOrName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tokens"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"collectionAddr"},"value":{"kind":"Variable","name":{"kind":"Name","value":"collectionAddr"}}},{"kind":"Argument","name":{"kind":"Name","value":"ownerAddrOrName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"ownerAddrOrName"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"limit"}},{"kind":"Field","name":{"kind":"Name","value":"offset"}},{"kind":"Field","name":{"kind":"Name","value":"total"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tokens"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tokenId"}}]}}]}}]}}]} as unknown as DocumentNode; -export const TokenQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"tokenQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"collectionAddr"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"tokenId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"token"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"collectionAddr"},"value":{"kind":"Variable","name":{"kind":"Name","value":"collectionAddr"}}},{"kind":"Argument","name":{"kind":"Name","value":"tokenId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"tokenId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tokenId"}},{"kind":"Field","name":{"kind":"Name","value":"collection"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"contractAddress"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"media"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]} as unknown as DocumentNode; -export const TokensForOwnerQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"tokensForOwnerQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"ownerAddrOrName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tokens"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"ownerAddrOrName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"ownerAddrOrName"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"limit"}},{"kind":"Field","name":{"kind":"Name","value":"offset"}},{"kind":"Field","name":{"kind":"Name","value":"total"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tokens"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tokenId"}},{"kind":"Field","name":{"kind":"Name","value":"collection"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"contractAddress"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"media"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export const TokenQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"tokenQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"collectionAddr"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"tokenId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"token"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"collectionAddr"},"value":{"kind":"Variable","name":{"kind":"Name","value":"collectionAddr"}}},{"kind":"Argument","name":{"kind":"Name","value":"tokenId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"tokenId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tokenId"}},{"kind":"Field","name":{"kind":"Name","value":"collection"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"contractAddress"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"media"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"visualAssets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lg"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]} as unknown as DocumentNode; +export const TokensForOwnerQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"tokensForOwnerQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"ownerAddrOrName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tokens"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"ownerAddrOrName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"ownerAddrOrName"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"limit"}},{"kind":"Field","name":{"kind":"Name","value":"offset"}},{"kind":"Field","name":{"kind":"Name","value":"total"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tokens"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tokenId"}},{"kind":"Field","name":{"kind":"Name","value":"collection"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"contractAddress"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"media"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"visualAssets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lg"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/packages/state/graphql/stargaze/queries/token.ts b/packages/state/graphql/stargaze/queries/token.ts index 0fe8b04583..4cf0bdac34 100644 --- a/packages/state/graphql/stargaze/queries/token.ts +++ b/packages/state/graphql/stargaze/queries/token.ts @@ -10,6 +10,11 @@ export const stargazeTokenQuery = gql(` } media { url + visualAssets { + lg { + url + } + } } name description @@ -41,6 +46,11 @@ export const stargazeTokensForOwnerQuery = gql(` } media { url + visualAssets { + lg { + url + } + } } name description diff --git a/packages/stateful/recoil/selectors/profile.ts b/packages/stateful/recoil/selectors/profile.ts index a072daebf7..153ac5a327 100644 --- a/packages/stateful/recoil/selectors/profile.ts +++ b/packages/stateful/recoil/selectors/profile.ts @@ -17,6 +17,7 @@ import { STARGAZE_NAMES_CONTRACT, getChainForChainId, getFallbackImage, + objectMatchesStructure, transformBech32Address, } from '@dao-dao/utils' @@ -92,6 +93,56 @@ export const stargazeNameSelector = selectorFamily({ }, }) +// Get image for address from Stargaze Names. +export const stargazeNameImageForAddressSelector = selectorFamily< + string | undefined, + string +>({ + key: 'stargazeNameImageForAddress', + get: + (walletAddress) => + async ({ get }) => { + // Get name associated with address. + const name = get(stargazeNameSelector(walletAddress)) + if (!name) { + return + } + + const chainId = MAINNET + ? ChainId.StargazeMainnet + : ChainId.StargazeTestnet + const client = get(cosmWasmClientForChainSelector(chainId)) + + // Get NFT associated with name. + let response + try { + response = await client.queryContractSmart(STARGAZE_NAMES_CONTRACT, { + image_n_f_t: { name }, + }) + } catch { + return + } + + // If NFT exists, get image associated with NFT. + if ( + objectMatchesStructure(response, { + collection: {}, + token_id: {}, + }) + ) { + const { imageUrl } = get( + nftCardInfoSelector({ + chainId, + collection: response.collection, + tokenId: response.token_id, + }) + ) + + return imageUrl + } + }, +}) + export const makeDefaultWalletProfileData = ( address: string, loading = false @@ -134,12 +185,27 @@ export const walletProfileDataSelector = selectorFamily< profile.nft = pfpkProfile.nft } + // Load Stargaze name as backup if no PFPK set. + if (!profile.name) { + const stargazeNameLoadable = get(noWait(stargazeNameSelector(address))) + if ( + stargazeNameLoadable.state === 'hasValue' && + stargazeNameLoadable.contents + ) { + profile.name = + stargazeNameLoadable.contents + + '.' + + getChainForChainId(chainId).bech32_prefix + profile.nameSource = 'stargaze' + } + } + const backupImageUrl = getFallbackImage(address) // Set `imageUrl` to PFPK image, defaulting to fallback image. profile.imageUrl = pfpkProfile?.nft?.imageUrl || backupImageUrl - // If NFT present from PFPK, get image from token. + // If NFT present from PFPK, get image from token once loaded. if (pfpkProfile?.nft) { // Don't wait for NFT info to load. When it loads, it will update. const nftInfoLoadable = get( @@ -159,20 +225,17 @@ export const walletProfileDataSelector = selectorFamily< ) { profile.imageUrl = nftInfoLoadable.contents.imageUrl } - } - // Load Stargaze name as backup if no PFPK set. - if (!profile.name) { - const stargazeNameLoadable = get(noWait(stargazeNameSelector(address))) + // Load Stargaze name image if no PFPK. + } else if (profile.nameSource === 'stargaze') { + const stargazeNameImageLoadable = get( + noWait(stargazeNameImageForAddressSelector(address)) + ) if ( - stargazeNameLoadable.state === 'hasValue' && - stargazeNameLoadable.contents + stargazeNameImageLoadable.state === 'hasValue' && + stargazeNameImageLoadable.contents ) { - profile.name = - stargazeNameLoadable.contents + - '.' + - getChainForChainId(chainId).bech32_prefix - profile.nameSource = 'stargaze' + profile.imageUrl = stargazeNameImageLoadable.contents } } diff --git a/packages/stateless/components/NftCard.tsx b/packages/stateless/components/NftCard.tsx index 0ba289b9e3..ab6260bbdd 100644 --- a/packages/stateless/components/NftCard.tsx +++ b/packages/stateless/components/NftCard.tsx @@ -146,6 +146,11 @@ export const NftCard = forwardRef( className="h-full w-full object-cover" fill onLoadingComplete={() => setImageLoading(false)} + // NFTs tend to be shown in the `GridCardContainer` component, + // which shows 1 column until 640px, 2 columns until 768px, + // and 3 columns after that (using the `sm` and `md` tailwind + // breakpoints). This helps the browser optimize the image. + sizes="(max-width: 640px) 100vw, (max-width: 768px) 50vw, 33vw" src={toAccessibleImageUrl(imageUrl, { proxy: true })} /> ) : ( diff --git a/packages/stateless/hooks/useQuerySyncedState.ts b/packages/stateless/hooks/useQuerySyncedState.ts index 1dce4bc839..4ffe94cdc7 100644 --- a/packages/stateless/hooks/useQuerySyncedState.ts +++ b/packages/stateless/hooks/useQuerySyncedState.ts @@ -54,13 +54,33 @@ export const useQuerySyncedState = ({ // On value change, store in query parameter. If default, remove. useEffect(() => { + if (!pageInitialized.current) { + return + } + if (value === defaultValue) { + if (!(param in router.query)) { + return + } + delete router.query[param] } else { - router.query[param] = + const newValue = typeof value === 'number' ? BigInt(value).toString() : `${value}` + if (router.query[param] === newValue) { + return + } + + router.query[param] = newValue } - router.push(router, undefined, { shallow: true }) + + router.push( + { + query: router.query, + }, + undefined, + { shallow: true } + ) }, [value, router, param, defaultValue]) return [value, setValue] diff --git a/packages/types/nft.ts b/packages/types/nft.ts index e1bc909b97..a01adbf3b7 100644 --- a/packages/types/nft.ts +++ b/packages/types/nft.ts @@ -23,6 +23,11 @@ export type StargazeNft = { } media?: { url?: string | null + visualAssets?: { + lg?: { + url?: string | null + } | null + } | null } | null } diff --git a/packages/utils/nft.ts b/packages/utils/nft.ts index de4c371ab7..4e6e271e96 100644 --- a/packages/utils/nft.ts +++ b/packages/utils/nft.ts @@ -85,7 +85,7 @@ export const nftCardInfoFromStargazeIndexerNft = ( href: `${STARGAZE_URL_BASE}/media/${token.collection.contractAddress}/${token.tokenId}`, name: 'Stargaze', }, - imageUrl: token.media?.url || undefined, + imageUrl: token.media?.visualAssets?.lg?.url || token.media?.url || undefined, name: token.name || token.tokenId || 'Unknown NFT', description: token.description || undefined, })