diff --git a/README.md b/README.md index 6d758e3..a9c131b 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ ## Intro to monorepo The monorepo consists of three main parts: + * [Contracts](packages/contracts) * [Dapp](packages/dapp) * [Subgraphs](packages/subgraphs) @@ -18,10 +19,10 @@ pnpm lint ## Deployed contracts and EAS schemas -### EESCore deployed contracts: +### EESCore deployed contracts * Mainnet: TODO -* Base: TODO +* Base: [0x6BbcC7D0E661a4f5441F74Dc0Ab324ac4327D940](https://basescan.org/address/0x6bbcc7d0e661a4f5441f74dc0ab324ac4327d940) * Sepolia: [0x306aa8b6640A4Ef12919Ed97b5d85c006DD68796](https://sepolia.etherscan.io/address/0x306aa8b6640A4Ef12919Ed97b5d85c006DD68796) * Base Sepolia: [0x63F610a03Caa82ca32386BDb6F447a93d4D6F6e7](https://sepolia.basescan.org/address/0x63F610a03Caa82ca32386BDb6F447a93d4D6F6e7) diff --git a/packages/contracts/scripts/deployCore.ts b/packages/contracts/scripts/deployCore.ts index 313fdec..b1c2bcf 100644 --- a/packages/contracts/scripts/deployCore.ts +++ b/packages/contracts/scripts/deployCore.ts @@ -13,7 +13,7 @@ const networkToSchemaUid = { mainnet: 'not-yet-deployed', sepolia: '0x28bb35c3774b2963e8703dccbe93a3d1620ddf91ee3eee4678cdb8fb8e1a8bbb', local: '0x28bb35c3774b2963e8703dccbe93a3d1620ddf91ee3eee4678cdb8fb8e1a8bbb', - base: 'not-yet-deployed', + base: '0xc15bb007fcd98a5a99c0fd98286fba2f62f997de62c11ea24dfd30d274eef99f', baseSepolia: '0xc15bb007fcd98a5a99c0fd98286fba2f62f997de62c11ea24dfd30d274eef99f', }; @@ -44,12 +44,12 @@ async function main() { ); await deployment.waitForDeployment(); + console.log('EESCore deployed to: ', await deployment.getAddress()); if (hre.network.name !== 'local') { await run('verify:verify', { address: await deployment.getAddress(), }); } - console.log('EESCore deployed to: ', await deployment.getAddress()); } main().catch((error) => { diff --git a/packages/dapp/.env.example b/packages/dapp/.env.example index 5e61eaf..f362191 100644 --- a/packages/dapp/.env.example +++ b/packages/dapp/.env.example @@ -1,7 +1,12 @@ -# GraphQL API endpoints -NEXT_PUBLIC_EES_BASE_GRAPHQL_ENDPOINT= -NEXT_PUBLIC_EES_BASE_SEPOLIA_GRAPHQL_ENDPOINT= -NEXT_PUBLIC_EES_SEPOLIA_GRAPHQL_ENDPOINT= +# GraphQL API endpoints (Alchemy + The Graph Network) +# Alchemy +EES_BASE_GRAPHQL_ENDPOINT_ALCHEMY= +EES_BASE_SEPOLIA_GRAPHQL_ENDPOINT_ALCHEMY= +EES_SEPOLIA_GRAPHQL_ENDPOINT_ALCHEMY= +# Graph network +EES_BASE_GRAPHQL_ENDPOINT_GRAPH_NETWORK= +EES_BASE_SEPOLIA_GRAPHQL_ENDPOINT_GRAPH_NETWORK= +EES_SEPOLIA_GRAPHQL_ENDPOINT_GRAPH_NETWORK= # Coinbase API Secrets COINBASE_API_KEY_NAME= @@ -14,3 +19,11 @@ NEXT_PUBLIC_APP_ENV= NEXT_PUBLIC_BASE_ENDPOINT= NEXT_PUBLIC_BASE_SEPOLIA_ENDPOINT= NEXT_PUBLIC_SEPOLIA_ENDPOINT= + +# Airstack +AIRSTACK_API_URL= +AIRSTACK_API_KEY= + +# Next.js Vercel +# Should be only set for local development, on Vercel it will be set automatically +NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL= diff --git a/packages/dapp/codegen.ts b/packages/dapp/codegen.ts index b6a007a..6f40919 100644 --- a/packages/dapp/codegen.ts +++ b/packages/dapp/codegen.ts @@ -2,22 +2,38 @@ import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { generates: { - './src/__generated__/eas/': { - documents: './src/lib/graphql/eas/**/*.graphql', - schema: 'https://base.easscan.org/graphql', + // './src/__generated__/eas/': { + // documents: './src/lib/graphql/eas/**/*.graphql', + // schema: 'https://base.easscan.org/graphql', + // preset: 'client', + // plugins: [], + // presetConfig: { + // gqlTagName: 'gqlEAS', + // }, + // }, + './src/__generated__/ees/': { + documents: './src/lib/graphql/ees/**/*.graphql', + config: { + documentMode: 'string', + }, + schema: + 'https://subgraph.satsuma-prod.com/9c8dcc2edf3c/martins-team--780110/ees-sepolia/api', preset: 'client', plugins: [], presetConfig: { - gqlTagName: 'gqlEAS', + gqlTagName: 'gqlEES', }, }, - './src/__generated__/ees/': { - documents: './src/lib/graphql/ees/**/*.graphql', - schema: 'http://0.0.0.0:8000/subgraphs/name/ees', + './src/__generated__/airstack/': { + documents: './src/lib/graphql/airstack/**/*.graphql', + config: { + documentMode: 'string', + }, + schema: 'https://api.airstack.xyz/graphql', preset: 'client', plugins: [], presetConfig: { - gqlTagName: 'gqlEES', + gqlTagName: 'gqlAirstack', }, }, }, diff --git a/packages/dapp/next.config.js b/packages/dapp/next.config.js index aa0a379..2267cb3 100644 --- a/packages/dapp/next.config.js +++ b/packages/dapp/next.config.js @@ -1,5 +1,10 @@ /** @type {import('next').NextConfig} */ const nextConfig = { + logging: { + fetches: { + fullUrl: true, + }, + }, images: { remotePatterns: [ { diff --git a/packages/dapp/package.json b/packages/dapp/package.json index 1b95ee6..88c490b 100644 --- a/packages/dapp/package.json +++ b/packages/dapp/package.json @@ -27,17 +27,20 @@ "@rainbow-me/rainbowkit": "^2.1.2", "@tanstack/react-query": "5.40.0", "@tanstack/react-query-devtools": "^5.40.0", + "@vercel/analytics": "^1.3.1", + "@vercel/speed-insights": "^1.0.11", "@wagmi/core": "^2.10.5", + "blo": "^1.2.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "^1.0.0", "framer-motion": "^11.2.10", "jsonwebtoken": "^9.0.2", "lucide-react": "^0.381.0", - "next": "14.2.3", + "next": "14.3.0-canary.87", "next-themes": "^0.3.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", + "react": "19.0.0-rc.0", + "react-dom": "19.0.0-rc.0", "react-inlinesvg": "^4.1.3", "react-share": "^5.1.0", "react-use": "^17.5.0", diff --git a/packages/dapp/public/endorse.png b/packages/dapp/public/endorse.png new file mode 100644 index 0000000..aa5d71c Binary files /dev/null and b/packages/dapp/public/endorse.png differ diff --git a/packages/dapp/public/icons/icon-gas.svg b/packages/dapp/public/icons/icon-gas.svg new file mode 100644 index 0000000..cf51997 --- /dev/null +++ b/packages/dapp/public/icons/icon-gas.svg @@ -0,0 +1,14 @@ + + + diff --git a/packages/dapp/src/__generated__/airstack/fragment-masking.ts b/packages/dapp/src/__generated__/airstack/fragment-masking.ts new file mode 100644 index 0000000..cca7098 --- /dev/null +++ b/packages/dapp/src/__generated__/airstack/fragment-masking.ts @@ -0,0 +1,63 @@ +/* eslint-disable */ +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; +import { Incremental, TypedDocumentString } from './graphql'; + + +export type FragmentType> = TDocumentType extends DocumentTypeDecoration< + infer TType, + any +> + ? [TType] extends [{ ' $fragmentName'?: infer TKey }] + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never + : never + : never; + +// return non-nullable if `fragmentType` is non-nullable +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> +): TType; +// return nullable if `fragmentType` is nullable +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> | null | undefined +): TType | null | undefined; +// return array of non-nullable if `fragmentType` is array of non-nullable +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> +): ReadonlyArray; +// return array of nullable if `fragmentType` is array of nullable +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined +): ReadonlyArray | null | undefined; +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> | ReadonlyArray>> | null | undefined +): TType | ReadonlyArray | null | undefined { + return fragmentType as any; +} + + +export function makeFragmentData< + F extends DocumentTypeDecoration, + FT extends ResultOf +>(data: FT, _fragment: F): FragmentType { + return data as FragmentType; +} +export function isFragmentReady( + queryNode: TypedDocumentString, + fragmentNode: TypedDocumentString, + data: FragmentType, any>> | null | undefined +): data is FragmentType { + const deferredFields = queryNode.__meta__?.deferredFields as Record; + const fragName = fragmentNode.__meta__?.fragmentName as string | undefined; + + if (!deferredFields || !fragName) return true; + + const fields = deferredFields[fragName] ?? []; + return fields.length > 0 && fields.every(field => data && field in data); +} diff --git a/packages/dapp/src/__generated__/airstack/gql.ts b/packages/dapp/src/__generated__/airstack/gql.ts new file mode 100644 index 0000000..6039a00 --- /dev/null +++ b/packages/dapp/src/__generated__/airstack/gql.ts @@ -0,0 +1,48 @@ +/* eslint-disable */ +import * as types from './graphql'; + + + +/** + * Map of all GraphQL operations in the project. + * + * This map has several performance disadvantages: + * 1. It is not tree-shakeable, so it will include all operations in the project. + * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. + * 3. It does not support dead code elimination, so it will add unused operations. + * + * Therefore it is highly recommended to use the babel or swc plugin for production. + */ +const documents = { + "query GetMinimalProfileFromAddress($identity: Identity!) {\n Wallet(input: {identity: $identity, blockchain: ethereum}) {\n primaryDomain {\n name\n avatar\n tokenNft {\n contentValue {\n image {\n small\n }\n }\n }\n }\n }\n farcasterSocials: Socials(\n input: {filter: {identity: {_eq: $identity}, dappName: {_eq: farcaster}}, blockchain: ethereum, order: {followerCount: DESC}, limit: 1}\n ) {\n Social {\n profileHandle\n profileBio\n profileImageContentValue {\n image {\n small\n }\n }\n }\n }\n lensSocials: Socials(\n input: {filter: {identity: {_eq: $identity}, dappName: {_eq: lens}}, blockchain: ethereum, order: {followerCount: DESC}, limit: 1}\n ) {\n Social {\n profileHandle\n profileBio\n profileImageContentValue {\n image {\n small\n }\n }\n }\n }\n}": types.GetMinimalProfileFromAddressDocument, + "query GetProfileFromEns($identity: Identity!) {\n Wallet(input: {identity: $identity, blockchain: ethereum}) {\n addresses\n primaryDomain {\n name\n avatar\n tokenNft {\n contentValue {\n image {\n small\n }\n }\n }\n }\n }\n}": types.GetProfileFromEnsDocument, + "query GetProfileFromFarcaster($identity: Identity!) {\n farcasterSocials: Socials(\n input: {limit: 1, filter: {identity: {_eq: $identity}, dappName: {_eq: farcaster}}, blockchain: ethereum, order: {followerCount: DESC}}\n ) {\n Social {\n connectedAddresses {\n address\n }\n userAddress\n profileName\n profileDisplayName\n profileHandle\n profileBio\n profileImageContentValue {\n image {\n small\n }\n }\n }\n }\n}": types.GetProfileFromFarcasterDocument, + "query GetProfileFromLens($identity: Identity!) {\n Wallet(input: {identity: $identity, blockchain: ethereum}) {\n addresses\n }\n lensSocials: Socials(\n input: {limit: 1, filter: {identity: {_eq: $identity}, dappName: {_eq: lens}}, blockchain: ethereum, order: {followerCount: DESC}}\n ) {\n Social {\n profileName\n profileDisplayName\n profileHandle\n profileBio\n profileImageContentValue {\n image {\n small\n }\n }\n }\n }\n}": types.GetProfileFromLensDocument, + "query GetProfileInfo($identity: Identity!) {\n Wallet(input: {identity: $identity, blockchain: ethereum}) {\n addresses\n primaryDomain {\n name\n avatar\n tokenNft {\n contentValue {\n image {\n small\n }\n }\n }\n }\n }\n farcasterSocials: Socials(\n input: {filter: {identity: {_eq: $identity}, dappName: {_eq: farcaster}}, blockchain: ethereum, order: {followerCount: DESC}}\n ) {\n Social {\n connectedAddresses {\n address\n }\n userAddress\n profileName\n profileDisplayName\n profileHandle\n profileBio\n profileImageContentValue {\n image {\n small\n }\n }\n }\n }\n lensSocials: Socials(\n input: {filter: {identity: {_eq: $identity}, dappName: {_eq: lens}}, blockchain: ethereum, order: {followerCount: DESC}}\n ) {\n Social {\n profileName\n profileDisplayName\n profileHandle\n profileBio\n profileImageContentValue {\n image {\n small\n }\n }\n }\n }\n}": types.GetProfileInfoDocument, +}; + +/** + * The gqlAirstack function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function gqlAirstack(source: "query GetMinimalProfileFromAddress($identity: Identity!) {\n Wallet(input: {identity: $identity, blockchain: ethereum}) {\n primaryDomain {\n name\n avatar\n tokenNft {\n contentValue {\n image {\n small\n }\n }\n }\n }\n }\n farcasterSocials: Socials(\n input: {filter: {identity: {_eq: $identity}, dappName: {_eq: farcaster}}, blockchain: ethereum, order: {followerCount: DESC}, limit: 1}\n ) {\n Social {\n profileHandle\n profileBio\n profileImageContentValue {\n image {\n small\n }\n }\n }\n }\n lensSocials: Socials(\n input: {filter: {identity: {_eq: $identity}, dappName: {_eq: lens}}, blockchain: ethereum, order: {followerCount: DESC}, limit: 1}\n ) {\n Social {\n profileHandle\n profileBio\n profileImageContentValue {\n image {\n small\n }\n }\n }\n }\n}"): typeof import('./graphql').GetMinimalProfileFromAddressDocument; +/** + * The gqlAirstack function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function gqlAirstack(source: "query GetProfileFromEns($identity: Identity!) {\n Wallet(input: {identity: $identity, blockchain: ethereum}) {\n addresses\n primaryDomain {\n name\n avatar\n tokenNft {\n contentValue {\n image {\n small\n }\n }\n }\n }\n }\n}"): typeof import('./graphql').GetProfileFromEnsDocument; +/** + * The gqlAirstack function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function gqlAirstack(source: "query GetProfileFromFarcaster($identity: Identity!) {\n farcasterSocials: Socials(\n input: {limit: 1, filter: {identity: {_eq: $identity}, dappName: {_eq: farcaster}}, blockchain: ethereum, order: {followerCount: DESC}}\n ) {\n Social {\n connectedAddresses {\n address\n }\n userAddress\n profileName\n profileDisplayName\n profileHandle\n profileBio\n profileImageContentValue {\n image {\n small\n }\n }\n }\n }\n}"): typeof import('./graphql').GetProfileFromFarcasterDocument; +/** + * The gqlAirstack function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function gqlAirstack(source: "query GetProfileFromLens($identity: Identity!) {\n Wallet(input: {identity: $identity, blockchain: ethereum}) {\n addresses\n }\n lensSocials: Socials(\n input: {limit: 1, filter: {identity: {_eq: $identity}, dappName: {_eq: lens}}, blockchain: ethereum, order: {followerCount: DESC}}\n ) {\n Social {\n profileName\n profileDisplayName\n profileHandle\n profileBio\n profileImageContentValue {\n image {\n small\n }\n }\n }\n }\n}"): typeof import('./graphql').GetProfileFromLensDocument; +/** + * The gqlAirstack function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function gqlAirstack(source: "query GetProfileInfo($identity: Identity!) {\n Wallet(input: {identity: $identity, blockchain: ethereum}) {\n addresses\n primaryDomain {\n name\n avatar\n tokenNft {\n contentValue {\n image {\n small\n }\n }\n }\n }\n }\n farcasterSocials: Socials(\n input: {filter: {identity: {_eq: $identity}, dappName: {_eq: farcaster}}, blockchain: ethereum, order: {followerCount: DESC}}\n ) {\n Social {\n connectedAddresses {\n address\n }\n userAddress\n profileName\n profileDisplayName\n profileHandle\n profileBio\n profileImageContentValue {\n image {\n small\n }\n }\n }\n }\n lensSocials: Socials(\n input: {filter: {identity: {_eq: $identity}, dappName: {_eq: lens}}, blockchain: ethereum, order: {followerCount: DESC}}\n ) {\n Social {\n profileName\n profileDisplayName\n profileHandle\n profileBio\n profileImageContentValue {\n image {\n small\n }\n }\n }\n }\n}"): typeof import('./graphql').GetProfileInfoDocument; + + +export function gqlAirstack(source: string) { + return (documents as any)[source] ?? {}; +} diff --git a/packages/dapp/src/__generated__/airstack/graphql.ts b/packages/dapp/src/__generated__/airstack/graphql.ts new file mode 100644 index 0000000..40b4a9c --- /dev/null +++ b/packages/dapp/src/__generated__/airstack/graphql.ts @@ -0,0 +1,2520 @@ +/* eslint-disable */ +import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; +export type Maybe = T | null; +export type InputMaybe = Maybe; +export type Exact = { [K in keyof T]: T[K] }; +export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; +export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; +export type MakeEmpty = { [_ in K]?: never }; +export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: { input: string; output: string; } + String: { input: string; output: string; } + Boolean: { input: boolean; output: boolean; } + Int: { input: number; output: number; } + Float: { input: number; output: number; } + Address: { input: any; output: any; } + Any: { input: any; output: any; } + DateRange: { input: any; output: any; } + Identity: { input: any; output: any; } + IntString: { input: any; output: any; } + Map: { input: any; output: any; } + Range: { input: any; output: any; } + Time: { input: any; output: any; } + TimeRange: { input: any; output: any; } +}; + +/** Represents on-chain smart contract account */ +export type Account = { + __typename?: 'Account'; + /** Nested query - on-chain wallet related information, including address, domains, social profile, other token balances, and transfer history */ + address: Wallet; + /** Blockchain where account is created */ + blockchain?: Maybe; + /** Block number of the account creation transaction */ + createdAtBlockNumber?: Maybe; + /** Block timestamp of the account creation transaction */ + createdAtBlockTimestamp?: Maybe; + /** Transaction Hash of the account creation transaction */ + creationTransactionHash?: Maybe; + /** Address of deployer */ + deployer?: Maybe; + /** Airstack unique identifier for the account */ + id: Scalars['ID']['output']; + /** ERC6551 standard : Implementation address of on chain smart contract account */ + implementation?: Maybe; + /** Token NFT associated with erc-6551 */ + nft?: Maybe; + /** ERC6551 standard : Registry used to deploy smart contract wallet */ + registry?: Maybe; + /** ERC6551 standard salt for account creation */ + salt?: Maybe; + /** Standard of account- ERC6551, Safe etc */ + standard: AccountStandard; + /** ERC6551 standard: Address of ERC721 token */ + tokenAddress?: Maybe; + /** ERC6551 standard: tokenId of ERC721 token */ + tokenId?: Maybe; + /** Block number of the account updation transaction */ + updatedAtBlockNumber?: Maybe; + /** Block timestamp of the account updation transaction */ + updatedAtBlockTimestamp?: Maybe; +}; + +export type AccountFilter = { + address?: InputMaybe; + createdAtBlockTimestamp?: InputMaybe; + implementation?: InputMaybe; + registry?: InputMaybe; + salt?: InputMaybe; + standard?: InputMaybe; + tokenAddress?: InputMaybe; + tokenId?: InputMaybe; +}; + +export type AccountOrderBy = { + createdAtBlockTimestamp?: InputMaybe; +}; + +export enum AccountStandard { + Erc6551 = 'ERC6551' +} + +export type AccountStandard_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export type AccountsInput = { + blockchain: TokenBlockchain; + cursor?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type AccountsNestedInput = { + blockchain?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + order?: InputMaybe>>; + showOptimisticAddress?: InputMaybe; +}; + +export type AccountsOutput = { + __typename?: 'AccountsOutput'; + Account?: Maybe>; + pageInfo?: Maybe; +}; + +export type Address_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; + _ne?: InputMaybe; + _nin?: InputMaybe>; +}; + +export type AnimationUrlVariants = { + __typename?: 'AnimationUrlVariants'; + original?: Maybe; +}; + +export enum Audience { + All = 'all', + Farcaster = 'farcaster' +} + +export type AudioVariants = { + __typename?: 'AudioVariants'; + original?: Maybe; +}; + +export enum Blockchain { + Ethereum = 'ethereum' +} + +export type Boolean_Comparator_Exp = { + _eq?: InputMaybe; +}; + +export type ConnectedAddress = { + __typename?: 'ConnectedAddress'; + address?: Maybe; + blockchain?: Maybe; + chainId?: Maybe; + timestamp?: Maybe; +}; + +export type ContractMetadata = { + __typename?: 'ContractMetadata'; + /** Description of the token, mirrored from the smart contract */ + description?: Maybe; + externalLink?: Maybe; + /** Royalties recipient address, mirrored from the smart contract */ + feeRecipient?: Maybe; + image?: Maybe; + /** Name of the token, mirrored from the smart contract */ + name?: Maybe; + sellerFeeBasisPoints?: Maybe; +}; + +export type Date_Range_Comparator_Exp = { + _eq?: InputMaybe; +}; + +export type Domain = { + __typename?: 'Domain'; + /** Avatar of the domain */ + avatar?: Maybe; + /** Blockchain where the NFT sale took place */ + blockchain: Blockchain; + /** Unique identifier for the blockchain */ + chainId?: Maybe; + /** Block number when the domain was created */ + createdAtBlockNumber?: Maybe; + /** Timestamp when the domain was created */ + createdAtBlockTimestamp?: Maybe; + /** DApp name associated with the domain (e.g. ENS) */ + dappName?: Maybe; + /** DApp slug (contract version) associated with the domain */ + dappSlug?: Maybe; + /** Timestamp when the domain registration expires */ + expiryTimestamp?: Maybe; + /** Domain registration cost in decimals */ + formattedRegistrationCost?: Maybe; + /** Domain registration cost in native blockchain token in decimals */ + formattedRegistrationCostInNativeToken?: Maybe; + /** Domain registration cost in USDC in decimals */ + formattedRegistrationCostInUSDC?: Maybe; + /** Airstack unique identifier for the data point */ + id?: Maybe; + /** Domain is name wrapped or not */ + isNameWrapped?: Maybe; + /** Indicates if the domain is set to be primary - true or false */ + isPrimary?: Maybe; + /** Airstack unique domain hash */ + labelHash?: Maybe; + /** Domain name without the domain ending, e.g. vitalik instead of vitalik.eth */ + labelName?: Maybe; + /** Block number when the domain was last updated */ + lastUpdatedBlockNumber?: Maybe; + /** Timestamp when the domain was last updated */ + lastUpdatedBlockTimestamp?: Maybe; + /** Manager of Domain */ + manager: Scalars['Address']['output']; + /** Manager wallet related information, including address, domains, social profile, other token balances, and transfer history */ + managerDetails?: Maybe; + /** Multichain associated with the domain */ + multiChainAddresses?: Maybe>; + /** Full domain name, e.g. vitalik.eth */ + name?: Maybe; + /** Owner of token associated with the domain */ + owner: Scalars['Address']['output']; + /** Owner wallet related information, including address, domains, social profile, other token balances, and transfer history */ + ownerDetails?: Maybe; + /** Parent domain name, if the entity is a subdomain */ + parent?: Maybe; + /** Nested query - can retrieve payment token data (name, symbol, etc.) */ + paymentToken?: Maybe; + /** payment amount in blockchain native token for the domain */ + paymentTokenCostInNativeToken?: Maybe; + /** payment amount in USDC for the domain */ + paymentTokenCostInUSDC?: Maybe; + /** Domain registration cost */ + registrationCost?: Maybe; + /** Domain registration cost in blockchain native token */ + registrationCostInNativeToken?: Maybe; + /** Domain registration cost in USDC */ + registrationCostInUSDC?: Maybe; + /** Blockchain address to which the domain is resolved */ + resolvedAddress?: Maybe; + /** Nested query - on-chain resolvedAddress wallet related information, including address, domains, social profile, other token balances, and transfer history */ + resolvedAddressDetails?: Maybe; + /** Resolver address associated with Domain */ + resolverAddress?: Maybe; + /** Count of subdomains linked to the domain */ + subDomainCount?: Maybe; + /** Nested query allowing to retrieve subdomain information associated with the domain */ + subDomains?: Maybe>>; + /** Texts associated with the domain */ + texts?: Maybe>; + /** Token Address associated with the domain, if applicable */ + tokenAddress: Scalars['Address']['output']; + /** Domain Token ID associated with the domain, if applicable */ + tokenId?: Maybe; + /** Token nft associated with the domain, if applicable */ + tokenNft?: Maybe; + /** Time-to-live value for the domain */ + ttl?: Maybe; +}; + + +export type DomainSubDomainsArgs = { + input?: InputMaybe; +}; + +export enum DomainDappName { + Ens = 'ens' +} + +export type DomainDappName_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export enum DomainDappSlug { + EnsV1 = 'ens_v1' +} + +export type DomainDappSlug_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export type DomainFilter = { + isPrimary?: InputMaybe; + lastUpdatedBlockTimestamp?: InputMaybe; + name?: InputMaybe; + owner?: InputMaybe; + resolvedAddress?: InputMaybe; +}; + +export type DomainMultiChainAddress = { + __typename?: 'DomainMultiChainAddress'; + /** address */ + address?: Maybe; + /** symbol according to SLIP-0044 */ + symbol?: Maybe; +}; + +export type DomainOrderBy = { + createdAtBlockTimestamp?: InputMaybe; + expiryTimestamp?: InputMaybe; + lastUpdatedBlockTimestamp?: InputMaybe; +}; + +export type DomainTexts = { + __typename?: 'DomainTexts'; + /** key of the text */ + key?: Maybe; + /** value of the text */ + value?: Maybe; +}; + +export type DomainsInput = { + blockchain: Blockchain; + cursor?: InputMaybe; + filter: DomainFilter; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type DomainsNestedInput = { + blockchain?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + order?: InputMaybe>>; +}; + +export type DomainsOutput = { + __typename?: 'DomainsOutput'; + Domain?: Maybe>; + pageInfo?: Maybe; +}; + +export enum EveryBlockchain { + All = 'ALL' +} + +export type FarcasterCast = { + __typename?: 'FarcasterCast'; + castedAtTimestamp?: Maybe; + castedBy?: Maybe; + channel?: Maybe; + embeds?: Maybe>>; + fid?: Maybe; + frame?: Maybe; + hash?: Maybe; + id?: Maybe; + mentions?: Maybe>; + numberOfLikes?: Maybe; + numberOfRecasts?: Maybe; + numberOfReplies?: Maybe; + parentCast?: Maybe; + parentFid?: Maybe; + parentHash?: Maybe; + quotedCast?: Maybe>>; + rawText?: Maybe; + rootParentUrl?: Maybe; + socialCapitalValue?: Maybe; + text?: Maybe; + url?: Maybe; +}; + +export type FarcasterCastFilter = { + castedAtTimestamp?: InputMaybe; + castedBy?: InputMaybe; + frameUrl?: InputMaybe; + hasEmbeds?: InputMaybe; + hasFrames?: InputMaybe; + hasMentions?: InputMaybe; + hash?: InputMaybe; + rootParentUrl?: InputMaybe; + url?: InputMaybe; +}; + +export type FarcasterCastInput = { + blockchain: EveryBlockchain; + cursor?: InputMaybe; + filter: FarcasterCastFilter; + limit?: InputMaybe; +}; + +export type FarcasterCastOutput = { + __typename?: 'FarcasterCastOutput'; + Cast?: Maybe>; + pageInfo?: Maybe; +}; + +export type FarcasterChannel = { + __typename?: 'FarcasterChannel'; + channelId: Scalars['String']['output']; + createdAtTimestamp: Scalars['Time']['output']; + dappName: Scalars['String']['output']; + dappSlug: Scalars['String']['output']; + description: Scalars['String']['output']; + followerCount?: Maybe; + /** Airstack unique identifier for the data point */ + id: Scalars['ID']['output']; + imageUrl: Scalars['String']['output']; + isModerationEnabled?: Maybe; + leadIds?: Maybe>; + leadProfiles?: Maybe>; + moderatorIds?: Maybe>; + moderatorProfiles?: Maybe>; + name: Scalars['String']['output']; + participants?: Maybe>; + url: Scalars['String']['output']; +}; + + +export type FarcasterChannelLeadProfilesArgs = { + input?: InputMaybe; +}; + + +export type FarcasterChannelModeratorProfilesArgs = { + input?: InputMaybe; +}; + + +export type FarcasterChannelParticipantsArgs = { + input?: InputMaybe; +}; + +export enum FarcasterChannelActionType { + Cast = 'cast', + Follow = 'follow', + Reply = 'reply' +} + +export type FarcasterChannelActionType_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export type FarcasterChannelFilter = { + channelId?: InputMaybe; + createdAtTimestamp?: InputMaybe; + leadId?: InputMaybe; + leadIdentity?: InputMaybe; + moderatorId?: InputMaybe; + moderatorIdentity?: InputMaybe; + name?: InputMaybe; +}; + +export type FarcasterChannelNestedInput = { + blockchain?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + order?: InputMaybe>>; +}; + +export type FarcasterChannelOrderBy = { + createdAtTimestamp?: InputMaybe; + followerCount?: InputMaybe; +}; + +export type FarcasterChannelParticipant = { + __typename?: 'FarcasterChannelParticipant'; + channel?: Maybe; + channelActions?: Maybe>; + channelId: Scalars['String']['output']; + channelName: Scalars['String']['output']; + dappName: Scalars['String']['output']; + dappSlug: Scalars['String']['output']; + /** Airstack unique identifier for the data point */ + id?: Maybe; + lastActionTimestamp: Scalars['Time']['output']; + lastCastedTimestamp?: Maybe; + lastFollowedTimestamp?: Maybe; + lastRepliedTimestamp?: Maybe; + participant?: Maybe; + participantId: Scalars['String']['output']; +}; + + +export type FarcasterChannelParticipantChannelArgs = { + input?: InputMaybe; +}; + + +export type FarcasterChannelParticipantParticipantArgs = { + input?: InputMaybe; +}; + +export type FarcasterChannelParticipantFilter = { + channelActions?: InputMaybe; + channelId?: InputMaybe; + channelName?: InputMaybe; + lastActionTimestamp?: InputMaybe; + participant?: InputMaybe; +}; + +export type FarcasterChannelParticipantNestedInput = { + blockchain?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + order?: InputMaybe>>; +}; + +export type FarcasterChannelParticipantOrderBy = { + lastActionTimestamp?: InputMaybe; +}; + +export type FarcasterChannelParticipantsInput = { + blockchain: EveryBlockchain; + cursor?: InputMaybe; + filter: FarcasterChannelParticipantFilter; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type FarcasterChannelParticipantsOutput = { + __typename?: 'FarcasterChannelParticipantsOutput'; + FarcasterChannelParticipant?: Maybe>; + pageInfo?: Maybe; +}; + +export type FarcasterChannelsInput = { + blockchain: EveryBlockchain; + cursor?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type FarcasterChannelsOutput = { + __typename?: 'FarcasterChannelsOutput'; + FarcasterChannel?: Maybe>; + pageInfo?: Maybe; +}; + +export type FarcasterFrame = { + __typename?: 'FarcasterFrame'; + buttons?: Maybe>; + castedAtTimestamp?: Maybe; + frameHash?: Maybe; + frameUrl?: Maybe; + imageAspectRatio?: Maybe; + imageUrl?: Maybe; + inputText?: Maybe; + postUrl?: Maybe; + state?: Maybe; +}; + +export type FarcasterFrameMessageInput = { + filter: FarcasterFrameMessageInputFilter; +}; + +export type FarcasterFrameMessageInputFilter = { + messageBytes?: InputMaybe; +}; + +export type FarcasterFrameMessageOutput = { + __typename?: 'FarcasterFrameMessageOutput'; + castedBy?: Maybe; + castedByFid?: Maybe; + interactedBy?: Maybe; + interactedByFid?: Maybe; + isValid?: Maybe; + message?: Maybe; + messageByte?: Maybe; + messageRaw?: Maybe; +}; + +export type FarcasterQuotedRecastsFilter = { + parentCastedBy?: InputMaybe; + parentHash?: InputMaybe; + parentUrl?: InputMaybe; + recastedBy?: InputMaybe; +}; + +export type FarcasterQuotedRecastsInput = { + blockchain: EveryBlockchain; + cursor?: InputMaybe; + filter: FarcasterQuotedRecastsFilter; + limit?: InputMaybe; +}; + +export type FarcasterQuotedRecastsOutput = { + __typename?: 'FarcasterQuotedRecastsOutput'; + QuotedRecast?: Maybe>; + pageInfo?: Maybe; +}; + +export type FarcasterReaction = { + __typename?: 'FarcasterReaction'; + cast?: Maybe; + castHash?: Maybe; + reactedBy?: Maybe; +}; + +export enum FarcasterReactionCriteria { + Liked = 'liked', + Recasted = 'recasted', + Replied = 'replied' +} + +export type FarcasterReactionsFilter = { + castHash?: InputMaybe; + castUrl?: InputMaybe; + channelId?: InputMaybe; + criteria: FarcasterReactionCriteria; + frameUrl?: InputMaybe; + reactedBy?: InputMaybe; +}; + +export type FarcasterReactionsInput = { + blockchain: EveryBlockchain; + cursor?: InputMaybe; + filter: FarcasterReactionsFilter; + limit?: InputMaybe; +}; + +export type FarcasterReactionsOutput = { + __typename?: 'FarcasterReactionsOutput'; + Criteria?: Maybe; + Reaction?: Maybe>; + pageInfo?: Maybe; +}; + +export type FarcasterRepliesFilter = { + hash?: InputMaybe; + parentCastedBy?: InputMaybe; + parentHash?: InputMaybe; + parentUrl?: InputMaybe; + repliedBy?: InputMaybe; +}; + +export type FarcasterRepliesInput = { + blockchain: EveryBlockchain; + cursor?: InputMaybe; + filter: FarcasterRepliesFilter; + limit?: InputMaybe; +}; + +export type FarcasterRepliesOutput = { + __typename?: 'FarcasterRepliesOutput'; + Reply?: Maybe>; + pageInfo?: Maybe; +}; + +export type Float_Comparator_Exp = { + _eq?: InputMaybe; + _gt?: InputMaybe; + _gte?: InputMaybe; + _in?: InputMaybe>; + _lt?: InputMaybe; + _lte?: InputMaybe; + _ne?: InputMaybe; + _nin?: InputMaybe>; +}; + +export type FrameButton = { + __typename?: 'FrameButton'; + action?: Maybe; + id?: Maybe; + index?: Maybe; + label?: Maybe; + target?: Maybe; +}; + +export type FrameMessage = { + __typename?: 'FrameMessage'; + data?: Maybe; + hash?: Maybe; + hashScheme?: Maybe; + signature?: Maybe; + signatureScheme?: Maybe; + signer?: Maybe; +}; + +export type FrameMessageActionBody = { + __typename?: 'FrameMessageActionBody'; + address?: Maybe; + buttonIndex?: Maybe; + castId?: Maybe; + inputText?: Maybe; + inputTextDecoded?: Maybe; + state?: Maybe; + stateDecoded?: Maybe; + transactionHash?: Maybe; + transactionId?: Maybe; + url?: Maybe; + urlDecoded?: Maybe; +}; + +export type FrameMessageCastId = { + __typename?: 'FrameMessageCastId'; + fid?: Maybe; + hash?: Maybe; +}; + +export type FrameMessageData = { + __typename?: 'FrameMessageData'; + fid?: Maybe; + frameActionBody?: Maybe; + network?: Maybe; + time?: Maybe; + type?: Maybe; +}; + +export type Identity_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export type ImageSizes = { + __typename?: 'ImageSizes'; + extraSmall?: Maybe; + large?: Maybe; + medium?: Maybe; + original?: Maybe; + small?: Maybe; +}; + +export type Int_Comparator_Exp = { + _eq?: InputMaybe; + _gt?: InputMaybe; + _gte?: InputMaybe; + _in?: InputMaybe>; + _lt?: InputMaybe; + _lte?: InputMaybe; + _ne?: InputMaybe; + _nin?: InputMaybe>; +}; + +export type Int_String_Comparator_Exp = { + _eq?: InputMaybe; + _gt?: InputMaybe; + _gte?: InputMaybe; + _in?: InputMaybe>; + _lt?: InputMaybe; + _lte?: InputMaybe; + _ne?: InputMaybe; + _nin?: InputMaybe>; +}; + +export type LogoSizes = { + __typename?: 'LogoSizes'; + external?: Maybe; + large?: Maybe; + medium?: Maybe; + original?: Maybe; + small?: Maybe; +}; + +export type Media = { + __typename?: 'Media'; + animation_url?: Maybe; + audio?: Maybe; + image?: Maybe; + json?: Maybe; + video?: Maybe; +}; + +export type Mentions = { + __typename?: 'Mentions'; + fid?: Maybe; + position?: Maybe; + profile?: Maybe; +}; + +export type NativeBalance = { + __typename?: 'NativeBalance'; + /** Token amount the address currently holds */ + amount: Scalars['String']['output']; + /** Blockchain where the token smart contract is deployed */ + blockchain?: Maybe; + /** Unique identifier for the blockchain */ + chainId: Scalars['String']['output']; + /** Formatted token balance in decimals */ + formattedAmount?: Maybe; + /** Airstack unique identifier for the data point */ + id: Scalars['ID']['output']; + /** Block number of the latest token balance change happened */ + lastUpdatedBlock: Scalars['Int']['output']; + /** Timestamp of the latest token balance change happened */ + lastUpdatedTimestamp?: Maybe; + /** Nested Query allowing to retrieve address, domain names, social profiles of the owner */ + owner: Wallet; +}; + +export enum NativeBalanceBlockchain { + Degen = 'degen' +} + +export type NativeBalanceFilter = { + formattedAmount?: InputMaybe; + lastUpdatedTimestamp?: InputMaybe; + owner?: InputMaybe; +}; + +export type NativeBalanceOrderBy = { + lastUpdatedTimestamp?: InputMaybe; +}; + +export type NativeBalancesInput = { + blockchain: NativeBalanceBlockchain; + cursor?: InputMaybe; + filter: NativeBalanceFilter; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type NativeBalancesOutput = { + __typename?: 'NativeBalancesOutput'; + NativeBalance?: Maybe>; + pageInfo?: Maybe; +}; + +export type NftAttribute = { + __typename?: 'NftAttribute'; + displayType?: Maybe; + maxValue?: Maybe; + /** NFT attribute type as defined in the smart contract, e.g. background */ + trait_type?: Maybe; + /** NFT attribute value as defined in the smart contract, e.g. blue */ + value?: Maybe; +}; + +export type NftAttributeFilter = { + trait_type?: InputMaybe; + value?: InputMaybe; +}; + +export type NftAttributesInput = { + cursor?: InputMaybe; + filter: NftAttributeFilter; + limit?: InputMaybe; +}; + +export type NftAttributesOutput = { + __typename?: 'NftAttributesOutput'; + NftAttribute?: Maybe>; + pageInfo?: Maybe; +}; + +export type NftMetadata = { + __typename?: 'NftMetadata'; + animationUrl?: Maybe; + attributes?: Maybe>; + backgroundColor?: Maybe; + /** Description of the token, mirrored from the smart contract */ + description?: Maybe; + externalUrl?: Maybe; + /** Link to the token image, mirrored from the smart contract */ + image?: Maybe; + imageData?: Maybe; + /** Name of the token, mirrored from the smart contract */ + name?: Maybe; + youtubeUrl?: Maybe; +}; + +export type NftMetadataFilter = { + attributes?: InputMaybe; + name?: InputMaybe; +}; + +export type NftMetadataOrderBy = { + attributes?: InputMaybe; +}; + +export type NftMetadatasInput = { + cursor?: InputMaybe; + filter: NftMetadataFilter; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type NftMetadatasOutput = { + __typename?: 'NftMetadatasOutput'; + NftMetadata?: Maybe>; + pageInfo?: Maybe; +}; + +export enum OrderBy { + Asc = 'ASC', + Desc = 'DESC' +} + +export enum OrderByAsIntString { + Asc = 'ASC', + Desc = 'DESC' +} + +export type PageInfo = { + __typename?: 'PageInfo'; + hasNextPage: Scalars['Boolean']['output']; + hasPrevPage: Scalars['Boolean']['output']; + nextCursor: Scalars['String']['output']; + prevCursor: Scalars['String']['output']; +}; + +export type Poap = { + __typename?: 'Poap'; + attendee?: Maybe; + /** Blockchain associated with the Poap */ + blockchain?: Maybe; + /** Unique identifier for the blockchain */ + chainId?: Maybe; + /** Block Number when POAP was created */ + createdAtBlockNumber?: Maybe; + /** Time when POAP was created */ + createdAtBlockTimestamp?: Maybe; + /** Poap DApp name */ + dappName?: Maybe; + /** Poap DApp slug (contract version) */ + dappSlug?: Maybe; + /** Airstack unique dapp version number */ + dappVersion?: Maybe; + /** Poap event id */ + eventId?: Maybe; + /** Airstack unique identifier for the data point */ + id?: Maybe; + mintHash?: Maybe; + mintOrder?: Maybe; + owner: Wallet; + poapEvent?: Maybe; + /** POAP Contract Address */ + tokenAddress?: Maybe; + tokenId?: Maybe; + tokenUri?: Maybe; + transferCount?: Maybe; +}; + +export type PoapAttendee = { + __typename?: 'PoapAttendee'; + owner: Wallet; + totalPoapOwned?: Maybe; +}; + +export type PoapAttendeesOutput = { + __typename?: 'PoapAttendeesOutput'; + PoapAttendee?: Maybe>; + pageInfo?: Maybe; +}; + +export enum PoapDappName { + Poap = 'poap' +} + +export type PoapDappName_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export enum PoapDappSlug { + PoapGnosis = 'poap_gnosis', + PoapMainnet = 'poap_mainnet' +} + +export type PoapDappSlug_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export type PoapEvent = { + __typename?: 'PoapEvent'; + /** Blockchain where the marketplace data is calculated from */ + blockchain?: Maybe; + /** Unique identifier for the blockchain */ + chainId?: Maybe; + city?: Maybe; + contentType?: Maybe; + contentValue?: Maybe; + country?: Maybe; + dappName?: Maybe; + dappSlug: PoapDappSlug; + dappVersion?: Maybe; + description?: Maybe; + endDate?: Maybe; + eventId?: Maybe; + eventName?: Maybe; + /** The Event URL */ + eventURL?: Maybe; + /** Airstack unique identifier for the data point */ + id: Scalars['ID']['output']; + /** If Event is Virtual or not */ + isVirtualEvent?: Maybe; + metadata?: Maybe; + poaps?: Maybe>; + startDate?: Maybe; + tokenMints?: Maybe; +}; + + +export type PoapEventPoapsArgs = { + input?: InputMaybe; +}; + +export type PoapEventFilter = { + city?: InputMaybe; + country?: InputMaybe; + dappName?: InputMaybe; + dappSlug?: InputMaybe; + endDate?: InputMaybe; + eventId?: InputMaybe; + eventName?: InputMaybe; + isVirtualEvent?: InputMaybe; + startDate?: InputMaybe; + tokenMints?: InputMaybe; +}; + +export type PoapEventOrderBy = { + endDate?: InputMaybe; + startDate?: InputMaybe; + tokenMints?: InputMaybe; +}; + +export type PoapEventsInput = { + blockchain: EveryBlockchain; + cursor?: InputMaybe; + filter: PoapEventFilter; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type PoapEventsOutput = { + __typename?: 'PoapEventsOutput'; + PoapEvent?: Maybe>; + pageInfo?: Maybe; +}; + +export type PoapFilter = { + createdAtBlockNumber?: InputMaybe; + dappName?: InputMaybe; + dappSlug?: InputMaybe; + eventId?: InputMaybe; + owner?: InputMaybe; + tokenId?: InputMaybe; +}; + +export type PoapOrderBy = { + createdAtBlockNumber?: InputMaybe; +}; + +export type PoapsInput = { + blockchain: EveryBlockchain; + cursor?: InputMaybe; + filter: PoapFilter; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type PoapsNestedInput = { + blockchain?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + order?: InputMaybe>>; +}; + +export type PoapsOutput = { + __typename?: 'PoapsOutput'; + Poap?: Maybe>; + pageInfo?: Maybe; +}; + +export type PopularDapp = { + __typename?: 'PopularDapp'; + address?: Maybe; + blockchain?: Maybe; + chainId?: Maybe; + criteria?: Maybe; + criteriaCount?: Maybe; + description?: Maybe; + lastTransactionBlockNumber?: Maybe; + lastTransactionHash?: Maybe; + lastTransactionTimestamp?: Maybe; + name?: Maybe; + timeFrom?: Maybe; + timeTo?: Maybe; + userbase?: Maybe; + website?: Maybe; +}; + +export enum PopularDappsCriteria { + GasSpent = 'GAS_SPENT', + TotalTransactions = 'TOTAL_TRANSACTIONS', + UniqueUsers = 'UNIQUE_USERS' +} + +export type PopularDappsInput = { + blockchain: TrendingBlockchain; + criteria: PopularDappsCriteria; + cursor?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + timeFrame: TimeFrame; + userbase: Audience; +}; + +export type PopularDappsOutput = { + __typename?: 'PopularDappsOutput'; + PopularDapps?: Maybe>; + pageInfo?: Maybe; +}; + +export type ProjectDetails = { + __typename?: 'ProjectDetails'; + collectionName?: Maybe; + description?: Maybe; + discordUrl?: Maybe; + externalUrl?: Maybe; + imageUrl?: Maybe; + twitterUrl?: Maybe; +}; + +export type Query = { + __typename?: 'Query'; + Accounts?: Maybe; + Domains?: Maybe; + FarcasterCasts?: Maybe; + FarcasterChannelParticipants?: Maybe; + FarcasterChannels?: Maybe; + FarcasterQuotedRecasts?: Maybe; + FarcasterReactions?: Maybe; + FarcasterReplies?: Maybe; + FarcasterValidateFrameMessage?: Maybe; + PoapEvents?: Maybe; + Poaps?: Maybe; + Snapshots?: Maybe; + SocialFollowers?: Maybe; + SocialFollowings?: Maybe; + Socials?: Maybe; + TokenBalances?: Maybe; + TokenNfts?: Maybe; + TokenTransfers?: Maybe; + Tokens?: Maybe; + TrendingCasts?: Maybe; + TrendingMints?: Maybe; + TrendingSwaps?: Maybe; + TrendingTokens?: Maybe; + Wallet?: Maybe; + XMTPs?: Maybe; +}; + + +export type QueryAccountsArgs = { + input: AccountsInput; +}; + + +export type QueryDomainsArgs = { + input: DomainsInput; +}; + + +export type QueryFarcasterCastsArgs = { + input: FarcasterCastInput; +}; + + +export type QueryFarcasterChannelParticipantsArgs = { + input: FarcasterChannelParticipantsInput; +}; + + +export type QueryFarcasterChannelsArgs = { + input: FarcasterChannelsInput; +}; + + +export type QueryFarcasterQuotedRecastsArgs = { + input: FarcasterQuotedRecastsInput; +}; + + +export type QueryFarcasterReactionsArgs = { + input: FarcasterReactionsInput; +}; + + +export type QueryFarcasterRepliesArgs = { + input: FarcasterRepliesInput; +}; + + +export type QueryFarcasterValidateFrameMessageArgs = { + input: FarcasterFrameMessageInput; +}; + + +export type QueryPoapEventsArgs = { + input: PoapEventsInput; +}; + + +export type QueryPoapsArgs = { + input: PoapsInput; +}; + + +export type QuerySnapshotsArgs = { + input: SnapshotsInput; +}; + + +export type QuerySocialFollowersArgs = { + input: SocialFollowerInput; +}; + + +export type QuerySocialFollowingsArgs = { + input: SocialFollowingInput; +}; + + +export type QuerySocialsArgs = { + input: SocialsInput; +}; + + +export type QueryTokenBalancesArgs = { + input: TokenBalancesInput; +}; + + +export type QueryTokenNftsArgs = { + input: TokenNftsInput; +}; + + +export type QueryTokenTransfersArgs = { + input: TokenTransfersInput; +}; + + +export type QueryTokensArgs = { + input: TokensInput; +}; + + +export type QueryTrendingCastsArgs = { + input: TrendingCastsInput; +}; + + +export type QueryTrendingMintsArgs = { + input: TrendingMintsInput; +}; + + +export type QueryTrendingSwapsArgs = { + input: TrendingSwapsInput; +}; + + +export type QueryTrendingTokensArgs = { + input: TrendingTokensInput; +}; + + +export type QueryWalletArgs = { + input: WalletInput; +}; + + +export type QueryXmtPsArgs = { + input: XmtPsInput; +}; + +export type Range_Comparator_Exp = { + _eq?: InputMaybe; +}; + +export type Regex_String_Comparator_Exp = { + _eq?: InputMaybe; + _gt?: InputMaybe; + _gte?: InputMaybe; + _in?: InputMaybe>; + _lt?: InputMaybe; + _lte?: InputMaybe; + _ne?: InputMaybe; + _nin?: InputMaybe>; + _regex?: InputMaybe; + _regex_in?: InputMaybe>; +}; + +export type Simple_String_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; + _ne?: InputMaybe; + _nin?: InputMaybe>; +}; + +export type Snapshot = { + __typename?: 'Snapshot'; + amount?: Maybe; + blockchain?: Maybe; + chainId?: Maybe; + endBlockNumber?: Maybe; + endBlockTimestamp?: Maybe; + formattedAmount?: Maybe; + /** Airstack unique identifier for the data point */ + id: Scalars['ID']['output']; + owner: Wallet; + startBlockNumber?: Maybe; + startBlockTimestamp?: Maybe; + token?: Maybe; + tokenAddress: Scalars['Address']['output']; + tokenId?: Maybe; + tokenNft?: Maybe; + tokenType?: Maybe; +}; + +export enum SnapshotBlockchain { + Base = 'base', + Ethereum = 'ethereum', + Gold = 'gold', + Zora = 'zora' +} + +export type SnapshotFilter = { + blockNumber?: InputMaybe; + date?: InputMaybe; + owner?: InputMaybe; + timestamp?: InputMaybe; + tokenAddress?: InputMaybe; + tokenId?: InputMaybe; + tokenType?: InputMaybe; +}; + +export type SnapshotsInput = { + blockchain: SnapshotBlockchain; + cursor?: InputMaybe; + filter: SnapshotFilter; + limit?: InputMaybe; +}; + +export type SnapshotsOutput = { + __typename?: 'SnapshotsOutput'; + Snapshot?: Maybe>; + pageInfo?: Maybe; +}; + +export type Social = { + __typename?: 'Social'; + /** Blockchain associated with the social identity */ + blockchain?: Maybe; + /** Unique identifier for the blockchain */ + chainId?: Maybe; + connectedAddresses?: Maybe>; + coverImageContentValue?: Maybe; + coverImageURI?: Maybe; + /** Social DApp name */ + dappName?: Maybe; + /** Social DApp slug (contract version) */ + dappSlug?: Maybe; + /** Airstack unique dapp version number */ + dappVersion?: Maybe; + fnames?: Maybe>>; + followerCount?: Maybe; + followerTokenAddress?: Maybe; + followers?: Maybe; + followingCount?: Maybe; + followings?: Maybe; + handleTokenAddress?: Maybe; + handleTokenId?: Maybe; + /** Airstack unique identifier for the data point */ + id?: Maybe; + /** Blockchain address, ENS domain name, social identity such as Farcaster (for Farcaster use 'fc_fid:' prefix followed by the Farcaster user ID like fc_fid:5650, or use 'fc_fname:' prefix followed by the Farcaster user ID like 'fc_fname:vbuterin') or Lens (e.g. 'stani.lens) */ + identity?: Maybe; + isDefault?: Maybe; + isFarcasterPowerUser?: Maybe; + location?: Maybe; + metadataURI?: Maybe; + profileBio?: Maybe; + profileCreatedAtBlockNumber?: Maybe; + profileCreatedAtBlockTimestamp?: Maybe; + profileDisplayName?: Maybe; + profileHandle?: Maybe; + profileImage?: Maybe; + profileImageContentValue?: Maybe; + profileLastUpdatedAtBlockNumber?: Maybe; + profileLastUpdatedAtBlockTimestamp?: Maybe; + profileMetadata?: Maybe; + profileName?: Maybe; + profileTokenAddress?: Maybe; + profileTokenId?: Maybe; + profileTokenIdHex?: Maybe; + profileTokenUri?: Maybe; + profileUrl?: Maybe; + socialCapital?: Maybe; + twitterUserName?: Maybe; + updatedAt?: Maybe; + userAddress?: Maybe; + userAddressDetails?: Maybe; + userAssociatedAddressDetails?: Maybe>; + /** blockchain addresses associated with the social profile */ + userAssociatedAddresses?: Maybe>; + userCreatedAtBlockNumber?: Maybe; + userCreatedAtBlockTimestamp?: Maybe; + userHomeURL?: Maybe; + userId?: Maybe; + userLastUpdatedAtBlockNumber?: Maybe; + userLastUpdatedAtBlockTimestamp?: Maybe; + userRecoveryAddress?: Maybe; + website?: Maybe; +}; + + +export type SocialFollowersArgs = { + input?: InputMaybe; +}; + + +export type SocialFollowingsArgs = { + input?: InputMaybe; +}; + +export type SocialCapital = { + __typename?: 'SocialCapital'; + socialCapitalRank?: Maybe; + socialCapitalScore?: Maybe; + socialCapitalScoreRaw?: Maybe; +}; + +export type SocialCapitalValue = { + __typename?: 'SocialCapitalValue'; + formattedValue?: Maybe; + hash?: Maybe; + rawValue?: Maybe; +}; + +export enum SocialDappName { + Farcaster = 'farcaster', + Lens = 'lens' +} + +export type SocialDappName_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export enum SocialDappSlug { + FarcasterGoerli = 'farcaster_goerli', + FarcasterOptimism = 'farcaster_optimism', + FarcasterV2Optimism = 'farcaster_v2_optimism', + FarcasterV3Optimism = 'farcaster_v3_optimism', + LensPolygon = 'lens_polygon', + LensV2Polygon = 'lens_v2_polygon' +} + +export type SocialDappSlug_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export type SocialFilter = { + dappName?: InputMaybe; + dappSlug?: InputMaybe; + followerCount?: InputMaybe; + followingCount?: InputMaybe; + identity?: InputMaybe; + isDefault?: InputMaybe; + profileCreatedAtBlockTimestamp?: InputMaybe; + profileName?: InputMaybe; + socialCapitalRank?: InputMaybe; + socialCapitalScore?: InputMaybe; + updatedAt?: InputMaybe; + userAssociatedAddresses?: InputMaybe; + userId?: InputMaybe; +}; + +export type SocialFollower = { + __typename?: 'SocialFollower'; + blockNumber?: Maybe; + blockchain?: Maybe; + dappName?: Maybe; + dappSlug?: Maybe; + followerAddress?: Maybe; + followerProfileId?: Maybe; + followerSince?: Maybe; + followerTokenId?: Maybe; + followingAddress?: Maybe; + followingProfileId?: Maybe; + id?: Maybe; +}; + +export type SocialFollowerFilter = { + blockNumber?: InputMaybe; + dappName?: InputMaybe; + dappSlug?: InputMaybe; + followerProfileId?: InputMaybe; + followerSince?: InputMaybe; + followingProfileId?: InputMaybe; + identity?: InputMaybe; +}; + +export type SocialFollowerInput = { + blockchain: EveryBlockchain; + cursor?: InputMaybe; + filter: SocialFollowerFilter; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type SocialFollowerNestedInput = { + blockchain?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + order?: InputMaybe>>; +}; + +export type SocialFollowerOrderBy = { + blockNumber?: InputMaybe; + followerSince?: InputMaybe; +}; + +export type SocialFollowerOutput = { + __typename?: 'SocialFollowerOutput'; + Follower?: Maybe>; + pageInfo?: Maybe; +}; + +export type SocialFollowing = { + __typename?: 'SocialFollowing'; + blockNumber?: Maybe; + blockchain?: Maybe; + dappName?: Maybe; + dappSlug?: Maybe; + followerAddress?: Maybe; + followerProfileId?: Maybe; + followerTokenId?: Maybe; + followingAddress?: Maybe; + followingProfileId?: Maybe; + followingSince?: Maybe; + id?: Maybe; +}; + +export type SocialFollowingFilter = { + blockNumber?: InputMaybe; + dappName?: InputMaybe; + dappSlug?: InputMaybe; + followerProfileId?: InputMaybe; + followingProfileId?: InputMaybe; + followingSince?: InputMaybe; + identity?: InputMaybe; +}; + +export type SocialFollowingInput = { + blockchain: EveryBlockchain; + cursor?: InputMaybe; + filter: SocialFollowingFilter; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type SocialFollowingNestedInput = { + blockchain?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + order?: InputMaybe>>; +}; + +export type SocialFollowingOrderBy = { + blockNumber?: InputMaybe; + followingSince?: InputMaybe; +}; + +export type SocialFollowingOutput = { + __typename?: 'SocialFollowingOutput'; + Following?: Maybe>; + pageInfo?: Maybe; +}; + +export type SocialOrderBy = { + followerCount?: InputMaybe; + followingCount?: InputMaybe; + profileCreatedAtBlockTimestamp?: InputMaybe; + socialCapitalRank?: InputMaybe; + socialCapitalScore?: InputMaybe; + updatedAt?: InputMaybe; +}; + +export type SocialsInput = { + blockchain: Blockchain; + cursor?: InputMaybe; + filter: SocialFilter; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type SocialsNestedInput = { + blockchain?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; +}; + +export type SocialsOutput = { + __typename?: 'SocialsOutput'; + Social?: Maybe>; + pageInfo?: Maybe; +}; + +export type String_Comparator_Exp = { + _eq?: InputMaybe; + _gt?: InputMaybe; + _gte?: InputMaybe; + _in?: InputMaybe>; + _lt?: InputMaybe; + _lte?: InputMaybe; + _ne?: InputMaybe; + _nin?: InputMaybe>; +}; + +export type String_Eq_Comparator_Exp = { + _eq?: InputMaybe; +}; + +export type String_Eq_In_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export enum TimeFrame { + EightHours = 'eight_hours', + OneDay = 'one_day', + OneHour = 'one_hour', + SevenDays = 'seven_days', + TwoDays = 'two_days', + TwoHours = 'two_hours' +} + +export type Time_Comparator_Exp = { + _eq?: InputMaybe; + _gt?: InputMaybe; + _gte?: InputMaybe; + _in?: InputMaybe>; + _lt?: InputMaybe; + _lte?: InputMaybe; + _ne?: InputMaybe; + _nin?: InputMaybe>; +}; + +export type Time_Range_Comparator_Exp = { + _eq?: InputMaybe; +}; + +export type Token = { + __typename?: 'Token'; + /** Smart contract address of the token */ + address: Scalars['Address']['output']; + /** Base URI of the token contract */ + baseURI?: Maybe; + /** Blockchain where the token smart contract is deployed */ + blockchain?: Maybe; + /** Unique identifier for the blockchain */ + chainId?: Maybe; + /** Token contract metadata object */ + contractMetaData?: Maybe; + /** URI for the token's contract metadata */ + contractMetaDataURI?: Maybe; + /** The number of decimal places this token uses, default to 18 */ + decimals?: Maybe; + /** Airstack unique identifier for the contract */ + id?: Maybe; + /** Indicates if the token is set to be spam - true or false */ + isSpam?: Maybe; + /** Block number of the token's most recent transfer */ + lastTransferBlock?: Maybe; + /** Transaction hash of the token's most recent transfer */ + lastTransferHash?: Maybe; + /** Timestamp of the token's most recent transfer */ + lastTransferTimestamp?: Maybe; + /** Logo image for the contract in various sizes (if available) */ + logo?: Maybe; + /** Name of the token, mirrored from the smart contract */ + name?: Maybe; + /** The owner of the token contract */ + owner?: Maybe; + /** off-chain data for the token project */ + projectDetails?: Maybe; + /** Token contract metadata as it appears inside the contract */ + rawContractMetaData?: Maybe; + /** Symbol of the token, mirrored from the smart contract */ + symbol?: Maybe; + /** Nested Query - allows querying the tokenBalance information */ + tokenBalances?: Maybe>; + /** Nested Query - allows querying the tokenNFTs information */ + tokenNfts?: Maybe>; + /** Returns count of all NFT token attribute types and values for the given smart contract */ + tokenTraits?: Maybe; + /** Amount of tokens in the protocol */ + totalSupply?: Maybe; + /** Token type: ERC20, ERC721, or ERC1155 */ + type?: Maybe; +}; + + +export type TokenTokenBalancesArgs = { + input?: InputMaybe; +}; + + +export type TokenTokenNftsArgs = { + input?: InputMaybe; +}; + +export type TokenBalance = { + __typename?: 'TokenBalance'; + /** Token amount the address currently holds */ + amount: Scalars['String']['output']; + /** Blockchain where the token smart contract is deployed */ + blockchain?: Maybe; + /** Unique identifier for the blockchain */ + chainId: Scalars['String']['output']; + /** Formatted token balance in decimals */ + formattedAmount?: Maybe; + /** Airstack unique identifier for the data point */ + id: Scalars['ID']['output']; + /** Block number of the latest token balance change happened */ + lastUpdatedBlock: Scalars['Int']['output']; + /** Timestamp of the latest token balance change happened */ + lastUpdatedTimestamp?: Maybe; + /** Nested Query allowing to retrieve address, domain names, social profiles of the owner */ + owner: Wallet; + /** Nested Query - allows retrieving token contract level data */ + token?: Maybe; + /** Smart contract address of the token */ + tokenAddress: Scalars['Address']['output']; + /** Unique NFT token ID */ + tokenId?: Maybe; + /** Nested Query - allows retrieving token NFT contract level data, such as images, traits, and so on */ + tokenNfts?: Maybe; + /** Nested Query - allows retrieving token transfer history */ + tokenTransfers?: Maybe>; + /** Token type: ERC20, ERC721, or ERC1155 */ + tokenType?: Maybe; +}; + + +export type TokenBalanceTokenTransfersArgs = { + input?: InputMaybe; +}; + +export type TokenBalanceFilter = { + formattedAmount?: InputMaybe; + lastUpdatedTimestamp?: InputMaybe; + owner?: InputMaybe; + tokenAddress?: InputMaybe; + tokenId?: InputMaybe; + tokenType?: InputMaybe; +}; + +export type TokenBalanceOrderBy = { + lastUpdatedTimestamp?: InputMaybe; +}; + +export type TokenBalancesInput = { + blockchain: TokenBlockchain; + cursor?: InputMaybe; + filter: TokenBalanceFilter; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type TokenBalancesNestedInput = { + blockchain?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + order?: InputMaybe>>; +}; + +export type TokenBalancesOutput = { + __typename?: 'TokenBalancesOutput'; + TokenBalance?: Maybe>; + pageInfo?: Maybe; +}; + +export enum TokenBlockchain { + Base = 'base', + Degen = 'degen', + Ethereum = 'ethereum', + Gold = 'gold', + Ham = 'ham', + Zora = 'zora' +} + +export type TokenFilter = { + address?: InputMaybe; + isSpam?: InputMaybe; + name?: InputMaybe; + owner?: InputMaybe; + symbol?: InputMaybe; + type?: InputMaybe; +}; + +export type TokenNft = { + __typename?: 'TokenNft'; + /** Smart contract address of the token */ + address: Scalars['Address']['output']; + /** Blockchain where the token smart contract is deployed */ + blockchain?: Maybe; + /** Unique identifier for the blockchain */ + chainId: Scalars['String']['output']; + /** Content type of the NFT token (image, video, audio, etc.) */ + contentType?: Maybe; + /** NFT Media - resized images, animation, videos, etc. */ + contentValue?: Maybe; + /** Nested Query - allows querying the erc6551 account */ + erc6551Accounts?: Maybe>; + /** Airstack unique identifier for the NFT token */ + id: Scalars['ID']['output']; + /** Block number of the NFT token most recent transfer */ + lastTransferBlock?: Maybe; + /** Transaction hash of the NFT token most recent transfer */ + lastTransferHash?: Maybe; + /** Timestamp of the NFT token most recent transfer */ + lastTransferTimestamp?: Maybe; + /** NFT token metadata and attributes */ + metaData?: Maybe; + /** NFT token metadata, mirrored from the smart contract */ + rawMetaData?: Maybe; + /** Nested Query - allows retrieving token contract level data */ + token?: Maybe; + /** Nested Query - allows querying the tokenBalance information */ + tokenBalances?: Maybe>; + /** Unique NFT token ID */ + tokenId: Scalars['String']['output']; + /** Nested Query - allows querying the tokenTransfer information */ + tokenTransfers?: Maybe>; + /** NFT token URI */ + tokenURI?: Maybe; + /** Amount of NFT tokens in the protocol */ + totalSupply?: Maybe; + /** NFT Token type: ERC721, or ERC1155 */ + type?: Maybe; +}; + + +export type TokenNftErc6551AccountsArgs = { + input?: InputMaybe; +}; + + +export type TokenNftTokenBalancesArgs = { + input?: InputMaybe; +}; + + +export type TokenNftTokenTransfersArgs = { + input?: InputMaybe; +}; + +export type TokenNftFilter = { + address?: InputMaybe; + metaData?: InputMaybe; + tokenId?: InputMaybe; +}; + +export type TokenNftOrderBy = { + tokenId?: InputMaybe; +}; + +export type TokenNftsInput = { + blockchain: TokenBlockchain; + cursor?: InputMaybe; + filter: TokenNftFilter; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type TokenNftsNestedInput = { + blockchain?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + order?: InputMaybe>>; +}; + +export type TokenNftsOutput = { + __typename?: 'TokenNftsOutput'; + TokenNft?: Maybe>; + pageInfo?: Maybe; +}; + +export type TokenTransfer = { + __typename?: 'TokenTransfer'; + /** Token amount in the transfer */ + amount?: Maybe; + /** Token amounts in the transfer, if applicable. This mostly occurs in ERC1155 batch transfers */ + amounts?: Maybe>; + /** Block number of the token transfer */ + blockNumber?: Maybe; + /** Block timestamp of the token transfer */ + blockTimestamp?: Maybe; + /** Blockchain where the token transfer took place */ + blockchain?: Maybe; + /** Unique identifier for the blockchain */ + chainId?: Maybe; + /** Formatted transfer amount in decimals */ + formattedAmount?: Maybe; + /** Nested query - sender wallet related information, including address, domains, social profile, other token balances, and transfer history */ + from?: Maybe; + /** Airstack unique identifier for the data point */ + id?: Maybe; + /** Nested query - operator wallet (if the transaction was facilitated via smart contract) related information, including address, domains, social profile, other token balances, and transfer history */ + operator?: Maybe; + /** Nested query - recipient wallet related information, including address, domains, social profile, other token balances, and transfer history */ + to?: Maybe; + /** Nested Query - allows retrieving token contract level data */ + token?: Maybe; + /** Transferred token smart contract address */ + tokenAddress?: Maybe; + /** Unique NFT token ID */ + tokenId?: Maybe; + /** Unique NFT token IDs if multiple NFTs were a part of the transfer */ + tokenIds?: Maybe>; + /** Nested Query - allows retrieving token Token NFT level data, such as images, traits, and so on for each unique NFT in the transfer */ + tokenNft?: Maybe; + /** Token type: ERC20, ERC721, or ERC1155 */ + tokenType?: Maybe; + /** Token transfer transction hash */ + transactionHash: Scalars['String']['output']; + /** Type of the token transfer */ + type?: Maybe; +}; + +export type TokenTransferFilter = { + blockTimestamp?: InputMaybe; + formattedAmount?: InputMaybe; + from?: InputMaybe; + operator?: InputMaybe; + to?: InputMaybe; + tokenAddress?: InputMaybe; + tokenId?: InputMaybe; + tokenType?: InputMaybe; + transactionHash?: InputMaybe; + type?: InputMaybe; +}; + +export type TokenTransferOrderBy = { + blockTimestamp?: InputMaybe; +}; + +export enum TokenTransferType { + Burn = 'BURN', + Mint = 'MINT', + Transfer = 'TRANSFER' +} + +export type TokenTransferType_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export type TokenTransfersInput = { + blockchain: TokenBlockchain; + cursor?: InputMaybe; + filter: TokenTransferFilter; + limit?: InputMaybe; + order?: InputMaybe>; +}; + +export type TokenTransfersNestedInput = { + blockchain?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + order?: InputMaybe>>; +}; + +export type TokenTransfersOutput = { + __typename?: 'TokenTransfersOutput'; + TokenTransfer?: Maybe>; + pageInfo?: Maybe; +}; + +export enum TokenType { + Erc20 = 'ERC20', + Erc721 = 'ERC721', + Erc1155 = 'ERC1155' +} + +export type TokenType_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export type TokensInput = { + blockchain: TokenBlockchain; + cursor?: InputMaybe; + filter: TokenFilter; + limit?: InputMaybe; +}; + +export type TokensOutput = { + __typename?: 'TokensOutput'; + Token?: Maybe>; + pageInfo?: Maybe; +}; + +export enum TrendingBlockchain { + Base = 'base', + Degen = 'degen' +} + +export type TrendingCast = { + __typename?: 'TrendingCast'; + cast?: Maybe; + channel?: Maybe; + criteria?: Maybe; + criteriaCount?: Maybe; + fid?: Maybe; + hash?: Maybe; + id?: Maybe; + rootParentUrl?: Maybe; + socialCapitalValueFormatted?: Maybe; + socialCapitalValueRaw?: Maybe; + timeFrom?: Maybe; + timeTo?: Maybe; +}; + +export type TrendingCastFilter = { + fid?: InputMaybe; + rootParentUrl?: InputMaybe; +}; + +export enum TrendingCastTimeFrame { + EightHours = 'eight_hours', + FourHours = 'four_hours', + OneDay = 'one_day', + OneHour = 'one_hour', + SevenDays = 'seven_days', + TwelveHours = 'twelve_hours', + TwoDays = 'two_days', + TwoHours = 'two_hours' +} + +export type TrendingCast_Int_Comparator_Exp = { + _eq?: InputMaybe; +}; + +export enum TrendingCastsCriteria { + Likes = 'likes', + LikesRecastsReplies = 'likes_recasts_replies', + Recasts = 'recasts', + Replies = 'replies', + SocialCapitalValue = 'social_capital_value' +} + +export type TrendingCastsInput = { + blockchain: EveryBlockchain; + criteria: TrendingCastsCriteria; + cursor?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + timeFrame: TrendingCastTimeFrame; +}; + +export type TrendingCastsOutput = { + __typename?: 'TrendingCastsOutput'; + TrendingCast?: Maybe>; + pageInfo?: Maybe; +}; + +export type TrendingFilter = { + address?: InputMaybe; +}; + +export type TrendingMint = { + __typename?: 'TrendingMint'; + address?: Maybe; + audience?: Maybe; + blockchain?: Maybe; + chainId?: Maybe; + criteria?: Maybe; + criteriaCount?: Maybe; + erc1155TokenID?: Maybe; + id?: Maybe; + timeFrom?: Maybe; + timeTo?: Maybe; + token?: Maybe; +}; + +export enum TrendingMintsCriteria { + TotalMints = 'total_mints', + UniqueWallets = 'unique_wallets' +} + +export type TrendingMintsInput = { + audience: Audience; + blockchain: TrendingBlockchain; + criteria: TrendingMintsCriteria; + cursor?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + timeFrame: TimeFrame; +}; + +export type TrendingMintsOutput = { + __typename?: 'TrendingMintsOutput'; + TrendingMint?: Maybe>; + pageInfo?: Maybe; +}; + +export type TrendingSwap = { + __typename?: 'TrendingSwap'; + address?: Maybe; + blockchain?: Maybe; + buyTransactionCount?: Maybe; + buyVolume?: Maybe; + chainId?: Maybe; + criteria?: Maybe; + id?: Maybe; + sellTransactionCount?: Maybe; + sellVolume?: Maybe; + timeFrom?: Maybe; + timeTo?: Maybe; + token?: Maybe; + totalTransactionCount?: Maybe; + totalUniqueWallets?: Maybe; + totalVolume?: Maybe; + uniqueBuyWallets?: Maybe; + uniqueSellWallets?: Maybe; +}; + +export enum TrendingSwapsBlockchain { + Base = 'base', + Ethereum = 'ethereum' +} + +export enum TrendingSwapsCriteria { + BuyTransactionCount = 'buy_transaction_count', + BuyVolume = 'buy_volume', + SellTransactionCount = 'sell_transaction_count', + SellVolume = 'sell_volume', + TotalTransactionCount = 'total_transaction_count', + TotalUniqueWallets = 'total_unique_wallets', + TotalVolume = 'total_volume', + UniqueBuyWallets = 'unique_buy_wallets', + UniqueSellWallets = 'unique_sell_wallets' +} + +export type TrendingSwapsFilter = { + address?: InputMaybe; +}; + +export type TrendingSwapsInput = { + blockchain: TrendingSwapsBlockchain; + criteria: TrendingSwapsCriteria; + cursor?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + timeFrame: TimeFrame; +}; + +export type TrendingSwapsOutput = { + __typename?: 'TrendingSwapsOutput'; + TrendingSwap?: Maybe>; + pageInfo?: Maybe; +}; + +export type TrendingToken = { + __typename?: 'TrendingToken'; + address?: Maybe; + audience?: Maybe; + blockchain?: Maybe; + chainId?: Maybe; + criteria?: Maybe; + criteriaCount?: Maybe; + id?: Maybe; + timeFrom?: Maybe; + timeTo?: Maybe; + token?: Maybe; + uniqueHolders?: Maybe; +}; + +export enum TrendingTokensCriteria { + TotalTransfers = 'total_transfers', + UniqueHolders = 'unique_holders', + UniqueWallets = 'unique_wallets' +} + +export type TrendingTokensFilter = { + address?: InputMaybe; +}; + +export type TrendingTokensInput = { + audience: Audience; + blockchain: TrendingBlockchain; + criteria: TrendingTokensCriteria; + cursor?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; + swappable?: InputMaybe; + timeFrame: TimeFrame; + transferType: TrendingTokensTransferType; +}; + +export type TrendingTokensOutput = { + __typename?: 'TrendingTokensOutput'; + TrendingToken?: Maybe>; + pageInfo?: Maybe; +}; + +export enum TrendingTokensTransferType { + All = 'all', + SelfInitiated = 'self_initiated' +} + +export type Trending_Comparator_Exp = { + _eq?: InputMaybe; + _in?: InputMaybe>; +}; + +export type VideoVariants = { + __typename?: 'VideoVariants'; + original?: Maybe; +}; + +export type Wallet = { + __typename?: 'Wallet'; + /** Represent On-chain smart-contract accounts */ + accounts?: Maybe>; + /** Returns addresses associated with the identity input */ + addresses?: Maybe>; + /** Blockchain associated with the provided identity */ + blockchain?: Maybe; + /** Nested query - allows querying domains owned by the address */ + domains?: Maybe>; + /** Blockchain address, ENS domain name, social identity such as Farcaster (for Farcaster use 'fc_fid:' prefix followed by the Farcaster user ID like fc_fid:5650, or use 'fc_fname:' prefix followed by the Farcaster user ID like 'fc_fname:vbuterin') or Lens (e.g. 'stani.lens) */ + identity: Scalars['Identity']['output']; + /** Returns Poaps owned by the address */ + poaps?: Maybe>; + /** Nested query - allows returning primary domains, if applicable */ + primaryDomain?: Maybe; + socialFollowers?: Maybe; + socialFollowings?: Maybe; + /** Returns social profile information related to the address */ + socials?: Maybe>; + /** Nested query - allows returning token balances */ + tokenBalances?: Maybe>; + /** Nested query - allows returning token transfers and related information */ + tokenTransfers?: Maybe>; + /** Nested query - allows querying the XMTP enabled addresses */ + xmtp?: Maybe>; +}; + + +export type WalletAccountsArgs = { + input?: InputMaybe; +}; + + +export type WalletDomainsArgs = { + input?: InputMaybe; +}; + + +export type WalletPoapsArgs = { + input?: InputMaybe; +}; + + +export type WalletSocialFollowersArgs = { + input?: InputMaybe; +}; + + +export type WalletSocialFollowingsArgs = { + input?: InputMaybe; +}; + + +export type WalletSocialsArgs = { + input?: InputMaybe; +}; + + +export type WalletTokenBalancesArgs = { + input?: InputMaybe; +}; + + +export type WalletTokenTransfersArgs = { + input?: InputMaybe; +}; + + +export type WalletXmtpArgs = { + input?: InputMaybe; +}; + +export type WalletInput = { + blockchain: TokenBlockchain; + identity: Scalars['Identity']['input']; +}; + +export type Xmtp = { + __typename?: 'XMTP'; + blockchain?: Maybe; + /** Airstack unique identifier for the data point */ + id?: Maybe; + isXMTPEnabled?: Maybe; + owner?: Maybe; +}; + +export type XmtpFilter = { + owner?: InputMaybe; +}; + +export type XmtPsInput = { + blockchain: EveryBlockchain; + cursor?: InputMaybe; + filter: XmtpFilter; + limit?: InputMaybe; +}; + +export type XmtPsNestedInput = { + blockchain?: InputMaybe; + filter?: InputMaybe; + limit?: InputMaybe; +}; + +export type XmtPsOutput = { + __typename?: 'XMTPsOutput'; + XMTP?: Maybe>; + pageInfo?: Maybe; +}; + +export type GetMinimalProfileFromAddressQueryVariables = Exact<{ + identity: Scalars['Identity']['input']; +}>; + + +export type GetMinimalProfileFromAddressQuery = { __typename?: 'Query', Wallet?: { __typename?: 'Wallet', primaryDomain?: { __typename?: 'Domain', name?: string | null, avatar?: string | null, tokenNft?: { __typename?: 'TokenNft', contentValue?: { __typename?: 'Media', image?: { __typename?: 'ImageSizes', small?: string | null } | null } | null } | null } | null } | null, farcasterSocials?: { __typename?: 'SocialsOutput', Social?: Array<{ __typename?: 'Social', profileHandle?: string | null, profileBio?: string | null, profileImageContentValue?: { __typename?: 'Media', image?: { __typename?: 'ImageSizes', small?: string | null } | null } | null }> | null } | null, lensSocials?: { __typename?: 'SocialsOutput', Social?: Array<{ __typename?: 'Social', profileHandle?: string | null, profileBio?: string | null, profileImageContentValue?: { __typename?: 'Media', image?: { __typename?: 'ImageSizes', small?: string | null } | null } | null }> | null } | null }; + +export type GetProfileFromEnsQueryVariables = Exact<{ + identity: Scalars['Identity']['input']; +}>; + + +export type GetProfileFromEnsQuery = { __typename?: 'Query', Wallet?: { __typename?: 'Wallet', addresses?: Array | null, primaryDomain?: { __typename?: 'Domain', name?: string | null, avatar?: string | null, tokenNft?: { __typename?: 'TokenNft', contentValue?: { __typename?: 'Media', image?: { __typename?: 'ImageSizes', small?: string | null } | null } | null } | null } | null } | null }; + +export type GetProfileFromFarcasterQueryVariables = Exact<{ + identity: Scalars['Identity']['input']; +}>; + + +export type GetProfileFromFarcasterQuery = { __typename?: 'Query', farcasterSocials?: { __typename?: 'SocialsOutput', Social?: Array<{ __typename?: 'Social', userAddress?: any | null, profileName?: string | null, profileDisplayName?: string | null, profileHandle?: string | null, profileBio?: string | null, connectedAddresses?: Array<{ __typename?: 'ConnectedAddress', address?: any | null }> | null, profileImageContentValue?: { __typename?: 'Media', image?: { __typename?: 'ImageSizes', small?: string | null } | null } | null }> | null } | null }; + +export type GetProfileFromLensQueryVariables = Exact<{ + identity: Scalars['Identity']['input']; +}>; + + +export type GetProfileFromLensQuery = { __typename?: 'Query', Wallet?: { __typename?: 'Wallet', addresses?: Array | null } | null, lensSocials?: { __typename?: 'SocialsOutput', Social?: Array<{ __typename?: 'Social', profileName?: string | null, profileDisplayName?: string | null, profileHandle?: string | null, profileBio?: string | null, profileImageContentValue?: { __typename?: 'Media', image?: { __typename?: 'ImageSizes', small?: string | null } | null } | null }> | null } | null }; + +export type GetProfileInfoQueryVariables = Exact<{ + identity: Scalars['Identity']['input']; +}>; + + +export type GetProfileInfoQuery = { __typename?: 'Query', Wallet?: { __typename?: 'Wallet', addresses?: Array | null, primaryDomain?: { __typename?: 'Domain', name?: string | null, avatar?: string | null, tokenNft?: { __typename?: 'TokenNft', contentValue?: { __typename?: 'Media', image?: { __typename?: 'ImageSizes', small?: string | null } | null } | null } | null } | null } | null, farcasterSocials?: { __typename?: 'SocialsOutput', Social?: Array<{ __typename?: 'Social', userAddress?: any | null, profileName?: string | null, profileDisplayName?: string | null, profileHandle?: string | null, profileBio?: string | null, connectedAddresses?: Array<{ __typename?: 'ConnectedAddress', address?: any | null }> | null, profileImageContentValue?: { __typename?: 'Media', image?: { __typename?: 'ImageSizes', small?: string | null } | null } | null }> | null } | null, lensSocials?: { __typename?: 'SocialsOutput', Social?: Array<{ __typename?: 'Social', profileName?: string | null, profileDisplayName?: string | null, profileHandle?: string | null, profileBio?: string | null, profileImageContentValue?: { __typename?: 'Media', image?: { __typename?: 'ImageSizes', small?: string | null } | null } | null }> | null } | null }; + +export class TypedDocumentString + extends String + implements DocumentTypeDecoration +{ + __apiType?: DocumentTypeDecoration['__apiType']; + + constructor(private value: string, public __meta__?: Record) { + super(value); + } + + toString(): string & DocumentTypeDecoration { + return this.value; + } +} + +export const GetMinimalProfileFromAddressDocument = new TypedDocumentString(` + query GetMinimalProfileFromAddress($identity: Identity!) { + Wallet(input: {identity: $identity, blockchain: ethereum}) { + primaryDomain { + name + avatar + tokenNft { + contentValue { + image { + small + } + } + } + } + } + farcasterSocials: Socials( + input: {filter: {identity: {_eq: $identity}, dappName: {_eq: farcaster}}, blockchain: ethereum, order: {followerCount: DESC}, limit: 1} + ) { + Social { + profileHandle + profileBio + profileImageContentValue { + image { + small + } + } + } + } + lensSocials: Socials( + input: {filter: {identity: {_eq: $identity}, dappName: {_eq: lens}}, blockchain: ethereum, order: {followerCount: DESC}, limit: 1} + ) { + Social { + profileHandle + profileBio + profileImageContentValue { + image { + small + } + } + } + } +} + `) as unknown as TypedDocumentString; +export const GetProfileFromEnsDocument = new TypedDocumentString(` + query GetProfileFromEns($identity: Identity!) { + Wallet(input: {identity: $identity, blockchain: ethereum}) { + addresses + primaryDomain { + name + avatar + tokenNft { + contentValue { + image { + small + } + } + } + } + } +} + `) as unknown as TypedDocumentString; +export const GetProfileFromFarcasterDocument = new TypedDocumentString(` + query GetProfileFromFarcaster($identity: Identity!) { + farcasterSocials: Socials( + input: {limit: 1, filter: {identity: {_eq: $identity}, dappName: {_eq: farcaster}}, blockchain: ethereum, order: {followerCount: DESC}} + ) { + Social { + connectedAddresses { + address + } + userAddress + profileName + profileDisplayName + profileHandle + profileBio + profileImageContentValue { + image { + small + } + } + } + } +} + `) as unknown as TypedDocumentString; +export const GetProfileFromLensDocument = new TypedDocumentString(` + query GetProfileFromLens($identity: Identity!) { + Wallet(input: {identity: $identity, blockchain: ethereum}) { + addresses + } + lensSocials: Socials( + input: {limit: 1, filter: {identity: {_eq: $identity}, dappName: {_eq: lens}}, blockchain: ethereum, order: {followerCount: DESC}} + ) { + Social { + profileName + profileDisplayName + profileHandle + profileBio + profileImageContentValue { + image { + small + } + } + } + } +} + `) as unknown as TypedDocumentString; +export const GetProfileInfoDocument = new TypedDocumentString(` + query GetProfileInfo($identity: Identity!) { + Wallet(input: {identity: $identity, blockchain: ethereum}) { + addresses + primaryDomain { + name + avatar + tokenNft { + contentValue { + image { + small + } + } + } + } + } + farcasterSocials: Socials( + input: {filter: {identity: {_eq: $identity}, dappName: {_eq: farcaster}}, blockchain: ethereum, order: {followerCount: DESC}} + ) { + Social { + connectedAddresses { + address + } + userAddress + profileName + profileDisplayName + profileHandle + profileBio + profileImageContentValue { + image { + small + } + } + } + } + lensSocials: Socials( + input: {filter: {identity: {_eq: $identity}, dappName: {_eq: lens}}, blockchain: ethereum, order: {followerCount: DESC}} + ) { + Social { + profileName + profileDisplayName + profileHandle + profileBio + profileImageContentValue { + image { + small + } + } + } + } +} + `) as unknown as TypedDocumentString; \ No newline at end of file diff --git a/packages/dapp/src/__generated__/airstack/index.ts b/packages/dapp/src/__generated__/airstack/index.ts new file mode 100644 index 0000000..f515991 --- /dev/null +++ b/packages/dapp/src/__generated__/airstack/index.ts @@ -0,0 +1,2 @@ +export * from "./fragment-masking"; +export * from "./gql"; \ No newline at end of file diff --git a/packages/dapp/src/__generated__/ees/fragment-masking.ts b/packages/dapp/src/__generated__/ees/fragment-masking.ts index fbedede..cca7098 100644 --- a/packages/dapp/src/__generated__/ees/fragment-masking.ts +++ b/packages/dapp/src/__generated__/ees/fragment-masking.ts @@ -1,7 +1,6 @@ /* eslint-disable */ -import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; -import { FragmentDefinitionNode } from 'graphql'; -import { Incremental } from './graphql'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; +import { Incremental, TypedDocumentString } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration< @@ -50,18 +49,15 @@ export function makeFragmentData< return data as FragmentType; } export function isFragmentReady( - queryNode: DocumentTypeDecoration, - fragmentNode: TypedDocumentNode, - data: FragmentType, any>> | null | undefined + queryNode: TypedDocumentString, + fragmentNode: TypedDocumentString, + data: FragmentType, any>> | null | undefined ): data is FragmentType { - const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ - ?.deferredFields; + const deferredFields = queryNode.__meta__?.deferredFields as Record; + const fragName = fragmentNode.__meta__?.fragmentName as string | undefined; - if (!deferredFields) return true; + if (!deferredFields || !fragName) return true; - const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; - const fragName = fragDef?.name?.value; - - const fields = (fragName && deferredFields[fragName]) || []; + const fields = deferredFields[fragName] ?? []; return fields.length > 0 && fields.every(field => data && field in data); } diff --git a/packages/dapp/src/__generated__/ees/gql.ts b/packages/dapp/src/__generated__/ees/gql.ts index 95cf6a4..fd2c862 100644 --- a/packages/dapp/src/__generated__/ees/gql.ts +++ b/packages/dapp/src/__generated__/ees/gql.ts @@ -1,6 +1,7 @@ /* eslint-disable */ import * as types from './graphql'; -import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; + + /** * Map of all GraphQL operations in the project. @@ -13,42 +14,20 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { - 'query GetAccount($address: ID!) {\n account(id: $address) {\n id\n totalDonationsReceived\n totalDonationsSent\n }\n}': - types.GetAccountDocument, - 'query GetAccounts {\n accounts {\n id\n totalDonationsReceived\n totalDonationsSent\n }\n}': - types.GetAccountsDocument, + "query GetAggregatedAccountData($account: ID!) {\n account(id: $account) {\n id\n totalEndorsementsReceived\n totalEndorsementsSent\n totalDonationsReceived\n totalDonationsSent\n }\n}": types.GetAggregatedAccountDataDocument, + "query GetTopEndorsersAndDonators($account: String!) {\n topEndorsers: aggregatedInformations(\n where: {to: $account}\n orderBy: from__totalEndorsementsReceived\n orderDirection: desc\n first: 6\n ) {\n id\n from {\n id\n }\n }\n topDonators: aggregatedInformations(\n where: {to: $account, donationAmount_gt: 0}\n orderBy: donationAmount\n orderDirection: desc\n first: 6\n ) {\n id\n from {\n id\n }\n donationAmount\n }\n}": types.GetTopEndorsersAndDonatorsDocument, }; /** * The gqlEES function is used to parse GraphQL queries into a document that can be used by GraphQL clients. - * - * - * @example - * ```ts - * const query = gqlEES(`query GetUser($id: ID!) { user(id: $id) { name } }`); - * ``` - * - * The query argument is unknown! - * Please regenerate the types. */ -export function gqlEES(source: string): unknown; - +export function gqlEES(source: "query GetAggregatedAccountData($account: ID!) {\n account(id: $account) {\n id\n totalEndorsementsReceived\n totalEndorsementsSent\n totalDonationsReceived\n totalDonationsSent\n }\n}"): typeof import('./graphql').GetAggregatedAccountDataDocument; /** * The gqlEES function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gqlEES( - source: 'query GetAccount($address: ID!) {\n account(id: $address) {\n id\n totalDonationsReceived\n totalDonationsSent\n }\n}' -): (typeof documents)['query GetAccount($address: ID!) {\n account(id: $address) {\n id\n totalDonationsReceived\n totalDonationsSent\n }\n}']; -/** - * The gqlEES function is used to parse GraphQL queries into a document that can be used by GraphQL clients. - */ -export function gqlEES( - source: 'query GetAccounts {\n accounts {\n id\n totalDonationsReceived\n totalDonationsSent\n }\n}' -): (typeof documents)['query GetAccounts {\n accounts {\n id\n totalDonationsReceived\n totalDonationsSent\n }\n}']; +export function gqlEES(source: "query GetTopEndorsersAndDonators($account: String!) {\n topEndorsers: aggregatedInformations(\n where: {to: $account}\n orderBy: from__totalEndorsementsReceived\n orderDirection: desc\n first: 6\n ) {\n id\n from {\n id\n }\n }\n topDonators: aggregatedInformations(\n where: {to: $account, donationAmount_gt: 0}\n orderBy: donationAmount\n orderDirection: desc\n first: 6\n ) {\n id\n from {\n id\n }\n donationAmount\n }\n}"): typeof import('./graphql').GetTopEndorsersAndDonatorsDocument; + export function gqlEES(source: string) { return (documents as any)[source] ?? {}; } - -export type DocumentType> = - TDocumentNode extends DocumentNode ? TType : never; diff --git a/packages/dapp/src/__generated__/ees/graphql.ts b/packages/dapp/src/__generated__/ees/graphql.ts index 1941240..b6ef2ff 100644 --- a/packages/dapp/src/__generated__/ees/graphql.ts +++ b/packages/dapp/src/__generated__/ees/graphql.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; @@ -22,11 +22,6 @@ export type Scalars = { * */ Int8: { input: any; output: any; } - /** - * A string representation of microseconds UNIX timestamp (16 digits) - * - */ - Timestamp: { input: any; output: any; } }; export type Account = { @@ -38,6 +33,8 @@ export type Account = { sentEndorsements: Array; totalDonationsReceived: Scalars['BigInt']['output']; totalDonationsSent: Scalars['BigInt']['output']; + totalEndorsementsReceived: Scalars['BigInt']['output']; + totalEndorsementsSent: Scalars['BigInt']['output']; withdrawals: Array; }; @@ -121,6 +118,22 @@ export type Account_Filter = { totalDonationsSent_lte?: InputMaybe; totalDonationsSent_not?: InputMaybe; totalDonationsSent_not_in?: InputMaybe>; + totalEndorsementsReceived?: InputMaybe; + totalEndorsementsReceived_gt?: InputMaybe; + totalEndorsementsReceived_gte?: InputMaybe; + totalEndorsementsReceived_in?: InputMaybe>; + totalEndorsementsReceived_lt?: InputMaybe; + totalEndorsementsReceived_lte?: InputMaybe; + totalEndorsementsReceived_not?: InputMaybe; + totalEndorsementsReceived_not_in?: InputMaybe>; + totalEndorsementsSent?: InputMaybe; + totalEndorsementsSent_gt?: InputMaybe; + totalEndorsementsSent_gte?: InputMaybe; + totalEndorsementsSent_in?: InputMaybe>; + totalEndorsementsSent_lt?: InputMaybe; + totalEndorsementsSent_lte?: InputMaybe; + totalEndorsementsSent_not?: InputMaybe; + totalEndorsementsSent_not_in?: InputMaybe>; withdrawals_?: InputMaybe; }; @@ -132,12 +145,111 @@ export enum Account_OrderBy { SentEndorsements = 'sentEndorsements', TotalDonationsReceived = 'totalDonationsReceived', TotalDonationsSent = 'totalDonationsSent', + TotalEndorsementsReceived = 'totalEndorsementsReceived', + TotalEndorsementsSent = 'totalEndorsementsSent', Withdrawals = 'withdrawals' } -export enum Aggregation_Interval { - Day = 'day', - Hour = 'hour' +export type AggregatedInformation = { + __typename?: 'AggregatedInformation'; + donationAmount: Scalars['BigInt']['output']; + endorsementCount: Scalars['BigInt']['output']; + from: Account; + id: Scalars['Bytes']['output']; + to: Account; +}; + +export type AggregatedInformation_Filter = { + /** Filter for the block changed event. */ + _change_block?: InputMaybe; + and?: InputMaybe>>; + donationAmount?: InputMaybe; + donationAmount_gt?: InputMaybe; + donationAmount_gte?: InputMaybe; + donationAmount_in?: InputMaybe>; + donationAmount_lt?: InputMaybe; + donationAmount_lte?: InputMaybe; + donationAmount_not?: InputMaybe; + donationAmount_not_in?: InputMaybe>; + endorsementCount?: InputMaybe; + endorsementCount_gt?: InputMaybe; + endorsementCount_gte?: InputMaybe; + endorsementCount_in?: InputMaybe>; + endorsementCount_lt?: InputMaybe; + endorsementCount_lte?: InputMaybe; + endorsementCount_not?: InputMaybe; + endorsementCount_not_in?: InputMaybe>; + from?: InputMaybe; + from_?: InputMaybe; + from_contains?: InputMaybe; + from_contains_nocase?: InputMaybe; + from_ends_with?: InputMaybe; + from_ends_with_nocase?: InputMaybe; + from_gt?: InputMaybe; + from_gte?: InputMaybe; + from_in?: InputMaybe>; + from_lt?: InputMaybe; + from_lte?: InputMaybe; + from_not?: InputMaybe; + from_not_contains?: InputMaybe; + from_not_contains_nocase?: InputMaybe; + from_not_ends_with?: InputMaybe; + from_not_ends_with_nocase?: InputMaybe; + from_not_in?: InputMaybe>; + from_not_starts_with?: InputMaybe; + from_not_starts_with_nocase?: InputMaybe; + from_starts_with?: InputMaybe; + from_starts_with_nocase?: InputMaybe; + id?: InputMaybe; + id_contains?: InputMaybe; + id_gt?: InputMaybe; + id_gte?: InputMaybe; + id_in?: InputMaybe>; + id_lt?: InputMaybe; + id_lte?: InputMaybe; + id_not?: InputMaybe; + id_not_contains?: InputMaybe; + id_not_in?: InputMaybe>; + or?: InputMaybe>>; + to?: InputMaybe; + to_?: InputMaybe; + to_contains?: InputMaybe; + to_contains_nocase?: InputMaybe; + to_ends_with?: InputMaybe; + to_ends_with_nocase?: InputMaybe; + to_gt?: InputMaybe; + to_gte?: InputMaybe; + to_in?: InputMaybe>; + to_lt?: InputMaybe; + to_lte?: InputMaybe; + to_not?: InputMaybe; + to_not_contains?: InputMaybe; + to_not_contains_nocase?: InputMaybe; + to_not_ends_with?: InputMaybe; + to_not_ends_with_nocase?: InputMaybe; + to_not_in?: InputMaybe>; + to_not_starts_with?: InputMaybe; + to_not_starts_with_nocase?: InputMaybe; + to_starts_with?: InputMaybe; + to_starts_with_nocase?: InputMaybe; +}; + +export enum AggregatedInformation_OrderBy { + DonationAmount = 'donationAmount', + EndorsementCount = 'endorsementCount', + From = 'from', + FromId = 'from__id', + FromTotalDonationsReceived = 'from__totalDonationsReceived', + FromTotalDonationsSent = 'from__totalDonationsSent', + FromTotalEndorsementsReceived = 'from__totalEndorsementsReceived', + FromTotalEndorsementsSent = 'from__totalEndorsementsSent', + Id = 'id', + To = 'to', + ToId = 'to__id', + ToTotalDonationsReceived = 'to__totalDonationsReceived', + ToTotalDonationsSent = 'to__totalDonationsSent', + ToTotalEndorsementsReceived = 'to__totalEndorsementsReceived', + ToTotalEndorsementsSent = 'to__totalEndorsementsSent' } export type BlockChangedFilter = { @@ -231,17 +343,22 @@ export enum Donation_OrderBy { FromId = 'from__id', FromTotalDonationsReceived = 'from__totalDonationsReceived', FromTotalDonationsSent = 'from__totalDonationsSent', + FromTotalEndorsementsReceived = 'from__totalEndorsementsReceived', + FromTotalEndorsementsSent = 'from__totalEndorsementsSent', Id = 'id', To = 'to', ToId = 'to__id', ToTotalDonationsReceived = 'to__totalDonationsReceived', - ToTotalDonationsSent = 'to__totalDonationsSent' + ToTotalDonationsSent = 'to__totalDonationsSent', + ToTotalEndorsementsReceived = 'to__totalEndorsementsReceived', + ToTotalEndorsementsSent = 'to__totalEndorsementsSent' } export type Endorsement = { __typename?: 'Endorsement'; + donationAmount: Scalars['BigInt']['output']; easUid: Scalars['Bytes']['output']; - endorsmentType: Scalars['String']['output']; + endorsementType: Scalars['String']['output']; from: Account; id: Scalars['Bytes']['output']; to: Account; @@ -251,6 +368,14 @@ export type Endorsement_Filter = { /** Filter for the block changed event. */ _change_block?: InputMaybe; and?: InputMaybe>>; + donationAmount?: InputMaybe; + donationAmount_gt?: InputMaybe; + donationAmount_gte?: InputMaybe; + donationAmount_in?: InputMaybe>; + donationAmount_lt?: InputMaybe; + donationAmount_lte?: InputMaybe; + donationAmount_not?: InputMaybe; + donationAmount_not_in?: InputMaybe>; easUid?: InputMaybe; easUid_contains?: InputMaybe; easUid_gt?: InputMaybe; @@ -261,26 +386,26 @@ export type Endorsement_Filter = { easUid_not?: InputMaybe; easUid_not_contains?: InputMaybe; easUid_not_in?: InputMaybe>; - endorsmentType?: InputMaybe; - endorsmentType_contains?: InputMaybe; - endorsmentType_contains_nocase?: InputMaybe; - endorsmentType_ends_with?: InputMaybe; - endorsmentType_ends_with_nocase?: InputMaybe; - endorsmentType_gt?: InputMaybe; - endorsmentType_gte?: InputMaybe; - endorsmentType_in?: InputMaybe>; - endorsmentType_lt?: InputMaybe; - endorsmentType_lte?: InputMaybe; - endorsmentType_not?: InputMaybe; - endorsmentType_not_contains?: InputMaybe; - endorsmentType_not_contains_nocase?: InputMaybe; - endorsmentType_not_ends_with?: InputMaybe; - endorsmentType_not_ends_with_nocase?: InputMaybe; - endorsmentType_not_in?: InputMaybe>; - endorsmentType_not_starts_with?: InputMaybe; - endorsmentType_not_starts_with_nocase?: InputMaybe; - endorsmentType_starts_with?: InputMaybe; - endorsmentType_starts_with_nocase?: InputMaybe; + endorsementType?: InputMaybe; + endorsementType_contains?: InputMaybe; + endorsementType_contains_nocase?: InputMaybe; + endorsementType_ends_with?: InputMaybe; + endorsementType_ends_with_nocase?: InputMaybe; + endorsementType_gt?: InputMaybe; + endorsementType_gte?: InputMaybe; + endorsementType_in?: InputMaybe>; + endorsementType_lt?: InputMaybe; + endorsementType_lte?: InputMaybe; + endorsementType_not?: InputMaybe; + endorsementType_not_contains?: InputMaybe; + endorsementType_not_contains_nocase?: InputMaybe; + endorsementType_not_ends_with?: InputMaybe; + endorsementType_not_ends_with_nocase?: InputMaybe; + endorsementType_not_in?: InputMaybe>; + endorsementType_not_starts_with?: InputMaybe; + endorsementType_not_starts_with_nocase?: InputMaybe; + endorsementType_starts_with?: InputMaybe; + endorsementType_starts_with_nocase?: InputMaybe; from?: InputMaybe; from_?: InputMaybe; from_contains?: InputMaybe; @@ -337,17 +462,22 @@ export type Endorsement_Filter = { }; export enum Endorsement_OrderBy { + DonationAmount = 'donationAmount', EasUid = 'easUid', - EndorsmentType = 'endorsmentType', + EndorsementType = 'endorsementType', From = 'from', FromId = 'from__id', FromTotalDonationsReceived = 'from__totalDonationsReceived', FromTotalDonationsSent = 'from__totalDonationsSent', + FromTotalEndorsementsReceived = 'from__totalEndorsementsReceived', + FromTotalEndorsementsSent = 'from__totalEndorsementsSent', Id = 'id', To = 'to', ToId = 'to__id', ToTotalDonationsReceived = 'to__totalDonationsReceived', - ToTotalDonationsSent = 'to__totalDonationsSent' + ToTotalDonationsSent = 'to__totalDonationsSent', + ToTotalEndorsementsReceived = 'to__totalEndorsementsReceived', + ToTotalEndorsementsSent = 'to__totalEndorsementsSent' } export type FeeWithdrawal = { @@ -432,6 +562,8 @@ export type Query = { _meta?: Maybe<_Meta_>; account?: Maybe; accounts: Array; + aggregatedInformation?: Maybe; + aggregatedInformations: Array; donation?: Maybe; donations: Array; endorsement?: Maybe; @@ -466,6 +598,24 @@ export type QueryAccountsArgs = { }; +export type QueryAggregatedInformationArgs = { + block?: InputMaybe; + id: Scalars['ID']['input']; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QueryAggregatedInformationsArgs = { + block?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; + where?: InputMaybe; +}; + + export type QueryDonationArgs = { block?: InputMaybe; id: Scalars['ID']['input']; @@ -543,6 +693,8 @@ export type Subscription = { _meta?: Maybe<_Meta_>; account?: Maybe; accounts: Array; + aggregatedInformation?: Maybe; + aggregatedInformations: Array; donation?: Maybe; donations: Array; endorsement?: Maybe; @@ -577,6 +729,24 @@ export type SubscriptionAccountsArgs = { }; +export type SubscriptionAggregatedInformationArgs = { + block?: InputMaybe; + id: Scalars['ID']['input']; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptionAggregatedInformationsArgs = { + block?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; + where?: InputMaybe; +}; + + export type SubscriptionDonationArgs = { block?: InputMaybe; id: Scalars['ID']['input']; @@ -706,6 +876,8 @@ export enum Withdrawal_OrderBy { AddressId = 'address__id', AddressTotalDonationsReceived = 'address__totalDonationsReceived', AddressTotalDonationsSent = 'address__totalDonationsSent', + AddressTotalEndorsementsReceived = 'address__totalEndorsementsReceived', + AddressTotalEndorsementsSent = 'address__totalEndorsementsSent', Amount = 'amount', Id = 'id' } @@ -716,8 +888,6 @@ export type _Block_ = { hash?: Maybe; /** The block number */ number: Scalars['Int']['output']; - /** The hash of the parent block */ - parentHash?: Maybe; /** Integer representation of the timestamp stored in blocks for the chain */ timestamp?: Maybe; }; @@ -746,18 +916,70 @@ export enum _SubgraphErrorPolicy_ { Deny = 'deny' } -export type GetAccountQueryVariables = Exact<{ - address: Scalars['ID']['input']; +export type GetAggregatedAccountDataQueryVariables = Exact<{ + account: Scalars['ID']['input']; }>; -export type GetAccountQuery = { __typename?: 'Query', account?: { __typename?: 'Account', id: any, totalDonationsReceived: any, totalDonationsSent: any } | null }; +export type GetAggregatedAccountDataQuery = { __typename?: 'Query', account?: { __typename?: 'Account', id: any, totalEndorsementsReceived: any, totalEndorsementsSent: any, totalDonationsReceived: any, totalDonationsSent: any } | null }; -export type GetAccountsQueryVariables = Exact<{ [key: string]: never; }>; +export type GetTopEndorsersAndDonatorsQueryVariables = Exact<{ + account: Scalars['String']['input']; +}>; + + +export type GetTopEndorsersAndDonatorsQuery = { __typename?: 'Query', topEndorsers: Array<{ __typename?: 'AggregatedInformation', id: any, from: { __typename?: 'Account', id: any } }>, topDonators: Array<{ __typename?: 'AggregatedInformation', id: any, donationAmount: any, from: { __typename?: 'Account', id: any } }> }; +export class TypedDocumentString + extends String + implements DocumentTypeDecoration +{ + __apiType?: DocumentTypeDecoration['__apiType']; -export type GetAccountsQuery = { __typename?: 'Query', accounts: Array<{ __typename?: 'Account', id: any, totalDonationsReceived: any, totalDonationsSent: any }> }; + constructor(private value: string, public __meta__?: Record) { + super(value); + } + toString(): string & DocumentTypeDecoration { + return this.value; + } +} -export const GetAccountDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAccount"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"address"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"account"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"address"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"totalDonationsReceived"}},{"kind":"Field","name":{"kind":"Name","value":"totalDonationsSent"}}]}}]}}]} as unknown as DocumentNode; -export const GetAccountsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"accounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"totalDonationsReceived"}},{"kind":"Field","name":{"kind":"Name","value":"totalDonationsSent"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export const GetAggregatedAccountDataDocument = new TypedDocumentString(` + query GetAggregatedAccountData($account: ID!) { + account(id: $account) { + id + totalEndorsementsReceived + totalEndorsementsSent + totalDonationsReceived + totalDonationsSent + } +} + `) as unknown as TypedDocumentString; +export const GetTopEndorsersAndDonatorsDocument = new TypedDocumentString(` + query GetTopEndorsersAndDonators($account: String!) { + topEndorsers: aggregatedInformations( + where: {to: $account} + orderBy: from__totalEndorsementsReceived + orderDirection: desc + first: 6 + ) { + id + from { + id + } + } + topDonators: aggregatedInformations( + where: {to: $account, donationAmount_gt: 0} + orderBy: donationAmount + orderDirection: desc + first: 6 + ) { + id + from { + id + } + donationAmount + } +} + `) as unknown as TypedDocumentString; \ No newline at end of file diff --git a/packages/dapp/src/__generated__/ees/index.ts b/packages/dapp/src/__generated__/ees/index.ts index c682b1e..f515991 100644 --- a/packages/dapp/src/__generated__/ees/index.ts +++ b/packages/dapp/src/__generated__/ees/index.ts @@ -1,2 +1,2 @@ -export * from './fragment-masking'; -export * from './gql'; +export * from "./fragment-masking"; +export * from "./gql"; \ No newline at end of file diff --git a/packages/dapp/src/app/api/og/route.tsx b/packages/dapp/src/app/api/og/route.tsx index 9bab4f5..20c8d58 100644 --- a/packages/dapp/src/app/api/og/route.tsx +++ b/packages/dapp/src/app/api/og/route.tsx @@ -1,5 +1,14 @@ +import { getMinimalProfileInfoByPlatform } from '@/lib/airstack'; +import { getMinimalProfileFromAddress } from '@/lib/airstack/getMinimalProfileFromAddress'; +import { + PlatformType, + formatAddress, + validateOrGetDefaultPlatform, +} from '@/utils'; import { ImageResponse } from 'next/og'; import type { NextRequest } from 'next/server'; +import { blo } from 'blo'; +import { APP_URL } from '@/utils'; export const runtime = 'edge'; @@ -11,82 +20,23 @@ export async function GET(req: NextRequest) { try { const fontRegular = await interRegular; + // Read search params const { searchParams } = new URL(req.url); - const values = Object.fromEntries(searchParams); + const { platform, account } = values; - const { title, description, platform, account, avatar, type } = values; + const _platform = validateOrGetDefaultPlatform(platform); - if (type && type) { - return new ImageResponse( -
-
-
-
- {avatar ? ( - EES Logo - ) : ( -
- {account[0].toUpperCase()} -
- )} -

