Skip to content

Commit

Permalink
migrate from n.xyz to sequencer
Browse files Browse the repository at this point in the history
  • Loading branch information
jfschwarz committed Sep 1, 2023
1 parent 5186a9c commit 9fe7e05
Show file tree
Hide file tree
Showing 15 changed files with 449 additions and 407 deletions.
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "1.0.0",
"private": true,
"devDependencies": {
"0xsequence": "^1.1.15",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@walletconnect/client": "^1.8.0",
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/chains.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { SequenceIndexerServices } from "@0xsequence/indexer"
import {
mainnet,
goerli,
Expand All @@ -23,3 +24,11 @@ export const CHAINS = {
export type ChainId = keyof typeof CHAINS

export const DEFAULT_CHAIN = CHAINS[5]

export const SEQUENCER_ENDPOINTS: Record<ChainId, SequenceIndexerServices> = {
1: SequenceIndexerServices.MAINNET,
5: SequenceIndexerServices.GOERLI,
100: SequenceIndexerServices.GNOSIS,
137: SequenceIndexerServices.POLYGON,
80001: SequenceIndexerServices.POLYGON_MUMBAI,
}
64 changes: 16 additions & 48 deletions frontend/src/components/NFTGrid/index.tsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,43 @@
import { useEffect, useState } from "react"

import useNFTsByOwner, { MechNFT } from "../../hooks/useNFTsByOwner"
import { ContractType, TokenBalance } from "@0xsequence/indexer"
import NFTGridItem from "../NFTGridItem"
import Spinner from "../Spinner"
import Button from "../Button"

import classes from "./NFTGrid.module.css"
import clsx from "clsx"
import { useChainId } from "wagmi"
import { useDeployedMechs } from "../../hooks/useDeployMech"
import { calculateMechAddress } from "../../utils/calculateMechAddress"
import useTokenBalances from "../../hooks/useTokenBalances"

interface Props {
address: string
}

const NFTGrid: React.FC<Props> = ({ address }) => {
const [pageToken, setPageToken] = useState<string | undefined>(undefined)

const chainId = useChainId()

const { data, isLoading } = useNFTsByOwner({
walletAddress: address,
const { balances, isLoading } = useTokenBalances({
accountAddress: address,
chainId,
pageToken,
})

const [nftData, setNftData] = useState<MechNFT[]>([])

useEffect(() => {
setNftData((nftData) => {
if (nftData.length === 0) {
return data?.assets || []
}
const ids = new Set(
nftData.map((nft) => nft.nft.tokenID + nft.contractAddress)
)

// merge and dedupe
return [
...nftData,
...data?.assets.filter(
(nft) => !ids.has(nft.nft.tokenID + nft.contractAddress)
),
]
})
}, [data])
const nftBalances = balances.filter(
(balance) =>
balance.contractType === ContractType.ERC721 ||
balance.contractType === ContractType.ERC1155
)

const deployedMechs = useDeployedMechs(nftData)
const deployedMechs = useDeployedMechs(nftBalances)

const isDeployed = (nft: MechNFT) =>
const isDeployed = (nft: TokenBalance) =>
deployedMechs.some(
(mech) =>
mech.chainId === chainId &&
mech.address.toLowerCase() === calculateMechAddress(nft).toLowerCase()
)

const deployed = nftData.filter(isDeployed)
const undeployed = nftData.filter((nft) => !isDeployed(nft))
const deployed = nftBalances.filter(isDeployed)
const undeployed = nftBalances.filter((nft) => !isDeployed(nft))

return (
<div className={classes.container}>
Expand All @@ -75,7 +55,7 @@ const NFTGrid: React.FC<Props> = ({ address }) => {
<ul className={classes.grid}>
{deployed.map((nft, index) => (
<li key={`${index}-${nft.contractAddress}`}>
<NFTGridItem nftData={nft} />
<NFTGridItem tokenBalance={nft} />
</li>
))}
</ul>
Expand All @@ -89,24 +69,12 @@ const NFTGrid: React.FC<Props> = ({ address }) => {
<ul className={classes.grid}>
{undeployed.map((nft, index) => (
<li key={`${index}-${nft.contractAddress}`}>
<NFTGridItem nftData={nft} />
<NFTGridItem tokenBalance={nft} />
</li>
))}
</ul>
)}
{isLoading ? (
<Spinner />
) : (
<Button
onClick={() => {
console.log("set page token")
setPageToken(data?.nextPageToken)
}}
secondary
>
Load more
</Button>
)}
{isLoading && <Spinner />}
</div>
)
}
Expand Down
33 changes: 18 additions & 15 deletions frontend/src/components/NFTGridItem/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TokenBalance } from "@0xsequence/indexer"
import { useState } from "react"
import copy from "copy-to-clipboard"
import clsx from "clsx"
Expand All @@ -7,47 +8,49 @@ import classes from "./NFTItem.module.css"
import Button from "../Button"
import { shortenAddress } from "../../utils/shortenAddress"
import Spinner from "../Spinner"
import { MechNFT } from "../../hooks/useNFTsByOwner"
import ChainIcon from "../ChainIcon"
import { calculateMechAddress } from "../../utils/calculateMechAddress"
import { CHAINS, ChainId } from "../../chains"
import { useDeployMech } from "../../hooks/useDeployMech"

interface Props {
nftData: MechNFT
tokenBalance: TokenBalance
}

const NFTGridItem: React.FC<Props> = ({ nftData }) => {
const NFTGridItem: React.FC<Props> = ({ tokenBalance }) => {
const [imageError, setImageError] = useState(false)

const chain = CHAINS[parseInt(nftData.blockchain.shortChainID) as ChainId]
const chain = CHAINS[tokenBalance.chainId as ChainId]

const mechAddress = calculateMechAddress(nftData)
const { deploy, deployPending, deployed } = useDeployMech(nftData)
const mechAddress = calculateMechAddress(tokenBalance)
const { deploy, deployPending, deployed } = useDeployMech(tokenBalance)

const name =
tokenBalance.tokenMetadata?.name || tokenBalance.contractInfo?.name

return (
<div className={classes.itemContainer}>
<div className={classes.header}>
<p className={classes.tokenName}>
<Link
to={`mechs/${chain.prefix}:${nftData.contractAddress}/${nftData.nft.tokenID}`}
to={`mechs/${chain.prefix}:${tokenBalance.contractAddress}/${tokenBalance.tokenID}`}
>
{nftData.nft.title || nftData.nft.contractTitle || "..."}
{name || "..."}
</Link>
</p>
{nftData.nft.tokenID.length < 5 && (
<p className={classes.tokenId}>{nftData.nft.tokenID || "..."}</p>
{tokenBalance.tokenID.length < 5 && (
<p className={classes.tokenId}>{tokenBalance.tokenID || "..."}</p>
)}
</div>
<div className={classes.main}>
{(!nftData.nft.previews || imageError) && (
{(imageError || !tokenBalance.tokenMetadata?.image) && (
<div className={classes.noImage}></div>
)}
{!imageError && nftData.nft.previews && (
{!imageError && tokenBalance.tokenMetadata?.image && (
<div className={classes.imageContainer}>
<img
src={nftData.nft.previews[0].URI}
alt={nftData.nft.contractTitle}
src={tokenBalance.tokenMetadata?.image}
alt={name}
className={classes.image}
onError={() => setImageError(true)}
/>
Expand All @@ -68,7 +71,7 @@ const NFTGridItem: React.FC<Props> = ({ nftData }) => {
</div>
{deployed ? (
<Link
to={`mechs/${chain.prefix}:${nftData.contractAddress}/${nftData.nft.tokenID}`}
to={`mechs/${chain.prefix}:${tokenBalance.contractAddress}/${tokenBalance.tokenID}`}
>
<Button className={classes.useButton} onClick={() => {}}>
Use Mech
Expand Down
97 changes: 47 additions & 50 deletions frontend/src/components/NFTItem/index.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,57 @@
import { TokenBalance } from "@0xsequence/indexer"
import classes from "./NFTItem.module.css"
import { useState } from "react"
import { shortenAddress } from "../../utils/shortenAddress"
import copy from "copy-to-clipboard"
import clsx from "clsx"

import useAccountBalance from "../../hooks/useAccountBalance"
import useTokenBalances from "../../hooks/useTokenBalances"
import Spinner from "../Spinner"
import { useDeployMech } from "../../hooks/useDeployMech"

import { MechNFT } from "../../hooks/useNFTsByOwner"
import { calculateMechAddress } from "../../utils/calculateMechAddress"
import { formatUnits } from "viem"

interface Props {
nftData: MechNFT
tokenBalance: TokenBalance
}

const NFTItem: React.FC<Props> = ({ nftData }) => {
const mechAddress = calculateMechAddress(nftData)

const operatorAddress = nftData.nft.owner?.address as string | undefined
const operatorLabel =
operatorAddress &&
((nftData.nft.owner?.ens && nftData.nft.owner?.ens[0]?.name) ||
shortenAddress(operatorAddress))
const NFTItem: React.FC<Props> = ({ tokenBalance }) => {
const mechAddress = calculateMechAddress(tokenBalance)
const operatorAddress = tokenBalance.accountAddress

const [imageError, setImageError] = useState(false)

const {
isLoading: assetsLoading,
data: assetsData,
error: assetsError,
} = useAccountBalance({
address: mechAddress,
chainId: parseInt(nftData.blockchain.shortChainID),
balances: mechBalances,
isLoading: mechBalancesLoading,
error: mechBalancesError,
} = useTokenBalances({
accountAddress: mechAddress,
chainId: tokenBalance.chainId,
})

const { deployed } = useDeployMech(nftData)

const { deployed } = useDeployMech(tokenBalance)
const name =
tokenBalance.tokenMetadata?.name || tokenBalance.contractInfo?.name || "..."
return (
<div className={classes.itemContainer}>
<div className={classes.header}>
<p className={classes.tokenName}>
{nftData.nft.title || nftData.nft.contractTitle || "..."}
</p>
<p className={classes.tokenName}>{name}</p>

<p className={classes.tokenId} title={nftData.nft.tokenID}>
{nftData.nft.tokenID}
<p className={classes.tokenId} title={tokenBalance.tokenID}>
{tokenBalance.tokenID}
</p>
</div>
<div className={classes.main}>
{(imageError || !nftData.nft.previews) && (
{(imageError || !tokenBalance.tokenMetadata?.image) && (
<div className={classes.noImage}></div>
)}
{!imageError && nftData.nft.previews && (
{!imageError && tokenBalance.tokenMetadata?.image && (
<div className={classes.imageContainer}>
<img
src={nftData.nft.previews[0].URI}
alt={nftData.nft.contractTitle}
src={tokenBalance.tokenMetadata?.image}
alt={name}
className={classes.image}
onError={() => setImageError(true)}
/>
Expand Down Expand Up @@ -98,45 +93,47 @@ const NFTItem: React.FC<Props> = ({ nftData }) => {
title={operatorAddress}
>
<div className={classes.ellipsis}>
{operatorAddress ? operatorLabel : "\u2014"}
{operatorAddress ? shortenAddress(operatorAddress) : "\u2014"}
</div>
</div>
</li>
<li>
{/* <li>
<label>Balance</label>
<div className={clsx(classes.infoItem)}>
{assetsError || !assetsData
? "n/a"
: `$ ${assetsData.totalBalanceUSD}`}
</div>
</li>
</li> */}
</ul>
</div>
<label>Assets</label>
<div
className={clsx(
classes.assetsContainer,
assetsData && assetsData.assets.length === 0 && classes.empty
mechBalances.length === 0 && classes.empty
)}
>
{assetsError && <p>Failed to load assets</p>}
{assetsLoading && <Spinner />}
{assetsData && (
<>
{assetsData.assets.length === 0 && <p>No assets found</p>}
<ul className={classes.assetList}>
{assetsData.assets.map((asset, index) => (
<li key={index} className={classes.asset}>
<div className={classes.name}>{asset.name}</div>
<div className={classes.value}>
<p>{asset.pretty}</p>
<p>{asset.symbol}</p>
</div>
</li>
))}
</ul>
</>
)}
{mechBalancesError && <p>Failed to load assets</p>}
{mechBalancesLoading && <Spinner />}

{mechBalances.length === 0 && <p>No assets found</p>}
<ul className={classes.assetList}>
{mechBalances.map((balance, index) => (
<li key={index} className={classes.asset}>
<div className={classes.name}>{balance.contractInfo?.name}</div>
<div className={classes.value}>
<p>
{formatUnits(
BigInt(balance.balance),
balance.contractInfo?.decimals || 0
)}
</p>
<p>{balance.contractInfo?.symbol}</p>
</div>
</li>
))}
</ul>
</div>
</div>
)
Expand Down
Loading

0 comments on commit 9fe7e05

Please sign in to comment.