Skip to content

Commit 3ea6090

Browse files
[SDK] Use insight for erc721/getNFTs and erc721/getOwnedNFTs
1 parent e29f749 commit 3ea6090

File tree

25 files changed

+771
-173
lines changed

25 files changed

+771
-173
lines changed

.changeset/purple-bats-march.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 erc721/getNFTs and erc721/getOwnedNFTs

packages/thirdweb/src/event/actions/get-events.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import type {
55
ExtractAbiEventNames,
66
} from "abitype";
77
import { type Log, formatLog } from "viem";
8-
import { getChainServices } from "../../chains/utils.js";
98
import { resolveContractAbi } from "../../contract/actions/resolve-abi.js";
109
import type { ThirdwebContract } from "../../contract/contract.js";
1110
import { getContractEvents as getContractEventsInsight } from "../../insight/get-events.js";
@@ -197,7 +196,7 @@ export async function getContractEvents<
197196
),
198197
);
199198
} catch (e) {
200-
console.warn("Error fetching from insight", e);
199+
console.warn("Error fetching from insight, falling back to rpc", e);
201200
// fetch from rpc
202201
logs = await Promise.all(
203202
logsParams.map((ethLogParams) => eth_getLogs(rpcRequest, ethLogParams)),
@@ -225,17 +224,6 @@ async function getLogsFromInsight(options: {
225224
}): Promise<Log[]> {
226225
const { params, contract } = options;
227226

228-
const chainServices = await getChainServices(contract.chain);
229-
const insightEnabled = chainServices.some(
230-
(c) => c.service === "insight" && c.enabled,
231-
);
232-
233-
if (!insightEnabled) {
234-
throw new Error(
235-
`Insight is not available for chainId ${contract.chain.id}`,
236-
);
237-
}
238-
239227
const fromBlock =
240228
typeof params.fromBlock === "bigint" ? Number(params.fromBlock) : undefined;
241229

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ export async function getNFT(
5858
type: "ERC1155",
5959
owner: null,
6060
supply,
61+
tokenAddress: options.contract.address,
62+
chainId: options.contract.chain.id,
6163
},
6264
);
6365
}

packages/thirdweb/src/extensions/erc20/read/getBalance.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export type GetBalanceResult = {
2323
displayValue: string;
2424
symbol: string;
2525
name: string;
26+
tokenAddress: string;
27+
chainId: number;
2628
};
2729

2830
/**
@@ -48,5 +50,7 @@ export async function getBalance(
4850
...currencyMetadata,
4951
value: balanceWei,
5052
displayValue: toTokens(balanceWei, currencyMetadata.decimals),
53+
tokenAddress: options.contract.address,
54+
chainId: options.contract.chain.id,
5155
};
5256
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ export async function getNFT(
9090
tokenUri: "",
9191
type: "ERC721",
9292
owner,
93+
tokenAddress: options.contract.address,
94+
chainId: options.contract.chain.id,
9395
},
9496
);
9597
}
@@ -109,6 +111,8 @@ export async function getNFT(
109111
tokenUri: uri,
110112
type: "ERC721",
111113
owner,
114+
tokenAddress: options.contract.address,
115+
chainId: options.contract.chain.id,
112116
},
113117
);
114118
}

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

Lines changed: 218 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
import { getNFTs } from "./getNFTs.js";
77

88
describe.runIf(process.env.TW_SECRET_KEY)("erc721.getNFTs", () => {
9-
it("works for a contract with 0 indexed NFTs", async () => {
9+
it("works for a contract with indexer", async () => {
1010
const nfts = await getNFTs({
1111
contract: DOODLES_CONTRACT,
1212
count: 5,
@@ -16,6 +16,214 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc721.getNFTs", () => {
1616
expect(nfts).toMatchInlineSnapshot(`
1717
[
1818
{
19+
"chainId": 1,
20+
"id": 0n,
21+
"metadata": {
22+
"attributes": [
23+
{
24+
"trait_type": "face",
25+
"value": "mustache",
26+
},
27+
{
28+
"trait_type": "hair",
29+
"value": "purple long",
30+
},
31+
{
32+
"trait_type": "body",
33+
"value": "blue and yellow jacket",
34+
},
35+
{
36+
"trait_type": "background",
37+
"value": "green",
38+
},
39+
{
40+
"trait_type": "head",
41+
"value": "tan",
42+
},
43+
],
44+
"description": "A community-driven collectibles project featuring art by Burnt Toast. Doodles come in a joyful range of colors, traits and sizes with a collection size of 10,000. Each Doodle allows its owner to vote for experiences and activations paid for by the Doodles Community Treasury. Burnt Toast is the working alias for Scott Martin, a Canadian–based illustrator, designer, animator and muralist.",
45+
"image": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmUEfFfwAh4wyB5UfHCVPUxis4j4Q4kJXtm5x5p3g1fVUn",
46+
"image_url": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmUEfFfwAh4wyB5UfHCVPUxis4j4Q4kJXtm5x5p3g1fVUn",
47+
"name": "Doodle #0",
48+
"uri": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/0",
49+
},
50+
"owner": null,
51+
"tokenAddress": "0x8a90cab2b38dba80c64b7734e58ee1db38b8992e",
52+
"tokenURI": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/0",
53+
"type": "ERC721",
54+
},
55+
{
56+
"chainId": 1,
57+
"id": 1n,
58+
"metadata": {
59+
"attributes": [
60+
{
61+
"trait_type": "face",
62+
"value": "holographic beard",
63+
},
64+
{
65+
"trait_type": "hair",
66+
"value": "white bucket cap",
67+
},
68+
{
69+
"trait_type": "body",
70+
"value": "purple sweater with satchel",
71+
},
72+
{
73+
"trait_type": "background",
74+
"value": "grey",
75+
},
76+
{
77+
"trait_type": "head",
78+
"value": "gradient 2",
79+
},
80+
],
81+
"description": "A community-driven collectibles project featuring art by Burnt Toast. Doodles come in a joyful range of colors, traits and sizes with a collection size of 10,000. Each Doodle allows its owner to vote for experiences and activations paid for by the Doodles Community Treasury. Burnt Toast is the working alias for Scott Martin, a Canadian–based illustrator, designer, animator and muralist.",
82+
"image": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmTDxnzcvj2p3xBrKcGv1wxoyhAn2yzCQnZZ9LmFjReuH9",
83+
"image_url": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmTDxnzcvj2p3xBrKcGv1wxoyhAn2yzCQnZZ9LmFjReuH9",
84+
"name": "Doodle #1",
85+
"uri": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/1",
86+
},
87+
"owner": null,
88+
"tokenAddress": "0x8a90cab2b38dba80c64b7734e58ee1db38b8992e",
89+
"tokenURI": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/1",
90+
"type": "ERC721",
91+
},
92+
{
93+
"chainId": 1,
94+
"id": 2n,
95+
"metadata": {
96+
"attributes": [
97+
{
98+
"trait_type": "face",
99+
"value": "designer glasses",
100+
},
101+
{
102+
"trait_type": "hair",
103+
"value": "poopie",
104+
},
105+
{
106+
"trait_type": "body",
107+
"value": "blue fleece",
108+
},
109+
{
110+
"trait_type": "background",
111+
"value": "yellow",
112+
},
113+
{
114+
"trait_type": "head",
115+
"value": "purple",
116+
},
117+
],
118+
"description": "A community-driven collectibles project featuring art by Burnt Toast. Doodles come in a joyful range of colors, traits and sizes with a collection size of 10,000. Each Doodle allows its owner to vote for experiences and activations paid for by the Doodles Community Treasury. Burnt Toast is the working alias for Scott Martin, a Canadian–based illustrator, designer, animator and muralist.",
119+
"image": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmbvZ2hbF3nEq5r3ijMEiSGssAmJvtyFwiejTAGHv74LR5",
120+
"image_url": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmbvZ2hbF3nEq5r3ijMEiSGssAmJvtyFwiejTAGHv74LR5",
121+
"name": "Doodle #2",
122+
"uri": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/2",
123+
},
124+
"owner": null,
125+
"tokenAddress": "0x8a90cab2b38dba80c64b7734e58ee1db38b8992e",
126+
"tokenURI": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/2",
127+
"type": "ERC721",
128+
},
129+
{
130+
"chainId": 1,
131+
"id": 3n,
132+
"metadata": {
133+
"attributes": [
134+
{
135+
"trait_type": "face",
136+
"value": "designer glasses",
137+
},
138+
{
139+
"trait_type": "hair",
140+
"value": "holographic mohawk",
141+
},
142+
{
143+
"trait_type": "body",
144+
"value": "pink fleece",
145+
},
146+
{
147+
"trait_type": "background",
148+
"value": "gradient 1",
149+
},
150+
{
151+
"trait_type": "head",
152+
"value": "pale",
153+
},
154+
],
155+
"description": "A community-driven collectibles project featuring art by Burnt Toast. Doodles come in a joyful range of colors, traits and sizes with a collection size of 10,000. Each Doodle allows its owner to vote for experiences and activations paid for by the Doodles Community Treasury. Burnt Toast is the working alias for Scott Martin, a Canadian–based illustrator, designer, animator and muralist.",
156+
"image": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmVpwaCqLut3wqwB5KSQr2fGnbLuJt5e3LhNvzvcisewZB",
157+
"image_url": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmVpwaCqLut3wqwB5KSQr2fGnbLuJt5e3LhNvzvcisewZB",
158+
"name": "Doodle #3",
159+
"uri": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/3",
160+
},
161+
"owner": null,
162+
"tokenAddress": "0x8a90cab2b38dba80c64b7734e58ee1db38b8992e",
163+
"tokenURI": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/3",
164+
"type": "ERC721",
165+
},
166+
{
167+
"chainId": 1,
168+
"id": 4n,
169+
"metadata": {
170+
"attributes": [
171+
{
172+
"trait_type": "face",
173+
"value": "happy",
174+
},
175+
{
176+
"trait_type": "hair",
177+
"value": "purple long",
178+
},
179+
{
180+
"trait_type": "body",
181+
"value": "spotted hoodie",
182+
},
183+
{
184+
"trait_type": "background",
185+
"value": "gradient 2",
186+
},
187+
{
188+
"trait_type": "head",
189+
"value": "purple",
190+
},
191+
],
192+
"description": "A community-driven collectibles project featuring art by Burnt Toast. Doodles come in a joyful range of colors, traits and sizes with a collection size of 10,000. Each Doodle allows its owner to vote for experiences and activations paid for by the Doodles Community Treasury. Burnt Toast is the working alias for Scott Martin, a Canadian–based illustrator, designer, animator and muralist.",
193+
"image": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmcyuFVLbfBmSeQ9ynu4dk67r97nB1abEekotuVuRGWedm",
194+
"image_url": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmcyuFVLbfBmSeQ9ynu4dk67r97nB1abEekotuVuRGWedm",
195+
"name": "Doodle #4",
196+
"uri": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/4",
197+
},
198+
"owner": null,
199+
"tokenAddress": "0x8a90cab2b38dba80c64b7734e58ee1db38b8992e",
200+
"tokenURI": "https://be1be9a2cd5ad08670882cce25b4815f.ipfscdn.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/4",
201+
"type": "ERC721",
202+
},
203+
]
204+
`);
205+
});
206+
207+
it("should throw error if totalSupply and nextTokenIdToMint are not supported", async () => {
208+
await expect(
209+
getNFTs({ contract: UNISWAPV3_FACTORY_CONTRACT, useIndexer: false }),
210+
).rejects.toThrowError(
211+
"Contract requires either `nextTokenIdToMint` or `totalSupply` function available to determine the next token ID to mint",
212+
);
213+
});
214+
215+
it("works for a contract with 0 indexed NFTs using RPC", async () => {
216+
const nfts = await getNFTs({
217+
contract: DOODLES_CONTRACT,
218+
count: 5,
219+
useIndexer: false,
220+
});
221+
222+
expect(nfts.length).toBe(5);
223+
expect(nfts).toMatchInlineSnapshot(`
224+
[
225+
{
226+
"chainId": 1,
19227
"id": 0n,
20228
"metadata": {
21229
"attributes": [
@@ -45,10 +253,12 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc721.getNFTs", () => {
45253
"name": "Doodle #0",
46254
},
47255
"owner": null,
256+
"tokenAddress": "0x8a90cab2b38dba80c64b7734e58ee1db38b8992e",
48257
"tokenURI": "ipfs://QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/0",
49258
"type": "ERC721",
50259
},
51260
{
261+
"chainId": 1,
52262
"id": 1n,
53263
"metadata": {
54264
"attributes": [
@@ -78,10 +288,12 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc721.getNFTs", () => {
78288
"name": "Doodle #1",
79289
},
80290
"owner": null,
291+
"tokenAddress": "0x8a90cab2b38dba80c64b7734e58ee1db38b8992e",
81292
"tokenURI": "ipfs://QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/1",
82293
"type": "ERC721",
83294
},
84295
{
296+
"chainId": 1,
85297
"id": 2n,
86298
"metadata": {
87299
"attributes": [
@@ -111,10 +323,12 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc721.getNFTs", () => {
111323
"name": "Doodle #2",
112324
},
113325
"owner": null,
326+
"tokenAddress": "0x8a90cab2b38dba80c64b7734e58ee1db38b8992e",
114327
"tokenURI": "ipfs://QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/2",
115328
"type": "ERC721",
116329
},
117330
{
331+
"chainId": 1,
118332
"id": 3n,
119333
"metadata": {
120334
"attributes": [
@@ -144,10 +358,12 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc721.getNFTs", () => {
144358
"name": "Doodle #3",
145359
},
146360
"owner": null,
361+
"tokenAddress": "0x8a90cab2b38dba80c64b7734e58ee1db38b8992e",
147362
"tokenURI": "ipfs://QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/3",
148363
"type": "ERC721",
149364
},
150365
{
366+
"chainId": 1,
151367
"id": 4n,
152368
"metadata": {
153369
"attributes": [
@@ -177,22 +393,11 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc721.getNFTs", () => {
177393
"name": "Doodle #4",
178394
},
179395
"owner": null,
396+
"tokenAddress": "0x8a90cab2b38dba80c64b7734e58ee1db38b8992e",
180397
"tokenURI": "ipfs://QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/4",
181398
"type": "ERC721",
182399
},
183400
]
184401
`);
185402
});
186-
187-
it.todo("works for a contract with `1` indexed NFTs", async () => {
188-
// TODO find a contract that we can use that has "1 indexed" NFTs, then re-enable this test
189-
});
190-
191-
it("should throw error if totalSupply and nextTokenIdToMint are not supported", async () => {
192-
await expect(
193-
getNFTs({ contract: UNISWAPV3_FACTORY_CONTRACT }),
194-
).rejects.toThrowError(
195-
"Contract requires either `nextTokenIdToMint` or `totalSupply` function available to determine the next token ID to mint",
196-
);
197-
});
198403
});

0 commit comments

Comments
 (0)