- {account} -

-
{description}
-
-
- EES Logo -
-
-
-
, - // ImageResponse options - { - width: 1200, - height: 630, - fonts: [ - { - name: 'Inter', - data: fontRegular, - weight: 400, - style: 'normal', - }, - { - name: 'Inter Medium', - data: fontRegular, - weight: 600, - style: 'normal', - }, - ], - } - ); + const { address, avatar, description, displayName, error } = + _platform === PlatformType.ethereum + ? await getMinimalProfileFromAddress(account as `0x${string}`) + : await getMinimalProfileInfoByPlatform(_platform, account); + + // Return bad request if error + if (error || !address) { + return new Response('Failed to generate OG image', { + status: 400, + }); } return new ImageResponse( @@ -105,6 +55,12 @@ export async function GET(req: NextRequest) {
+ Profile avatar

- Endorse.fun + {displayName ?? formatAddress(address)}

-
-
{'Build Web3 '}
-
{' Reputation '}
-
{'with '}
-
Endorsements
-
+ {description &&
{description}
}{' '}
-
-
- EES Logo +
+ EES Logo
@@ -153,7 +99,7 @@ export async function GET(req: NextRequest) { } ); } catch (error) { - return new Response('Failed to generate image', { + return new Response('Failed to generate OG image', { status: 500, }); } diff --git a/packages/dapp/src/app/api/quota/route.ts b/packages/dapp/src/app/api/quota/route.ts index 434806f..91676c2 100644 --- a/packages/dapp/src/app/api/quota/route.ts +++ b/packages/dapp/src/app/api/quota/route.ts @@ -5,10 +5,13 @@ import { randomBytes } from 'node:crypto'; const SUPPORTED_FIAT = new Set(['USD', 'EUR']); const SUPPORTED_CRYPTO = new Set(['ETH', 'USDC']); -export const revalidate = 60; // revalidate at most every 2 minutes +export const revalidate = 60; // revalidate at most every 1 minute const KEY_NAME = process.env.COINBASE_API_KEY_NAME!; -const KEY_SECRET = process.env.COINBASE_API_KEY_SECRET!; +const KEY_SECRET = (process.env.COINBASE_API_KEY_SECRET ?? '').replace( + /\\n/g, + '\n' +); const URL = 'api.coinbase.com'; const REQUEST_PATH = '/api/v3/brokerage/market/products'; @@ -72,7 +75,7 @@ export async function GET(request: NextRequest) { headers: { Authorization: `Bearer ${token}`, }, - next: { revalidate: 60 }, // Cache for 2 minutes + next: { revalidate: 60 }, // Cache for 1 minute } ); diff --git a/packages/dapp/src/app/claim/ClaimCard.tsx b/packages/dapp/src/app/claim/ClaimCard.tsx index 90f5a50..f1c6c6c 100644 --- a/packages/dapp/src/app/claim/ClaimCard.tsx +++ b/packages/dapp/src/app/claim/ClaimCard.tsx @@ -52,11 +52,11 @@ export const ClaimCard = () => { }) .then((txHash) => { toast( -
+
-
+

Transaction submitted

@@ -84,11 +84,11 @@ export const ClaimCard = () => { if (error.name === 'TransactionExecutionError') { if (error.cause.name === 'UserRejectedRequestError') { return toast( -
+
-
+

Transaction rejected

, @@ -100,11 +100,11 @@ export const ClaimCard = () => { } return toast( -
+
-
+

Something went wrong

, @@ -122,7 +122,7 @@ export const ClaimCard = () => { if (isQuotaError || isDonationBalanceError) { return ( -
Could not estimate value
+
Couldn't estimate value.
); } @@ -177,7 +177,7 @@ export const ClaimCard = () => {
- Unclaimed donations + Tips available to claim
{DonationBalance} @@ -219,7 +219,7 @@ export const ClaimCard = () => { > {donationBalance?.toString() === '0' ? 'Nothing to claim' - : 'Claim donations'} + : 'Claim tips'} )} diff --git a/packages/dapp/src/app/error.tsx b/packages/dapp/src/app/error.tsx new file mode 100644 index 0000000..9db19d4 --- /dev/null +++ b/packages/dapp/src/app/error.tsx @@ -0,0 +1,33 @@ +'use client'; // Error components must be Client Components + +import { Button } from '@/components/ui/button'; +import { useEffect } from 'react'; + +export default function ErrorPage({ + error, + reset, +}: { + error: Error & { digest?: string }; + reset: () => void; +}) { + useEffect(() => { + // Log the error to an error reporting service + console.error(error); + }, [error]); + + return ( +
+

An error occurred

+ +
+ ); +} diff --git a/packages/dapp/src/app/layout.tsx b/packages/dapp/src/app/layout.tsx index 566d770..94062bf 100644 --- a/packages/dapp/src/app/layout.tsx +++ b/packages/dapp/src/app/layout.tsx @@ -8,16 +8,32 @@ import { Providers } from '@/components/Providers'; import { cookieToInitialState } from '@/lib/wagmi/cookieToInitialState'; import { cn } from '@/lib/utils'; import { Toaster } from '@/components/ui/sonner'; +import { Analytics } from '@vercel/analytics/react'; +import { SpeedInsights } from '@vercel/speed-insights/next'; const inter = Inter({ subsets: ['latin'] }); export const metadata: Metadata = { - title: 'Endorse - Ethereum Endorsement Service', + metadataBase: new URL('https://ees-eosin.vercel.app'), + title: 'endorse.fun - Ethereum Endorsement Service', + description: 'The next upgrade for Web3 social layer.', robots: { // FIXME: Update for production release index: false, follow: false, }, + openGraph: { + description: 'The next upgrade for Web3 social layer.', + siteName: 'endorse.fun', + title: 'endorse.fun - Ethereum Endorsement Service', + type: 'article', + url: '/', + }, + twitter: { + card: 'summary_large_image', + title: 'endorse.fun - Ethereum Endorsement Service', + description: 'The next upgrade for Web3 social layer.', + }, }; export default function RootLayout(props: { children: ReactNode }) { @@ -25,9 +41,9 @@ export default function RootLayout(props: { children: ReactNode }) { const initialState = cookieToInitialState(headers().get('cookie')); return ( - + -
+
@@ -36,6 +52,8 @@ export default function RootLayout(props: { children: ReactNode }) {
+ + ); diff --git a/packages/dapp/src/app/opengraph-image.tsx b/packages/dapp/src/app/opengraph-image.tsx new file mode 100644 index 0000000..1fb8cb1 --- /dev/null +++ b/packages/dapp/src/app/opengraph-image.tsx @@ -0,0 +1,61 @@ +import { APP_URL } from '@/utils'; +import { ImageResponse } from 'next/og'; + +export const runtime = 'nodejs'; +export const alt = 'Check out my profile on endorse.fun!'; +export const size = { + width: 1200, + height: 630, +}; +export const contentType = 'image/png'; +export const revalidate = 86400; // Cache for 1 day + +export default async function Image() { + return new ImageResponse( +
+
+
+
+

+ endorse.fun +

+
+
{'Build Web3 '}
+
{' Reputation '}
+
{'with '}
+
Endorsements
+
+
+
+
+ EES Logo with text +
+
+
+
, + { + ...size, + } + ); +} diff --git a/packages/dapp/src/app/page.tsx b/packages/dapp/src/app/page.tsx index 7bd0d13..2189778 100644 --- a/packages/dapp/src/app/page.tsx +++ b/packages/dapp/src/app/page.tsx @@ -1,7 +1,77 @@ -import { HomepageView } from '@/components/HomepageView'; +import { Container } from '@/components/Container'; +import { EndorseForm } from '@/components/EndorseForm'; +import { Endorsee, EndorseeSkeleton } from '@/components/Endorsee'; +import { Button } from '@/components/ui/button'; +import { PlatformType, validateOrGetDefaultPlatform } from '@/utils'; +import Link from 'next/link'; +import { Suspense } from 'react'; -function App() { - return ; -} +export default async function Page({ + searchParams, +}: { + searchParams: { platform?: string; account?: string; intro?: string }; +}) { + if (searchParams.intro === 'true') { + return ( +
+
+

+ Build Web3 Reputation +
with Endorsements +

+

+ Endorse any Ethereum address, ENS or social account. +

+ +
+ +
+ } + > + + + } + /> + +
+
+
+ ); + } + + const platform = validateOrGetDefaultPlatform(searchParams.platform); -export default App; + return ( + +
+ } + > + + + } + /> +
+
+ ); +} diff --git a/packages/dapp/src/app/profile/[slug]/Badges.tsx b/packages/dapp/src/app/profile/[slug]/Badges.tsx new file mode 100644 index 0000000..fb9c3e9 --- /dev/null +++ b/packages/dapp/src/app/profile/[slug]/Badges.tsx @@ -0,0 +1,78 @@ +import type { GetProfileInfoQuery } from '@/__generated__/airstack/graphql'; +import { MemoizedSVG } from '@/components/MemoizedSVG'; +import { Skeleton } from '@/components/ui/skeleton'; +import { cn } from '@/lib/utils'; +import { PLATFORM_DATA, PlatformType } from '@/utils'; + +type BadgesProps = { + data: GetProfileInfoQuery; +}; + +const Badge = ({ + identity, + platform, +}: { identity: string; platform: PlatformType }) => { + const link = PLATFORM_DATA[platform].urlPrefix + identity; + return ( + + } + /> + {identity} + + ); +}; + +export const Badges = ({ + data: { Wallet, farcasterSocials, lensSocials }, +}: BadgesProps) => { + return ( +
+ {/* ENS */} + {Wallet?.primaryDomain?.name && ( + + )} + {/* Lens */} + {lensSocials?.Social?.map((item) => { + if (!item.profileHandle) return null; + + return ( + + ); + })} + {/* Farcaster */} + {farcasterSocials?.Social?.map((item) => { + if (!item.profileHandle) return null; + + return ( + + ); + })} +
+ ); +}; diff --git a/packages/dapp/src/app/profile/[slug]/Explorer.tsx b/packages/dapp/src/app/profile/[slug]/Explorer.tsx new file mode 100644 index 0000000..2d1740d --- /dev/null +++ b/packages/dapp/src/app/profile/[slug]/Explorer.tsx @@ -0,0 +1,14 @@ +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; + +export const Explorer = () => { + return ( +
+ + + Endorsement Explorer + + 🚧 Under construction 🚧 + +
+ ); +}; diff --git a/packages/dapp/src/app/profile/[slug]/Feed.tsx b/packages/dapp/src/app/profile/[slug]/Feed.tsx new file mode 100644 index 0000000..28faf3d --- /dev/null +++ b/packages/dapp/src/app/profile/[slug]/Feed.tsx @@ -0,0 +1,106 @@ +import Link from 'next/link'; +import type { PlatformType } from '@/utils'; +import { Summary } from './Summary'; +import { Explorer } from './Explorer'; +import { SocialGraph } from './SocialGraph'; +import { Skeleton } from '@/components/ui/skeleton'; +import { Suspense } from 'react'; + +const TABS = [ + { value: 'summary', label: 'Summary' }, + { value: 'explorer', label: 'Endorsement Explorer' }, + { value: 'graph', label: 'Social Graph' }, +] as const; + +type TabType = (typeof TABS)[number]['value']; + +const validateOrGetDefaultTab = (tab: string | undefined) => { + if (!tab) return 'summary'; + // Check if the tab is valid + const lowercaseTab = tab.toLowerCase(); + + if (TABS.some((item) => item.value === lowercaseTab)) { + return lowercaseTab as TabType; + } + + // If the tab is not valid, return the default tab + return 'summary'; +}; + +type FeedProps = { + account: `0x${string}`; + platform: PlatformType; + tab?: string; + network: number; +}; + +export const Feed = ({ account, platform, tab, network }: FeedProps) => { + const _tab = validateOrGetDefaultTab(tab); + + return ( +
+
+
+ + Summary + + + Endorsement Explorer 🚧 + + + Social Graph 🚧 + +
+
+ +
+ + +
+ } + > + {_tab === 'summary' && ( + + )} + {_tab === 'explorer' && } + {_tab === 'graph' && } + +
+
+ ); +}; + +export const FeedSkeleton = () => { + return ( +
+
+ + + +
+
+ +
+
+ ); +}; diff --git a/packages/dapp/src/app/profile/[slug]/PageSkeleton.tsx b/packages/dapp/src/app/profile/[slug]/PageSkeleton.tsx new file mode 100644 index 0000000..326a091 --- /dev/null +++ b/packages/dapp/src/app/profile/[slug]/PageSkeleton.tsx @@ -0,0 +1,30 @@ +import { Container } from '@/components/Container'; +import { Skeleton } from '@/components/ui/skeleton'; +import { FeedSkeleton } from './Feed'; +import { ProfileAvatarSkeleton } from '@/components/ProfileAvatar'; + +export const PageSkeleton = () => { + return ( + +
+
+
+ +
+ +
+
+ + +
+ + +
+
+
+ +
+
+
+ ); +}; diff --git a/packages/dapp/src/components/Profile/ShareDialog.tsx b/packages/dapp/src/app/profile/[slug]/ShareDialog.tsx similarity index 64% rename from packages/dapp/src/components/Profile/ShareDialog.tsx rename to packages/dapp/src/app/profile/[slug]/ShareDialog.tsx index 2c3b8eb..af9087f 100644 --- a/packages/dapp/src/components/Profile/ShareDialog.tsx +++ b/packages/dapp/src/app/profile/[slug]/ShareDialog.tsx @@ -1,34 +1,42 @@ +'use client'; + import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, - DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; -import { ArrowUpTrayIcon, ShareIcon } from '@heroicons/react/24/outline'; +import { ArrowUpTrayIcon } from '@heroicons/react/24/outline'; import Link from 'next/link'; import { TwitterIcon, TwitterShareButton } from 'react-share'; -import Image from 'next/image'; -import { ProfileAvatar } from './ProfileAvatar'; -import { Card } from '../ui/card'; +import { ProfileAvatar } from '@/components/ProfileAvatar'; +import { Card } from '@/components/ui/card'; +import { MemoizedImage } from '@/components/MemoizedImage'; type ShareDialogProps = { + avatar: string | null; + address: `0x${string}`; shareLink: string; - account: any; + displayName: string; }; -export function ShareDialog({ shareLink, account }: ShareDialogProps) { +export function ShareDialog({ + avatar, + address, + shareLink, + displayName, +}: ShareDialogProps) { return ( ); }} diff --git a/packages/dapp/src/components/Container/index.tsx b/packages/dapp/src/components/Container/index.tsx index ad07455..0db94c3 100644 --- a/packages/dapp/src/components/Container/index.tsx +++ b/packages/dapp/src/components/Container/index.tsx @@ -3,7 +3,7 @@ import { cn } from '@/lib/utils'; export function Container({ className, ...props }: any) { return (
); diff --git a/packages/dapp/src/components/CopyIcon/index.tsx b/packages/dapp/src/components/CopyIcon/index.tsx new file mode 100644 index 0000000..ea46ed0 --- /dev/null +++ b/packages/dapp/src/components/CopyIcon/index.tsx @@ -0,0 +1,36 @@ +'use client'; + +import { cn } from '@/lib/utils'; +import { DocumentDuplicateIcon } from '@heroicons/react/24/outline'; +import { Check } from 'lucide-react'; +import { useState } from 'react'; + +export const CopyIcon = ({ value }: { value: string }) => { + const [isCopied, setIsCopied] = useState(false); + + const handleCopy = () => { + setIsCopied(true); + navigator.clipboard.writeText(value); + setTimeout(() => { + setIsCopied(false); + }, 1000); + }; + + return ( + <> + + + + ); +}; diff --git a/packages/dapp/src/components/EndorseForm/Balance.tsx b/packages/dapp/src/components/EndorseForm/Balance.tsx index 1074f5b..97009d9 100644 --- a/packages/dapp/src/components/EndorseForm/Balance.tsx +++ b/packages/dapp/src/components/EndorseForm/Balance.tsx @@ -16,6 +16,9 @@ export const Balance = () => { const balance = useBalance({ address: account.address, chainId: account.chainId, + query: { + refetchInterval: 4000, + }, }); const balanceValue = useMemo(() => { diff --git a/packages/dapp/src/components/EndorseForm/CommentButton.tsx b/packages/dapp/src/components/EndorseForm/CommentButton.tsx index 03ae5a1..adbdb7e 100644 --- a/packages/dapp/src/components/EndorseForm/CommentButton.tsx +++ b/packages/dapp/src/components/EndorseForm/CommentButton.tsx @@ -12,7 +12,7 @@ export const CommentButton = ({ onMouseDown }: CommentButtonProps) => { className="bg-primary-50 hover:bg-primary-100 rounded-full flex gap-x-2" > -
Add Comment
+
Add comment
); }; diff --git a/packages/dapp/src/components/EndorseForm/CommentCard.tsx b/packages/dapp/src/components/EndorseForm/CommentCard.tsx index 2822e60..1e79672 100644 --- a/packages/dapp/src/components/EndorseForm/CommentCard.tsx +++ b/packages/dapp/src/components/EndorseForm/CommentCard.tsx @@ -18,7 +18,7 @@ export const CommentCard = ({ close }: CommentCardProps) => {
-
Add Comment
+
Add comment
); }; diff --git a/packages/dapp/src/components/EndorseForm/DonationCard.tsx b/packages/dapp/src/components/EndorseForm/DonationCard.tsx index 68ead99..852de10 100644 --- a/packages/dapp/src/components/EndorseForm/DonationCard.tsx +++ b/packages/dapp/src/components/EndorseForm/DonationCard.tsx @@ -1,6 +1,6 @@ -import { useMemo } from 'react'; +import React, { useMemo } from 'react'; import { useEndorsementStore } from '@/stores'; -import Image from 'next/image'; +import { MemoizedImage } from '@/components/MemoizedImage'; import { Select, SelectContent, @@ -48,7 +48,7 @@ export const DonationCard = ({ close }: DonationCardProps) => { d="M21 11.25v8.25a1.5 1.5 0 0 1-1.5 1.5H5.25a1.5 1.5 0 0 1-1.5-1.5v-8.25M12 4.875A2.625 2.625 0 1 0 9.375 7.5H12m0-2.625V7.5m0-2.625A2.625 2.625 0 1 1 14.625 7.5H12m0 0V21m-8.625-9.75h18c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125h-18c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z" /> -
Add Donation
+
Add tip
-
+
diff --git a/packages/dapp/src/components/EndorseForm/Endorsee.tsx b/packages/dapp/src/components/EndorseForm/Endorsee.tsx deleted file mode 100644 index 49fcdcb..0000000 --- a/packages/dapp/src/components/EndorseForm/Endorsee.tsx +++ /dev/null @@ -1,86 +0,0 @@ -'use client'; - -import { useEffect, useMemo } from 'react'; -import { EndorseeDialog } from './EndorseeDialog'; -import { useEndorsementStore } from '@/stores'; -import { EndorseeBadge } from './EndorseeBadge'; -import { Skeleton } from '@/components/ui/skeleton'; -import { useSearchParams } from 'next/navigation'; -import { useNameService } from '@/hooks'; -import { PlatformType } from '@/utils/platform'; - -export const Endorsee = () => { - const searchParams = useSearchParams(); - const intro = !!searchParams.get('intro'); - - // Global state - const { platform, displayValue, changeAddress } = useEndorsementStore( - (state) => ({ - platform: state.platform, - displayValue: state.displayValue, - changeAddress: state.changeAddress, - }) - ); - - // Hooks - const { data, error, isLoading } = useNameService({ - platform, - value: displayValue, - enabled: displayValue !== null && platform !== null && !intro, - }); - - const isValidAccount = useMemo(() => !!data?.address, [data]); - - useEffect(() => { - if (data?.address) { - changeAddress(data.address as `0x${string}`); - } - }, [data]); - - if (intro) { - return ( -
- -
- ); - } - - if (isLoading) { - return ( -
- -
- - -
-
- ); - } - - if (data && isValidAccount) { - return ( -
- -
- ); - } - - return ( -
- -
- {error?.message} -
-
- ); -}; diff --git a/packages/dapp/src/components/EndorseForm/EndorseeBadge.tsx b/packages/dapp/src/components/EndorseForm/EndorseeBadge.tsx deleted file mode 100644 index 0a95135..0000000 --- a/packages/dapp/src/components/EndorseForm/EndorseeBadge.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import Image from 'next/image'; -import { useMemo, useState } from 'react'; -import SVG from 'react-inlinesvg'; - -import { DocumentDuplicateIcon } from '@heroicons/react/24/outline'; -import { PLATFORM_DATA, PlatformType } from '@/utils/platform'; -import { cn } from '@/lib/utils'; -import { Skeleton } from '@/components/ui/skeleton'; - -type EndorseeBadgeProps = { - type: PlatformType; - value: string; - avatar: string | null; - address: string; -}; - -export const EndorseeBadge = ({ - type, - value, - avatar, - address, -}: EndorseeBadgeProps) => { - const [avatarLoading, setAvatarLoading] = useState(true); - - const Avatar = useMemo(() => { - if (!avatar) { - return ( -
- {value[0].toUpperCase()} -
- ); - } - - return ( -
- {address} setAvatarLoading(false)} - /> - -
- ); - }, [avatar, avatarLoading, value]); - - switch (type) { - case PlatformType.ethereum: { - return ( -
- {`${value.slice(0, 6)}...${value.slice(-4)}`} - -
- ); - } - case PlatformType.ens: - case PlatformType.lens: - case PlatformType.farcaster: { - return ( - <> -
- {Avatar} -
- -
-
-
-
{value}
-
- {`${address.slice(0, 6)}...${address.slice(-4)}`} - -
-
- - ); - } - default: - return <>; - } -}; diff --git a/packages/dapp/src/components/EndorseForm/EndorseeCard.tsx b/packages/dapp/src/components/EndorseForm/EndorseeCard.tsx index bddc8cf..c4e7e93 100644 --- a/packages/dapp/src/components/EndorseForm/EndorseeCard.tsx +++ b/packages/dapp/src/components/EndorseForm/EndorseeCard.tsx @@ -7,19 +7,32 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select'; -import { Endorsee } from './Endorsee'; import { useEndorsementStore } from '@/stores'; +import { useRouter } from 'next/navigation'; import { Button } from '@/components/ui/button'; -const ENDORSMENT_OPTIONS = [ - { value: 'web3', label: 'Web3Explorer' }, - { value: 'dev', label: 'Developer' }, - { value: 'art', label: 'Artist' }, - { value: 'content', label: 'Content Creator' }, - { value: 'trader', label: 'Trader' }, +const ENDORSEMENT_OPTIONS = [ + { value: 'Developer', label: 'Developer' }, + { value: 'Hacker', label: 'Hacker' }, + { value: 'Buidler', label: 'Buidler' }, + { value: 'Memer', label: 'Memer' }, + { value: 'Degen', label: 'Degen' }, + { value: 'Based energy 🔵', label: 'Based energy 🔵' }, + { value: 'Web3 explorer', label: 'Web3 explorer' }, + { value: 'Friend', label: 'Friend' }, + { value: 'Artist', label: 'Artist' }, + { value: 'Blogger', label: 'Blogger' }, + { value: 'Trader', label: 'Trader' }, ]; -export const EndorseeCard = () => { +type EndorseeCardProps = { + endorsee: React.ReactNode; +}; + +export const EndorseeCard = ({ endorsee }: EndorseeCardProps) => { + const router = useRouter(); + + // Global state const { address, endorsementType, changeEndorsementType, clear } = useEndorsementStore((state) => ({ address: state.address, @@ -36,7 +49,15 @@ export const EndorseeCard = () => {
)}
-
- +
+ {endorsee} +
- Suggested Accounts + Suggested accounts
{SUGGESTED_ACCOUNTS.map((account) => { return ( @@ -84,13 +87,16 @@ export function EndorseeDialog() { onMouseDown={() => { changePlatform(account.platform); changeDisplayValue(account.value); + router.push( + `/?platform=${account.platform}&account=${account.value}` + ); setOpen(false); }} variant="ghost" className="w-full justify-start" >
- { changePlatform(PlatformType.ethereum); changeDisplayValue(query); + router.push( + `/?platform=${PlatformType.ethereum}&account=${query}` + ); setOpen(false); }} variant="ghost" className="w-full justify-start" >
- { changePlatform(PlatformType.ens); changeDisplayValue(`${query}.eth`); + router.push( + `/?platform=${PlatformType.ens}&account=${query}.eth` + ); setOpen(false); }} variant="ghost" className="w-full justify-start" >
- { changePlatform(PlatformType.lens); changeDisplayValue(`${query}.lens`); + router.push( + `/?platform=${PlatformType.lens}&account=${query}.lens` + ); setOpen(false); }} variant="ghost" className="w-full justify-start" >
- { changePlatform(PlatformType.farcaster); changeDisplayValue(query); + router.push( + `/?platform=${PlatformType.farcaster}&account=${query}` + ); setOpen(false); }} variant="ghost" className="w-full justify-start" >
- { + const searchParams = useSearchParams(); + const account = searchParams.get('account'); + const platform = validateOrGetDefaultPlatform(searchParams.get('platform')); + + // Global state + const { changeDisplayValue, changePlatform, changeAddress } = + useEndorsementStore((state) => ({ + changeAddress: state.changeAddress, + changePlatform: state.changePlatform, + changeDisplayValue: state.changeDisplayValue, + })); + + // Reads search params and updates global store + useEffect(() => { + changeDisplayValue(account); + changePlatform(platform); + changeAddress(address); + }, [account, platform, address]); + + return null; +}; diff --git a/packages/dapp/src/components/Endorsee/index.tsx b/packages/dapp/src/components/Endorsee/index.tsx new file mode 100644 index 0000000..0bd1b03 --- /dev/null +++ b/packages/dapp/src/components/Endorsee/index.tsx @@ -0,0 +1,82 @@ +import { EndorseeDialog } from './EndorseeDialog'; +import { EndorseeBadge } from './EndorseeBadge'; +import { PlatformType } from '@/utils/platform'; +import { getMinimalProfileInfoByPlatform } from '@/lib/airstack'; +import { SearchParamsStateSync } from './SearchParamsStateSync'; +import { Skeleton } from '@/components/ui/skeleton'; +import { getMinimalProfileFromAddress } from '@/lib/airstack/getMinimalProfileFromAddress'; +import { ProfileAvatarSkeleton } from '@/components/ProfileAvatar'; + +type EndorseeProps = { + platform: PlatformType; + displayValue: string | null; + intro: boolean; +}; + +export const Endorsee = async ({ + platform, + displayValue, + intro, +}: EndorseeProps) => { + let address: `0x${string}` | null; + let avatar; + let error; + let displayName = displayValue; + + if (intro) { + address = '0x32b1172e786a31a65b46710cd946b2521e13ac96'; + avatar = + 'https://assets.airstack.xyz/v2/image/social/10/8GnKRP2z0DZmg1H4wesg4o9fmVVND1rhv9clPqF6y7sq7Dx5tYx7WfqYTbq3h4GtIJl8mNHSB7vBZyBkgRnAH8RZ3RK3pMKhg/liZlFLAwk2GndPk43U0vfTP/UBOqmmxBfJnOwWplobI3v1icOprrTz8fcWJ64YecoWETk1eLhwevNHdV450lUnYFBnqAvv2rB4wGXz7cACQh5X9kqcrLtceCiCf9ZQt8Cf184ePEE=/small.jpg'; + error = null; + } else { + const result = + platform === PlatformType.ethereum + ? await getMinimalProfileFromAddress(displayValue as `0x${string}`) + : await getMinimalProfileInfoByPlatform(platform, displayValue); + + displayName = result.displayName; + address = result.address; + avatar = result.avatar; + error = result.error; + } + + if (address) { + return ( + <> + + + + ); + } + + return ( +
+ + {error && ( +
+ {error} +
+ )} + +
+ ); +}; + +export const EndorseeSkeleton = () => { + return ( + <> +
+ +
+
+ + +
+ + ); +}; diff --git a/packages/dapp/src/components/EndorsementDashboard/UserBadge.tsx b/packages/dapp/src/components/EndorsementDashboard/UserBadge.tsx deleted file mode 100644 index 39e406a..0000000 --- a/packages/dapp/src/components/EndorsementDashboard/UserBadge.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { useNameService, useProfile } from '@/hooks'; -import React, { useMemo, useState } from 'react'; -import { ProfileAvatar } from '../Profile/ProfileAvatar'; -import { Card } from '../ui/card'; -import { useRouter } from 'next/navigation'; - -type UserBadgeProps = { - address: string; - endorsements: number; -}; - -export const UserBadge = ({ address, endorsements }: UserBadgeProps) => { - //TODO enable support for multiple platforms (optional platform) - const { data, error, isLoading } = useProfile({ - value: address, - enabled: true, - }); - - if (isLoading) { - return
; - } - - if (!data) { - return
; - } - - return ( - - ); -}; - -const LoadedUserBadge = ({ - address, - endorsements, - data, -}: { address: string; endorsements: number; data: any[] }) => { - const ens = useMemo(() => { - return data.find((item) => { - return item.platform === 'ens'; - }); - }, [data]); - - const secondary = useMemo(() => { - if (ens) return null; - return data[0]; - }, [ens, data]); - - const account = useMemo(() => { - if (!ens) return secondary; - return ens; - }, [ens, secondary]); - - const router = useRouter(); - - return ( -
-
- -
- { - router.push(`/profile/${account.address}`); - }} - > -
- {account.displayName} - - {endorsements} Endorsements - -
-
-
- ); -}; diff --git a/packages/dapp/src/components/HomepageView/index.tsx b/packages/dapp/src/components/HomepageView/index.tsx deleted file mode 100644 index 497683a..0000000 --- a/packages/dapp/src/components/HomepageView/index.tsx +++ /dev/null @@ -1,70 +0,0 @@ -'use client'; - -import { EndorseForm } from '@/components/EndorseForm'; -import { Container } from '@/components/Container'; -import { useRouter, useSearchParams } from 'next/navigation'; -import { Button } from '@/components/ui/button'; -import { useEndorsementStore } from '@/stores'; -import { PlatformType } from '@/utils/platform'; - -export const HomepageView = () => { - const router = useRouter(); - - const searchParams = useSearchParams(); - const intro = !!searchParams.get('intro'); - - const platform = searchParams.get('platform'); - const account = searchParams.get('account'); - - if (platform && account && platform in PlatformType) { - useEndorsementStore.setState({ - displayValue: account, - platform: PlatformType[platform as keyof typeof PlatformType], - }); - } - - const handleIntroClick = () => { - router.push('/'); - }; - - if (intro) { - return ( -
-
-

- Build Web3 Reputation -
with Endorsements -

-

- Endorse any address, ENS domain or social account. -

- -
- -
- -
-
-
- ); - } - - return ( - -
- -
-
- ); -}; diff --git a/packages/dapp/src/components/MemoizedImage/index.tsx b/packages/dapp/src/components/MemoizedImage/index.tsx new file mode 100644 index 0000000..89bfeab --- /dev/null +++ b/packages/dapp/src/components/MemoizedImage/index.tsx @@ -0,0 +1,4 @@ +import React from 'react'; +import Image, { type ImageProps } from 'next/image'; + +export const MemoizedImage: React.FC = React.memo(Image); diff --git a/packages/dapp/src/components/MemoizedSVG/index.tsx b/packages/dapp/src/components/MemoizedSVG/index.tsx new file mode 100644 index 0000000..5045d09 --- /dev/null +++ b/packages/dapp/src/components/MemoizedSVG/index.tsx @@ -0,0 +1,4 @@ +import React from 'react'; +import SVG, { type Props as SVGProps } from 'react-inlinesvg'; + +export const MemoizedSVG: React.FC = React.memo(SVG); diff --git a/packages/dapp/src/components/Navbar/ClaimNavigationLink.tsx b/packages/dapp/src/components/Navbar/ClaimNavigationLink.tsx index bc984a2..b4fc735 100644 --- a/packages/dapp/src/components/Navbar/ClaimNavigationLink.tsx +++ b/packages/dapp/src/components/Navbar/ClaimNavigationLink.tsx @@ -26,7 +26,7 @@ export const ClaimNavigationLink = () => { return ( { + // Hooks + const { address } = useAccount(); + // Local state const [query, setQuery] = useState(''); const [showDropdown, setShowDropdown] = useState(false); @@ -77,18 +81,22 @@ export const Searchbar = () => { )} >
- Suggested Accounts + Suggested accounts
{SUGGESTED_ACCOUNTS.map((account) => { return ( setShowDropdown(false)} - href={`/profile/${account.value}`} + onClick={() => { + setShowDropdown(false); + setModalOpen(false); + }} + prefetch={false} + href={`/profile/${account.value}?platform=${account.platform}`} className="w-full justify-start gap-x-2 hover:bg-gray-100 inline-flex items-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 h-9 px-4 py-2" >
- {
{isEthereumAddress ? ( setShowDropdown(false)} - href={`/profile/${query}`} + onClick={() => { + setShowDropdown(false); + setModalOpen(false); + }} + prefetch={false} + href={`/profile/${query}?platform=${PlatformType.ethereum}`} className="w-full justify-start gap-x-2 hover:bg-gray-100 inline-flex items-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 h-9 px-4 py-2" > - { Results
setShowDropdown(false)} - href={`/profile/${query}.eth`} + prefetch={false} + onClick={() => { + setShowDropdown(false); + setModalOpen(false); + }} + href={`/profile/${query}.eth?platform=${PlatformType.ens}`} className="w-full justify-start gap-x-2 hover:bg-gray-100 inline-flex items-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 h-9 px-4 py-2" > - { {query}.eth setShowDropdown(false)} - href={`/profile/${query}.lens`} + prefetch={false} + onClick={() => { + setShowDropdown(false); + setModalOpen(false); + }} + href={`/profile/${query}.lens?platform=${PlatformType.lens}`} className="w-full justify-start gap-x-2 hover:bg-gray-100 inline-flex items-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 h-9 px-4 py-2" > - { {query}.lens setShowDropdown(false)} - href={`/profile/${query}.farcaster`} + prefetch={false} + onClick={() => { + setShowDropdown(false); + setModalOpen(false); + }} + href={`/profile/${query}?platform=${PlatformType.farcaster}`} className="w-full justify-start gap-x-2 hover:bg-gray-100 inline-flex items-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 h-9 px-4 py-2" > - { }, [query]); return ( - <> +
- -
+ +
{
-
+
setShowDropdown(true)} />
@@ -212,7 +238,7 @@ export const Searchbar = () => {
- +
); }; diff --git a/packages/dapp/src/components/Navbar/index.tsx b/packages/dapp/src/components/Navbar/index.tsx index 5cf1d50..30fdab4 100644 --- a/packages/dapp/src/components/Navbar/index.tsx +++ b/packages/dapp/src/components/Navbar/index.tsx @@ -1,35 +1,44 @@ -import Image from 'next/image'; import { ConnectButton } from '@/components/ConnectButton'; import { Searchbar } from './Searchbar'; import { Nunito } from 'next/font/google'; import Link from 'next/link'; import { cn } from '@/lib/utils'; import { ClaimNavigationLink } from './ClaimNavigationLink'; +import { MemoizedImage } from '@/components/MemoizedImage'; const nunito = Nunito({ subsets: ['latin'] }); export const Navbar = () => { return ( -
+