Skip to content

Commit 2a4b5dc

Browse files
authored
[TOOL-3515] Handle token by index (#6344)
1 parent 4a9da8f commit 2a4b5dc

File tree

6 files changed

+66
-10
lines changed

6 files changed

+66
-10
lines changed

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ export const ContractNFTPage: React.FC<NftOverviewPageProps> = ({
4242
const isSetSharedMetadataSupported =
4343
ERC721Ext.isSetSharedMetadataSupported(functionSelectors);
4444

45+
const isTokenByIndexSupported =
46+
ERC721Ext.isTokenByIndexSupported(functionSelectors);
47+
4548
const canRenderNFTTable = (() => {
4649
if (isErc721) {
4750
return ERC721Ext.isGetNFTsSupported(functionSelectors);
@@ -101,7 +104,11 @@ export const ContractNFTPage: React.FC<NftOverviewPageProps> = ({
101104
</div>
102105
{canShowSupplyCards && <SupplyCards contract={contract} />}
103106
{canRenderNFTTable && (
104-
<NFTGetAllTable contract={contract} isErc721={isErc721} />
107+
<NFTGetAllTable
108+
contract={contract}
109+
isErc721={isErc721}
110+
tokenByIndex={isTokenByIndexSupported}
111+
/>
105112
)}
106113
</div>
107114
);

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/token-id.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export const TokenIdPage: React.FC<TokenIdPageProps> = ({
8585
contract,
8686
tokenId: BigInt(tokenId || 0),
8787
includeOwner: true,
88+
tokenByIndex: false,
8889
},
8990
);
9091

@@ -222,7 +223,11 @@ export const TokenIdPage: React.FC<TokenIdPageProps> = ({
222223
<GridItem colSpan={8}>
223224
<CopyTextButton
224225
textToCopy={nft.id?.toString()}
225-
textToShow={nft.id?.toString()}
226+
textToShow={
227+
nft.id?.toString().length > 8
228+
? `${nft.id.toString().slice(0, 4)}...${nft.id.toString().slice(-4)}`
229+
: nft.id?.toString()
230+
}
226231
tooltip="Token ID"
227232
copyIconPosition="right"
228233
/>

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/table.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,12 @@ import { useReadContract } from "thirdweb/react";
4545
interface ContractOverviewNFTGetAllProps {
4646
contract: ThirdwebContract;
4747
isErc721: boolean;
48+
tokenByIndex: boolean;
4849
}
4950
export const NFTGetAllTable: React.FC<ContractOverviewNFTGetAllProps> = ({
5051
contract,
5152
isErc721,
53+
tokenByIndex,
5254
}) => {
5355
// if it's not erc721, it's erc1155
5456
const isErc1155 = !isErc721;
@@ -59,7 +61,10 @@ export const NFTGetAllTable: React.FC<ContractOverviewNFTGetAllProps> = ({
5961
const cols: Column<NFT>[] = [
6062
{
6163
Header: "Token Id",
62-
accessor: (row) => row.id?.toString(),
64+
accessor: (row) =>
65+
row.id?.toString().length > 8
66+
? `${row.id.toString().slice(0, 4)}...${row.id.toString().slice(-4)}`
67+
: row.id?.toString(),
6368
Cell: (cell: CellProps<NFT, string>) => <p>{cell.value}</p>,
6469
},
6570
{
@@ -155,6 +160,7 @@ export const NFTGetAllTable: React.FC<ContractOverviewNFTGetAllProps> = ({
155160
start: queryParams.start,
156161
count: queryParams.count,
157162
includeOwners: true,
163+
tokenByIndex,
158164
},
159165
);
160166

packages/thirdweb/src/exports/extensions/erc721.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export {
1616
nextTokenIdToMint,
1717
isNextTokenIdToMintSupported,
1818
} from "../../extensions/erc721/__generated__/IERC721Enumerable/read/nextTokenIdToMint.js";
19+
export { isTokenByIndexSupported } from "../../extensions/erc721/__generated__/IERC721Enumerable/read/tokenByIndex.js";
1920
export {
2021
ownerOf,
2122
type OwnerOfParams,

packages/thirdweb/src/extensions/erc721/read/getNFT.ts

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
type TokenURIParams,
77
tokenURI,
88
} from "../__generated__/IERC721A/read/tokenURI.js";
9+
import { tokenByIndex } from "../__generated__/IERC721Enumerable/read/tokenByIndex.js";
910

1011
export { isTokenURISupported as isGetNFTSupported } from "../__generated__/IERC721A/read/tokenURI.js";
1112

@@ -19,6 +20,13 @@ export type GetNFTParams = Prettify<
1920
* Whether to include the owner of the NFT.
2021
*/
2122
includeOwner?: boolean;
23+
/**
24+
* Whether to check and fetch tokenID by index, in case of non-sequential IDs.
25+
*
26+
* It should be set to true if it's an ERC721Enumerable contract, and has `tokenByIndex` function.
27+
* In this case, the provided tokenId will be considered as token-index and actual tokenId will be fetched from the contract.
28+
*/
29+
tokenByIndex?: boolean;
2230
}
2331
>;
2432

@@ -35,28 +43,50 @@ export type GetNFTParams = Prettify<
3543
* tokenId: 1n,
3644
* });
3745
* ```
46+
*
47+
* * @example
48+
* ```ts
49+
* import { getNFT } from "thirdweb/extensions/erc721";
50+
*
51+
*
52+
* const nft = await getNFT({
53+
* contract,
54+
* tokenId: 1n,
55+
* tokenByIndex: true // use this flag if the contract supports `tokenByIndex` and the above tokenId should be treated as an index.
56+
* });
57+
* ```
3858
*/
3959
export async function getNFT(
4060
options: BaseTransactionOptions<GetNFTParams>,
4161
): Promise<NFT> {
62+
let tokenId = options.tokenId;
63+
if (options.tokenByIndex) {
64+
try {
65+
tokenId = await tokenByIndex({
66+
contract: options.contract,
67+
index: options.tokenId,
68+
});
69+
} catch {}
70+
}
71+
4272
const [uri, owner] = await Promise.all([
43-
tokenURI(options).catch(() => null),
73+
tokenURI({ contract: options.contract, tokenId }).catch(() => null),
4474
options.includeOwner
4575
? import("../__generated__/IERC721A/read/ownerOf.js")
46-
.then((m) => m.ownerOf(options))
76+
.then((m) => m.ownerOf({ contract: options.contract, tokenId }))
4777
.catch(() => null)
4878
: null,
4979
]);
5080

5181
if (!uri?.trim()) {
5282
return parseNFT(
5383
{
54-
id: options.tokenId,
84+
id: tokenId,
5585
type: "ERC721",
5686
uri: "",
5787
},
5888
{
59-
tokenId: options.tokenId,
89+
tokenId,
6090
tokenUri: "",
6191
type: "ERC721",
6292
owner,
@@ -67,15 +97,15 @@ export async function getNFT(
6797
return parseNFT(
6898
await fetchTokenMetadata({
6999
client: options.contract.client,
70-
tokenId: options.tokenId,
100+
tokenId,
71101
tokenUri: uri,
72102
}).catch(() => ({
73-
id: options.tokenId,
103+
id: tokenId,
74104
type: "ERC721",
75105
uri,
76106
})),
77107
{
78-
tokenId: options.tokenId,
108+
tokenId: tokenId,
79109
tokenUri: uri,
80110
type: "ERC721",
81111
owner,

packages/thirdweb/src/extensions/erc721/read/getNFTs.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ export type GetNFTsParams = {
3434
* @default false
3535
*/
3636
includeOwners?: boolean;
37+
/**
38+
* Whether to check and fetch tokenID by index, in case of non-sequential IDs.
39+
*
40+
* It should be set to true if it's an ERC721Enumerable contract, and has `tokenByIndex` function.
41+
* In this case, the provided tokenId will be considered as token-index and actual tokenId will be fetched from the contract.
42+
*/
43+
tokenByIndex?: boolean;
3744
};
3845

3946
/**

0 commit comments

Comments
 (0)