Skip to content

Commit

Permalink
Remove old blocking nft queries (solana-labs#1810)
Browse files Browse the repository at this point in the history
  • Loading branch information
asktree authored Sep 6, 2023
1 parent 5651a40 commit 63a2d0a
Show file tree
Hide file tree
Showing 18 changed files with 161 additions and 574 deletions.
263 changes: 75 additions & 188 deletions components/NFTVotePluginSettingsDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,218 +1,105 @@
import { PublicKey } from '@solana/web3.js'
import type BN from 'bn.js'
import { useEffect, useState } from 'react'
import { pipe } from 'fp-ts/lib/function'
import cx from 'classnames'
// import ChevronRightIcon from '@carbon/icons-react/lib/ChevronRight'

import useVotePluginsClientStore from 'stores/useVotePluginsClientStore'
import { ConnectionContext } from '@utils/connection'
import BigNumber from 'bignumber.js'
import * as RE from '@utils/uiTypes/Result'
import NFTIcon from '@components/treasuryV2/icons/NFTCollectionPreviewIcon'
import { tryGetMint, getNFTsByCollection } from '@utils/tokens'
import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext'
import { useConnection } from '@solana/wallet-adapter-react'
import { useAsync } from 'react-async-hook'
import { fetchDigitalAssetById } from '@hooks/queries/digitalAssets'
import { getNetworkFromEndpoint } from '@utils/connection'
import { useMintInfoByPubkeyQuery } from '@hooks/queries/mintInfo'
import BigNumber from 'bignumber.js'

interface CollectionConfig {
collection: PublicKey
size: number
weight: BN
}

async function fetchCollection(
address: PublicKey,
count: number,
connection: ConnectionContext
) {
const nfts = await getNFTsByCollection(
address,
connection.cluster === 'devnet'
)
const collectionName = nfts[0]?.collection.name

return {
name: collectionName,
nfts: nfts
.map((nft) => ({
name: nft.name,
owner: nft.owner,
}))
.sort((a, b) => {
return a.name
.toLocaleLowerCase()
.localeCompare(b.name.toLocaleLowerCase())
}),
} as {
name: string
nfts: {
name: string
owner: null | PublicKey
}[]
}
}

async function fetchCollections(
configs: CollectionConfig[],
connection: ConnectionContext,
mintPublicKey?: null | PublicKey
) {
const collections = await Promise.all(
configs.map((config) =>
fetchCollection(config.collection, config.size, connection).then(
(details) => ({
name: details.name,
nfts: details.nfts,
numNFTs: config.size,
publicKey: config.collection,
voteWeight: new BigNumber(config.weight.toString()),
})
)
)
)

const mint = mintPublicKey
? await tryGetMint(connection.current, mintPublicKey)
: undefined

return { collections, mint }
}

type Data = Awaited<ReturnType<typeof fetchCollections>>
// type Collections = Data['collections']
// type NFTs = Collections[number]['nfts']

// function NFTList(props: { className?: string; nfts: NFTs }) {
// const [expanded, setExpanded] = useState(false)

// return (
// <div className={props.className}>
// <button
// className="flex items-center text-xs text-primary-light"
// onClick={() => setExpanded((cur) => !cur)}
// >
// <div>{expanded ? 'Hide' : 'View'} NFTs</div>
// <ChevronRightIcon
// className={cx(
// 'h-4',
// 'w-4',
// 'fill-current',
// 'transition-transform',
// expanded && 'rotate-90'
// )}
// />
// </button>
// {expanded && (
// <div className="mt-2">
// <div className="grid grid-cols-[25%,1fr] text-white/50 text-xs gap-1">
// <div>Name</div>
// <div>Owner</div>
// </div>
// <div className="grid grid-cols-[25%,1fr] text-sm text-fgd-1 gap-1 mt-1 max-h-96 overflow-y-auto">
// {props.nfts.map((nft, i) => (
// <React.Fragment key={i}>
// <div className="truncate">{nft.name}</div>
// <div className="truncate">
// {nft.owner ? nft.owner.toBase58() : ''}
// </div>
// </React.Fragment>
// ))}
// </div>
// </div>
// )}
// </div>
// )
// }

interface Props {
className?: string
}

export function NFTVotePluginSettingsDisplay(props: Props) {
const connection = useLegacyConnectionContext()
const { connection } = useConnection()
const registrar = useVotePluginsClientStore((s) => s.state.nftMintRegistrar)
const [collections, setCollections] = useState<RE.Result<Data>>(RE.pending())

const collectionConfigs = (registrar?.collectionConfigs ||
[]) as CollectionConfig[]

useEffect(() => {
setCollections(RE.pending())
fetchCollections(
collectionConfigs,
connection,
registrar?.governingTokenMint
)
.then((collections) => {
setCollections(RE.ok(collections))
const { result: configsWithNames } = useAsync(async () => {
const collectionConfigs = (registrar?.collectionConfigs ||
[]) as CollectionConfig[]
const network = getNetworkFromEndpoint(connection.rpcEndpoint)
if (network === 'localnet') throw new Error()

return Promise.all(
collectionConfigs.map(async (collectionConfig) => {
const collectionNft = await fetchDigitalAssetById(
network,
collectionConfig.collection
)
const name = collectionNft?.result?.content.metadata.name
return { name: name ?? 'Unknown Collection', ...collectionConfig }
})
.catch((error: any) => setCollections(RE.failed(error)))
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
// eslint-disable-next-line react-hooks/exhaustive-deps
collectionConfigs.map(({ collection }) => collection.toBase58()).join('-'),
])

if (!collectionConfigs.length) {
return null
}

return pipe(
collections,
RE.match(
() => <div className={props.className} />,
() => (
<div className={props.className}>
<div className="text-xl text-fgd-1 font-bold flex items-center space-x-2">
<NFTIcon className="h-5 w-5 stroke-current" />{' '}
<span>NFT Voting Configuration</span>
</div>
<div className="rounded bg-bkg-2 px-6 py-4 mt-4 h-[140px] animate-pulse" />
</div>
),
({ collections, mint }) => (
<div className={props.className}>
<div className="text-xl text-fgd-1 font-bold flex items-center space-x-2">
<NFTIcon className="h-5 w-5 stroke-current" />{' '}
<span>NFT Voting Configuration</span>
</div>
{collections.map((collection, i) => (
<div className="rounded bg-bkg-2 px-6 py-4 mt-4" key={i}>
<div className="grid grid-cols-[max-content,1fr] items-start gap-x-4">
<div className="text-2xl text-fgd-1 font-bold">{i + 1}.</div>
<div>
<div className="text-2xl text-fgd-2 font-semibold">
{collection.name}
</div>
<div className="text-xs text-white/50">
{collection.publicKey.toBase58()}
</div>
<div
className={cx(
'gap-x-4',
'gap-y-1',
'grid-cols-[max-content,max-content]',
'grid',
'mt-4',
'text-fgd-2',
'text-sm'
)}
>
<div className="text-white/50"># NFTs in Collection:</div>
<div>{collection.numNFTs}</div>
)
}, [connection.rpcEndpoint, registrar?.collectionConfigs])

const governingMint = useMintInfoByPubkeyQuery(registrar?.governingTokenMint)
.data?.result

return configsWithNames === undefined ? (
<div className={props.className}>
<div className="text-xl text-fgd-1 font-bold flex items-center space-x-2">
<NFTIcon className="h-5 w-5 stroke-current" />{' '}
<span>NFT Voting Configuration</span>
</div>
<div className="rounded bg-bkg-2 px-6 py-4 mt-4 h-[140px] animate-pulse" />
</div>
) : (
<div className={props.className}>
<div className="text-xl text-fgd-1 font-bold flex items-center space-x-2">
<NFTIcon className="h-5 w-5 stroke-current" />{' '}
<span>NFT Voting Configuration</span>
</div>
{configsWithNames.map((collection, i) => (
<div className="rounded bg-bkg-2 px-6 py-4 mt-4" key={i}>
<div className="grid grid-cols-[max-content,1fr] items-start gap-x-4">
<div className="text-lg text-fgd-1 font-bold">{i + 1}.</div>
<div>
<div className="text-lg text-fgd-2 font-semibold">
{collection.name}
</div>
<div className="text-xs text-white/50">
{collection.collection.toBase58()}
</div>
<div
className={cx(
'gap-x-4',
'gap-y-1',
'grid-cols-[max-content,max-content]',
'grid',
'mt-4',
'text-fgd-2',
'text-sm'
)}
>
<div className="text-white/50"># NFTs in Collection:</div>
<div>{collection.size}</div>
{governingMint && (
<>
<div className="text-white/50">Vote Weight per NFT:</div>
<div>
{collection.voteWeight
.shiftedBy(mint ? -mint.account.decimals : 0)
{new BigNumber(collection.weight.toString())
.shiftedBy(-governingMint.decimals)
.toFormat()}
</div>
</div>
{/* <NFTList className="mt-4" nfts={collection.nfts} /> */}
</div>
</>
)}
</div>
{/* <NFTList className="mt-4" nfts={collection.nfts} /> */}
</div>
))}
</div>
</div>
)
)
))}
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export default function AuxiliaryWalletListItem(props: Props) {
<AssetsPreviewIconList
assets={props.wallet.assets}
className="pl-5 mt-1"
governance={undefined}
/>
</div>
<ChevronDownIcon
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@ import { useMemo } from 'react'
import Collapsible from './Collapsible'
import NFTCollectionPreviewIcon from '../../../icons/NFTCollectionPreviewIcon'
import NFTListItem from './NFTListItem'
import useTreasuryAddressForGovernance from '@hooks/useTreasuryAddressForGovernance'
import {
DasNftObject,
useDigitalAssetsByOwner,
} from '@hooks/queries/digitalAssets'
import { PublicKey } from '@solana/web3.js'
import { SUPPORT_CNFTS } from '@constants/flags'
import cx from '@hub/lib/cx'
import useGovernanceNfts from './useGovernanceNfts'

interface Props {
className?: string
Expand All @@ -25,19 +20,7 @@ function onlyUnique(value, index, array) {
}

export default function NFTList({ governance, ...props }: Props) {
const { result: treasury } = useTreasuryAddressForGovernance(governance)
const { data: governanceNfts } = useDigitalAssetsByOwner(governance)
const { data: treasuryNfts } = useDigitalAssetsByOwner(treasury)

const nfts = useMemo(
() =>
governanceNfts && treasuryNfts
? ([...governanceNfts, ...treasuryNfts] as DasNftObject[])
.flat()
.filter((x) => SUPPORT_CNFTS || !x.compression.compressed)
: undefined,
[governanceNfts, treasuryNfts]
)
const nfts = useGovernanceNfts(governance)

const collectionIds = useMemo(
() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ export default function AssetList(props: Props) {

return (
<div className={cx(props.className, 'relative', 'space-y-6')}>
{props.assets.length === 0 && (
{props.assets.length === 0 && (nfts?.length ?? 0) === 0 && (
<div className="p-4 text-center text-sm text-fgd-1">
This wallet contains no assets
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { SUPPORT_CNFTS } from '@constants/flags'
import {
DasNftObject,
useDigitalAssetsByOwner,
} from '@hooks/queries/digitalAssets'
import useTreasuryAddressForGovernance from '@hooks/useTreasuryAddressForGovernance'
import { PublicKey } from '@solana/web3.js'
import { useMemo } from 'react'

const useGovernanceNfts = (governance: PublicKey | undefined) => {
const { result: treasury } = useTreasuryAddressForGovernance(governance)
const { data: governanceNfts } = useDigitalAssetsByOwner(governance)
const { data: treasuryNfts } = useDigitalAssetsByOwner(treasury)

const nfts = useMemo(
() =>
governanceNfts && treasuryNfts
? ([...governanceNfts, ...treasuryNfts] as DasNftObject[])
.flat()
.filter((x) => SUPPORT_CNFTS || !x.compression.compressed)
: undefined,
[governanceNfts, treasuryNfts]
)

return nfts
}

export default useGovernanceNfts
Loading

0 comments on commit 63a2d0a

Please sign in to comment.