Skip to content

Commit 4cf15a2

Browse files
[SDK] Use insight for 1155 getNFTs, getOwnedNFTs and getNFT (#6753)
Signed-off-by: Joaquim Verges <joaquim.verges@gmail.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
1 parent 62ce05e commit 4cf15a2

File tree

8 files changed

+552
-323
lines changed

8 files changed

+552
-323
lines changed

.changeset/huge-berries-call.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Use insight for 1155 getNFTs, getOwnedNFTs and getNFT

packages/thirdweb/src/extensions/erc1155/read/getNFT.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,21 @@ import { DROP1155_CONTRACT } from "~test/test-contracts.js";
44
import { getNFT } from "./getNFT.js";
55

66
describe.runIf(process.env.TW_SECRET_KEY)("erc1155.getNFT", () => {
7+
it("without owner with indexer", async () => {
8+
const nft = await getNFT({
9+
contract: DROP1155_CONTRACT,
10+
tokenId: 2n,
11+
});
12+
expect(nft.metadata.name).toBe("Aura Platinum");
13+
// biome-ignore lint/suspicious/noExplicitAny: todo type this better
14+
expect((nft as any).supply).toBe(2519n);
15+
});
16+
717
it("without owner", async () => {
818
const nft = await getNFT({
919
contract: DROP1155_CONTRACT,
1020
tokenId: 2n,
21+
useIndexer: false,
1122
});
1223
expect(nft).toMatchInlineSnapshot(`
1324
{

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

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
import { getNFT as getNFTInsight } from "../../../insight/get-nfts.js";
12
import type { BaseTransactionOptions } from "../../../transaction/types.js";
23
import { fetchTokenMetadata } from "../../../utils/nft/fetchTokenMetadata.js";
34
import { type NFT, parseNFT } from "../../../utils/nft/parseNft.js";
45
import { totalSupply } from "../__generated__/IERC1155/read/totalSupply.js";
56
import { uri } from "../__generated__/IERC1155/read/uri.js";
6-
77
export { isUriSupported as isGetNFTSupported } from "../__generated__/IERC1155/read/uri.js";
88

99
/**
@@ -12,6 +12,11 @@ export { isUriSupported as isGetNFTSupported } from "../__generated__/IERC1155/r
1212
*/
1313
export type GetNFTParams = {
1414
tokenId: bigint;
15+
/**
16+
* Whether to use the insight API to fetch the NFT.
17+
* @default true
18+
*/
19+
useIndexer?: boolean;
1520
};
1621

1722
/**
@@ -30,6 +35,51 @@ export type GetNFTParams = {
3035
*/
3136
export async function getNFT(
3237
options: BaseTransactionOptions<GetNFTParams>,
38+
): Promise<NFT> {
39+
const { useIndexer = true } = options;
40+
if (useIndexer) {
41+
try {
42+
return await getNFTFromInsight(options);
43+
} catch {
44+
return await getNFTFromRPC(options);
45+
}
46+
}
47+
return await getNFTFromRPC(options);
48+
}
49+
50+
async function getNFTFromInsight(
51+
options: BaseTransactionOptions<GetNFTParams>,
52+
): Promise<NFT> {
53+
const tokenId = options.tokenId;
54+
const nft = await getNFTInsight({
55+
client: options.contract.client,
56+
chain: options.contract.chain,
57+
contractAddress: options.contract.address,
58+
tokenId: options.tokenId,
59+
});
60+
if (!nft) {
61+
return parseNFT(
62+
{
63+
id: tokenId,
64+
type: "ERC1155",
65+
uri: "",
66+
},
67+
{
68+
tokenId: options.tokenId,
69+
tokenUri: "",
70+
type: "ERC1155",
71+
owner: null,
72+
supply: 0n,
73+
tokenAddress: options.contract.address,
74+
chainId: options.contract.chain.id,
75+
},
76+
);
77+
}
78+
return nft;
79+
}
80+
81+
async function getNFTFromRPC(
82+
options: BaseTransactionOptions<GetNFTParams>,
3383
): Promise<NFT> {
3484
const [tokenUri, supply] = await Promise.all([
3585
uri({

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { maxUint256 } from "ox/Solidity";
2+
import { getContractNFTs } from "../../../insight/get-nfts.js";
23
import type { BaseTransactionOptions } from "../../../transaction/types.js";
34
import { min } from "../../../utils/bigint.js";
45
import type { NFT } from "../../../utils/nft/parseNft.js";
@@ -23,6 +24,11 @@ export type GetNFTsParams = {
2324
* The number of NFTs to retrieve.
2425
*/
2526
count?: number;
27+
/**
28+
* Whether to use the insight API to fetch the NFTs.
29+
* @default true
30+
*/
31+
useIndexer?: boolean;
2632
};
2733

2834
/**
@@ -42,6 +48,38 @@ export type GetNFTsParams = {
4248
*/
4349
export async function getNFTs(
4450
options: BaseTransactionOptions<GetNFTsParams>,
51+
): Promise<NFT[]> {
52+
const { useIndexer = true } = options;
53+
if (useIndexer) {
54+
try {
55+
return await getNFTsFromInsight(options);
56+
} catch {
57+
return await getNFTsFromRPC(options);
58+
}
59+
}
60+
return await getNFTsFromRPC(options);
61+
}
62+
63+
async function getNFTsFromInsight(
64+
options: BaseTransactionOptions<GetNFTsParams>,
65+
): Promise<NFT[]> {
66+
const { contract, start, count = Number(DEFAULT_QUERY_ALL_COUNT) } = options;
67+
68+
const result = await getContractNFTs({
69+
client: contract.client,
70+
chains: [contract.chain],
71+
contractAddress: contract.address,
72+
queryOptions: {
73+
limit: count,
74+
page: start ? Math.floor(start / count) : undefined,
75+
},
76+
});
77+
78+
return result;
79+
}
80+
81+
async function getNFTsFromRPC(
82+
options: BaseTransactionOptions<GetNFTsParams>,
4583
): Promise<NFT[]> {
4684
const start = BigInt(options.start || 0);
4785
const count = BigInt(options.count || DEFAULT_QUERY_ALL_COUNT);

packages/thirdweb/src/extensions/erc1155/read/getOwnedNFTs.ts

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
1+
import { getOwnedNFTs as getInsightNFTs } from "../../../insight/get-nfts.js";
12
import type { BaseTransactionOptions } from "../../../transaction/types.js";
23
import type { NFT } from "../../../utils/nft/parseNft.js";
34
import { getNFT } from "./getNFT.js";
45
import {
56
type GetOwnedTokenIdsParams,
67
getOwnedTokenIds,
78
} from "./getOwnedTokenIds.js";
8-
99
/**
1010
* Parameters for retrieving NFTs.
1111
* @extension ERC1155
1212
*/
13-
export type GetOwnedNFTsParams = GetOwnedTokenIdsParams;
13+
export type GetOwnedNFTsParams = GetOwnedTokenIdsParams & {
14+
/**
15+
* Whether to use the insight API to fetch the NFTs.
16+
* @default true
17+
*/
18+
useIndexer?: boolean;
19+
};
1420

1521
/**
1622
* Retrieves the owned ERC1155 NFTs for a given wallet address.
@@ -30,6 +36,63 @@ export type GetOwnedNFTsParams = GetOwnedTokenIdsParams;
3036
*/
3137
export async function getOwnedNFTs(
3238
options: BaseTransactionOptions<GetOwnedNFTsParams>,
39+
): Promise<(NFT & { quantityOwned: bigint })[]> {
40+
const { useIndexer = true } = options;
41+
if (useIndexer) {
42+
try {
43+
return await getOwnedNFTsFromInsight(options);
44+
} catch {
45+
return await getOwnedNFTsFromRPC(options);
46+
}
47+
}
48+
return await getOwnedNFTsFromRPC(options);
49+
}
50+
51+
async function getOwnedNFTsFromInsight(
52+
options: BaseTransactionOptions<GetOwnedNFTsParams>,
53+
): Promise<(NFT & { quantityOwned: bigint })[]> {
54+
const limit = 50;
55+
const nfts: (NFT & { quantityOwned: bigint })[] = [];
56+
let page = 0;
57+
let hasMore = true;
58+
59+
// TODO (insight): add support for contract address filters
60+
while (hasMore) {
61+
const pageResults = await getInsightNFTs({
62+
client: options.contract.client,
63+
chains: [options.contract.chain],
64+
ownerAddress: options.address,
65+
queryOptions: {
66+
limit,
67+
page,
68+
},
69+
});
70+
71+
nfts.push(...pageResults);
72+
73+
// If we got fewer results than the limit, we've reached the end
74+
if (pageResults.length < limit) {
75+
hasMore = false;
76+
} else {
77+
page++;
78+
}
79+
}
80+
81+
const results = nfts;
82+
83+
return results
84+
.filter(
85+
(n) =>
86+
n.tokenAddress.toLowerCase() === options.contract.address.toLowerCase(),
87+
)
88+
.map((result) => ({
89+
...result,
90+
owner: options.address,
91+
}));
92+
}
93+
94+
async function getOwnedNFTsFromRPC(
95+
options: BaseTransactionOptions<GetOwnedNFTsParams>,
3396
): Promise<(NFT & { quantityOwned: bigint })[]> {
3497
const ownedBalances = await getOwnedTokenIds(options);
3598

0 commit comments

Comments
 (0)