From e1c2681f6d5f5c6f5916ac13c563be9d261c47b9 Mon Sep 17 00:00:00 2001 From: Kien Ngo Date: Mon, 2 Oct 2023 13:26:12 -0400 Subject: [PATCH 01/11] Add pagination to getOwned for ERC721 --- .../evm/core/classes/erc-721-enumerable.ts | 18 ++++++++++-- .../src/evm/core/classes/erc-721-standard.ts | 8 ++++-- packages/sdk/src/evm/core/classes/erc-721.ts | 28 ++++++++++++++----- .../evm/core/classes/erc-721a-queryable.ts | 17 +++++++++-- packages/sdk/test/evm/nft.test.ts | 18 ++++++++++++ 5 files changed, 76 insertions(+), 13 deletions(-) diff --git a/packages/sdk/src/evm/core/classes/erc-721-enumerable.ts b/packages/sdk/src/evm/core/classes/erc-721-enumerable.ts index ec070c88199..6e1d9fee0c6 100644 --- a/packages/sdk/src/evm/core/classes/erc-721-enumerable.ts +++ b/packages/sdk/src/evm/core/classes/erc-721-enumerable.ts @@ -8,6 +8,10 @@ import type { BaseERC721 } from "../../types/eips"; import { DetectableFeature } from "../interfaces/DetectableFeature"; import type { ContractWrapper } from "./contract-wrapper"; import type { Erc721 } from "./erc-721"; +import { + DEFAULT_QUERY_ALL_COUNT, + QueryAllParams, +} from "../../../core/schema/QueryParams"; /** * List owned ERC721 NFTs @@ -46,10 +50,20 @@ export class Erc721Enumerable implements DetectableFeature { * const nfts = await contract.nft.query.owned.all(address); * ``` * @param walletAddress - the wallet address to query, defaults to the connected wallet + * @param queryParams - optional filtering to only fetch a subset of results. * @returns The NFT metadata for all NFTs in the contract. */ - public async all(walletAddress?: AddressOrEns): Promise { - const tokenIds = await this.tokenIds(walletAddress); + public async all( + walletAddress?: AddressOrEns, + queryParams?: QueryAllParams, + ): Promise { + let tokenIds = await this.tokenIds(walletAddress); + if (queryParams) { + const page = queryParams?.start || 0; + const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT; + const startIndex = page * count; + tokenIds = tokenIds.slice(startIndex, startIndex + count); + } return await Promise.all( tokenIds.map((tokenId) => this.erc721.get(tokenId.toString())), ); diff --git a/packages/sdk/src/evm/core/classes/erc-721-standard.ts b/packages/sdk/src/evm/core/classes/erc-721-standard.ts index 198d32a5110..3cf4735e9bd 100644 --- a/packages/sdk/src/evm/core/classes/erc-721-standard.ts +++ b/packages/sdk/src/evm/core/classes/erc-721-standard.ts @@ -95,13 +95,17 @@ export class StandardErc721< * console.log(nfts); * ``` * @param walletAddress - the wallet address to query, defaults to the connected wallet + * @param queryParams - optional filtering to only fetch a subset of results. * @returns The NFT metadata for all NFTs in the contract. */ - public async getOwned(walletAddress?: AddressOrEns): Promise { + public async getOwned( + walletAddress?: AddressOrEns, + queryParams?: QueryAllParams, + ): Promise { if (walletAddress) { walletAddress = await resolveAddress(walletAddress); } - return this.erc721.getOwned(walletAddress); + return this.erc721.getOwned(walletAddress, queryParams); } /** diff --git a/packages/sdk/src/evm/core/classes/erc-721.ts b/packages/sdk/src/evm/core/classes/erc-721.ts index e77b88f60d4..48cd214ac6e 100644 --- a/packages/sdk/src/evm/core/classes/erc-721.ts +++ b/packages/sdk/src/evm/core/classes/erc-721.ts @@ -17,7 +17,10 @@ import type { } from "@thirdweb-dev/contracts-js"; import type { ThirdwebStorage } from "@thirdweb-dev/storage"; import { BigNumber, BigNumberish, constants } from "ethers"; -import type { QueryAllParams } from "../../../core/schema/QueryParams"; +import { + DEFAULT_QUERY_ALL_COUNT, + type QueryAllParams, +} from "../../../core/schema/QueryParams"; import type { NFT, NFTMetadata, @@ -411,24 +414,35 @@ export class Erc721< * console.log(nfts); * ``` * @param walletAddress - the wallet address to query, defaults to the connected wallet + * @param queryParams - optional filtering to only fetch a subset of results. * @returns The NFT metadata for all NFTs in the contract. * @twfeature ERC721Supply | ERC721Enumerable */ - public async getOwned(walletAddress?: AddressOrEns) { + public async getOwned( + walletAddress?: AddressOrEns, + queryParams?: QueryAllParams, + ) { if (walletAddress) { walletAddress = await resolveAddress(walletAddress); } if (this.query?.owned) { - return this.query.owned.all(walletAddress); + return this.query.owned.all(walletAddress, queryParams); } else { const address = walletAddress || (await this.contractWrapper.getSignerAddress()); const allOwners = await this.getAllOwners(); - return Promise.all( - (allOwners || []) - .filter((i) => address?.toLowerCase() === i.owner?.toLowerCase()) - .map(async (i) => await this.get(i.tokenId)), + let ownedTokens = (allOwners || []).filter( + (i) => address?.toLowerCase() === i.owner?.toLowerCase(), + ); + if (queryParams) { + const page = queryParams?.start || 0; + const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT; + const startIndex = page * count; + ownedTokens = ownedTokens.slice(startIndex, startIndex + count); + } + return await Promise.all( + ownedTokens.map(async (i) => this.get(i.tokenId)), ); } } diff --git a/packages/sdk/src/evm/core/classes/erc-721a-queryable.ts b/packages/sdk/src/evm/core/classes/erc-721a-queryable.ts index 35b65ba6d03..82667a577f9 100644 --- a/packages/sdk/src/evm/core/classes/erc-721a-queryable.ts +++ b/packages/sdk/src/evm/core/classes/erc-721a-queryable.ts @@ -8,6 +8,10 @@ import type { BaseERC721 } from "../../types/eips"; import { DetectableFeature } from "../interfaces/DetectableFeature"; import type { ContractWrapper } from "./contract-wrapper"; import type { Erc721 } from "./erc-721"; +import { + DEFAULT_QUERY_ALL_COUNT, + QueryAllParams, +} from "../../../core/schema/QueryParams"; /** * List owned ERC721 NFTs @@ -50,8 +54,17 @@ export class Erc721AQueryable implements DetectableFeature { * @param walletAddress - the wallet address to query, defaults to the connected wallet * @returns The NFT metadata for all NFTs in the contract. */ - public async all(walletAddress?: AddressOrEns): Promise { - const tokenIds = await this.tokenIds(walletAddress); + public async all( + walletAddress?: AddressOrEns, + queryParams?: QueryAllParams, + ): Promise { + let tokenIds = await this.tokenIds(walletAddress); + if (queryParams) { + const page = queryParams?.start || 0; + const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT; + const startIndex = page * count; + tokenIds = tokenIds.slice(startIndex, startIndex + count); + } return await Promise.all( tokenIds.map((tokenId) => this.erc721.get(tokenId.toString())), ); diff --git a/packages/sdk/test/evm/nft.test.ts b/packages/sdk/test/evm/nft.test.ts index ce5c99db649..3193a35b773 100644 --- a/packages/sdk/test/evm/nft.test.ts +++ b/packages/sdk/test/evm/nft.test.ts @@ -273,4 +273,22 @@ describe("NFT Contract", async () => { }); expect(tx.id.toNumber()).to.eq(0); }); + + it("should respect pagination for getOwned", async () => { + const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10] + const metadata = _tokenIds.map((num) => ({ name: `Test${num}` })); + await nftContract.mintBatch(metadata); + const nftPage1 = await nftContract.getOwned(undefined, { + count: 2, + start: 1, + }); + expect(nftPage1).to.be.an("array").length(2); + const nftPage2 = await nftContract.getOwned(undefined, { + count: 3, + start: 3, + }); + expect(nftPage2).to.be.an("array").length(3); + expect(nftPage2[0].metadata.id).to.eq("6"); + expect(nftPage2[1].metadata.id).to.eq("7"); + }); }); From d2291c59a041bef5f6b4152583c33fd7e976150a Mon Sep 17 00:00:00 2001 From: Kien Ngo Date: Mon, 2 Oct 2023 13:32:51 -0400 Subject: [PATCH 02/11] Fix unit test --- packages/sdk/test/evm/nft.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sdk/test/evm/nft.test.ts b/packages/sdk/test/evm/nft.test.ts index 9e39c534932..b5a6362fb82 100644 --- a/packages/sdk/test/evm/nft.test.ts +++ b/packages/sdk/test/evm/nft.test.ts @@ -294,12 +294,12 @@ describe("NFT Contract", async () => { await nftContract.mintBatch(metadata); const nftPage1 = await nftContract.getOwned(undefined, { count: 2, - page: 1, + start: 0, }); expect(nftPage1).to.be.an("array").length(2); const nftPage2 = await nftContract.getOwned(undefined, { count: 3, - page: 3, + start: 2, }); expect(nftPage2).to.be.an("array").length(3); expect(nftPage2[0].metadata.id).to.eq("6"); From f648b6a5af41afa659d3a297a14035fa73ffbd64 Mon Sep 17 00:00:00 2001 From: Kien Ngo Date: Mon, 2 Oct 2023 17:58:32 -0400 Subject: [PATCH 03/11] Add pagination to getOwned for ERC1155 --- .../prebuilt-implementations/edition-drop.ts | 7 ++- .../prebuilt-implementations/edition.ts | 7 ++- .../evm/core/classes/erc-1155-enumerable.ts | 43 ++++++++++++------- packages/sdk/src/evm/core/classes/erc-1155.ts | 6 ++- packages/sdk/test/evm/edition.test.ts | 25 +++++++++++ 5 files changed, 67 insertions(+), 21 deletions(-) diff --git a/packages/sdk/src/evm/contracts/prebuilt-implementations/edition-drop.ts b/packages/sdk/src/evm/contracts/prebuilt-implementations/edition-drop.ts index b4d107de515..aa7b36cfe6c 100644 --- a/packages/sdk/src/evm/contracts/prebuilt-implementations/edition-drop.ts +++ b/packages/sdk/src/evm/contracts/prebuilt-implementations/edition-drop.ts @@ -216,8 +216,11 @@ export class EditionDrop extends StandardErc1155 { * * @returns The NFT metadata for all NFTs in the contract. */ - public async getOwned(walletAddress?: AddressOrEns): Promise { - return this.erc1155.getOwned(walletAddress); + public async getOwned( + walletAddress?: AddressOrEns, + queryParams?: QueryAllParams, + ): Promise { + return this.erc1155.getOwned(walletAddress, queryParams); } /** diff --git a/packages/sdk/src/evm/contracts/prebuilt-implementations/edition.ts b/packages/sdk/src/evm/contracts/prebuilt-implementations/edition.ts index 8489e23bcf7..d02c7a8656a 100644 --- a/packages/sdk/src/evm/contracts/prebuilt-implementations/edition.ts +++ b/packages/sdk/src/evm/contracts/prebuilt-implementations/edition.ts @@ -190,8 +190,11 @@ export class Edition extends StandardErc1155 { * * @returns The NFT metadata for all NFTs in the contract. */ - public async getOwned(walletAddress?: AddressOrEns): Promise { - return this.erc1155.getOwned(walletAddress); + public async getOwned( + walletAddress?: AddressOrEns, + queryParams?: QueryAllParams, + ): Promise { + return this.erc1155.getOwned(walletAddress, queryParams); } /** diff --git a/packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts b/packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts index 0adad0ba8dd..de77eff3522 100644 --- a/packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts +++ b/packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts @@ -102,17 +102,22 @@ export class Erc1155Enumerable implements DetectableFeature { * * @returns The NFT metadata for all NFTs in the contract. */ - public async owned(walletAddress?: AddressOrEns): Promise { - const address = await resolveAddress( - walletAddress || (await this.contractWrapper.getSignerAddress()), - ); - const maxId = await this.contractWrapper.read("nextTokenIdToMint", []); + public async owned( + walletAddress?: AddressOrEns, + queryParams?: QueryAllParams, + ): Promise { + const [address, maxId] = await Promise.all([ + resolveAddress( + walletAddress || (await this.contractWrapper.getSignerAddress()), + ), + this.contractWrapper.read("nextTokenIdToMint", []), + ]); const balances = await this.contractWrapper.read("balanceOfBatch", [ Array(maxId.toNumber()).fill(address), Array.from(Array(maxId.toNumber()).keys()), ]); - const ownedBalances = balances + let ownedBalances = balances .map((b, i) => { return { tokenId: i, @@ -120,15 +125,21 @@ export class Erc1155Enumerable implements DetectableFeature { }; }) .filter((b) => b.balance.gt(0)); - return await Promise.all( - ownedBalances.map(async (b) => { - const editionMetadata = await this.erc1155.get(b.tokenId.toString()); - return { - ...editionMetadata, - owner: address, - quantityOwned: b.balance.toString(), - }; - }), - ); + if (queryParams) { + const page = queryParams?.start || 0; + const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT; + const startIndex = page * count; + ownedBalances = ownedBalances.slice(startIndex, startIndex + count); + } + const nfts = ( + await Promise.all( + ownedBalances.map((item) => this.erc1155.get(item.tokenId.toString())), + ) + ).map((editionMetadata, index) => ({ + ...editionMetadata, + owner: address, + quantityOwned: ownedBalances[index].balance.toString(), + })); + return nfts; } } diff --git a/packages/sdk/src/evm/core/classes/erc-1155.ts b/packages/sdk/src/evm/core/classes/erc-1155.ts index af4c33c5d3d..d9069443d08 100644 --- a/packages/sdk/src/evm/core/classes/erc-1155.ts +++ b/packages/sdk/src/evm/core/classes/erc-1155.ts @@ -494,12 +494,16 @@ export class Erc1155< * @returns The NFT metadata for all NFTs in the contract. * @twfeature ERC1155Enumerable */ - public async getOwned(walletAddress?: AddressOrEns): Promise { + public async getOwned( + walletAddress?: AddressOrEns, + queryParams?: QueryAllParams, + ): Promise { if (walletAddress) { walletAddress = await resolveAddress(walletAddress); } return assertEnabled(this.query, FEATURE_EDITION_ENUMERABLE).owned( walletAddress, + queryParams, ); } diff --git a/packages/sdk/test/evm/edition.test.ts b/packages/sdk/test/evm/edition.test.ts index 3aab671c064..518b36ef3eb 100644 --- a/packages/sdk/test/evm/edition.test.ts +++ b/packages/sdk/test/evm/edition.test.ts @@ -259,4 +259,29 @@ describe("Edition Contract", async () => { i++; }); }); + + it("should respect pagination for getOwned", async () => { + const nfts = [] as { metadata: { name: string }; supply: number }[]; + for (let i = 0; i < 10; i++) { + nfts.push({ + metadata: { name: `Test${i}` }, + supply: 10, + }); + } + await bundleContract.mintBatch(nfts); + const total = await bundleContract.getTotalCount(); + expect(total.toNumber()).to.eq(10); + const page1 = await bundleContract.getOwned(adminWallet.address, { + count: 2, + start: 0, + }); + expect(page1).to.be.an("array").length(2); + const page3 = await bundleContract.getOwned(adminWallet.address, { + count: 3, + start: 2, + }); + expect(page3).to.be.an("array").length(3); + expect(page3[0].metadata.id).to.eq("6"); + expect(page3[1].metadata.id).to.eq("7"); + }); }); From 677224f19ad5d21afeb9b24d8493653df6640d44 Mon Sep 17 00:00:00 2001 From: Kien Ngo Date: Mon, 2 Oct 2023 18:54:35 -0400 Subject: [PATCH 04/11] Add more test units --- packages/sdk/test/evm/edition.test.ts | 16 ++++++++++++++++ packages/sdk/test/evm/nft.test.ts | 11 +++++++++++ 2 files changed, 27 insertions(+) diff --git a/packages/sdk/test/evm/edition.test.ts b/packages/sdk/test/evm/edition.test.ts index 518b36ef3eb..3bcec4a8b5a 100644 --- a/packages/sdk/test/evm/edition.test.ts +++ b/packages/sdk/test/evm/edition.test.ts @@ -284,4 +284,20 @@ describe("Edition Contract", async () => { expect(page3[0].metadata.id).to.eq("6"); expect(page3[1].metadata.id).to.eq("7"); }); + + it("getOwned pagination should return all records when queryParams.count is greater than the total supply", async () => { + const nfts = [] as { metadata: { name: string }; supply: number }[]; + for (let i = 0; i < 10; i++) { + nfts.push({ + metadata: { name: `Test${i}` }, + supply: 10, + }); + } + await bundleContract.mintBatch(nfts); + const items = await bundleContract.getOwned(undefined, { + count: 1000, + start: 0, + }); + expect(items).to.be.an("array").length(nfts.length); + }); }); diff --git a/packages/sdk/test/evm/nft.test.ts b/packages/sdk/test/evm/nft.test.ts index b5a6362fb82..2876a8bfca0 100644 --- a/packages/sdk/test/evm/nft.test.ts +++ b/packages/sdk/test/evm/nft.test.ts @@ -305,4 +305,15 @@ describe("NFT Contract", async () => { expect(nftPage2[0].metadata.id).to.eq("6"); expect(nftPage2[1].metadata.id).to.eq("7"); }); + + it("getOwned pagination should return all records when queryParams.count is greater than the total supply", async () => { + const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10] + const metadata = _tokenIds.map((num) => ({ name: `Test${num}` })); + await nftContract.mintBatch(metadata); + const nfts = await nftContract.getOwned(undefined, { + count: 1000, + start: 0, + }); + expect(nfts).to.be.an("array").length(_tokenIds.length); + }); }); From 91afac0625c7b56710c84e8961d9a993f12bcb35 Mon Sep 17 00:00:00 2001 From: Kien Ngo Date: Mon, 2 Oct 2023 21:35:46 -0400 Subject: [PATCH 05/11] Add changeset --- .changeset/four-jeans-brake.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/four-jeans-brake.md diff --git a/.changeset/four-jeans-brake.md b/.changeset/four-jeans-brake.md new file mode 100644 index 00000000000..7e8d03b231f --- /dev/null +++ b/.changeset/four-jeans-brake.md @@ -0,0 +1,5 @@ +--- +"@thirdweb-dev/sdk": minor +--- + +Add optional pagination to getOwned NFTs From ea3fc38f252a875749ec2933acc103775e43fe2d Mon Sep 17 00:00:00 2001 From: Kien Ngo Date: Tue, 3 Oct 2023 13:12:00 -0400 Subject: [PATCH 06/11] Set to patch --- .changeset/four-jeans-brake.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/four-jeans-brake.md b/.changeset/four-jeans-brake.md index 7e8d03b231f..3f03ef04ea9 100644 --- a/.changeset/four-jeans-brake.md +++ b/.changeset/four-jeans-brake.md @@ -1,5 +1,5 @@ --- -"@thirdweb-dev/sdk": minor +"@thirdweb-dev/sdk": patch --- Add optional pagination to getOwned NFTs From 75ce24c90f484be419483c85a9c953d718e126b1 Mon Sep 17 00:00:00 2001 From: Kien Ngo Date: Tue, 3 Oct 2023 13:25:11 -0400 Subject: [PATCH 07/11] Update var names --- packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts | 4 ++-- packages/sdk/src/evm/core/classes/erc-721-enumerable.ts | 4 ++-- packages/sdk/src/evm/core/classes/erc-721.ts | 4 ++-- packages/sdk/src/evm/core/classes/erc-721a-queryable.ts | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts b/packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts index de77eff3522..7a1b8c2f5a8 100644 --- a/packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts +++ b/packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts @@ -126,9 +126,9 @@ export class Erc1155Enumerable implements DetectableFeature { }) .filter((b) => b.balance.gt(0)); if (queryParams) { - const page = queryParams?.start || 0; + const start = queryParams?.start || 0; const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT; - const startIndex = page * count; + const startIndex = start * count; ownedBalances = ownedBalances.slice(startIndex, startIndex + count); } const nfts = ( diff --git a/packages/sdk/src/evm/core/classes/erc-721-enumerable.ts b/packages/sdk/src/evm/core/classes/erc-721-enumerable.ts index 6e1d9fee0c6..3da9bea7337 100644 --- a/packages/sdk/src/evm/core/classes/erc-721-enumerable.ts +++ b/packages/sdk/src/evm/core/classes/erc-721-enumerable.ts @@ -59,9 +59,9 @@ export class Erc721Enumerable implements DetectableFeature { ): Promise { let tokenIds = await this.tokenIds(walletAddress); if (queryParams) { - const page = queryParams?.start || 0; + const start = queryParams?.start || 0; const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT; - const startIndex = page * count; + const startIndex = start * count; tokenIds = tokenIds.slice(startIndex, startIndex + count); } return await Promise.all( diff --git a/packages/sdk/src/evm/core/classes/erc-721.ts b/packages/sdk/src/evm/core/classes/erc-721.ts index 10bd9932b59..61e25d01e02 100644 --- a/packages/sdk/src/evm/core/classes/erc-721.ts +++ b/packages/sdk/src/evm/core/classes/erc-721.ts @@ -441,9 +441,9 @@ export class Erc721< (i) => address?.toLowerCase() === i.owner?.toLowerCase(), ); if (queryParams) { - const page = queryParams?.start || 0; + const start = queryParams?.start || 0; const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT; - const startIndex = page * count; + const startIndex = start * count; ownedTokens = ownedTokens.slice(startIndex, startIndex + count); } return await Promise.all( diff --git a/packages/sdk/src/evm/core/classes/erc-721a-queryable.ts b/packages/sdk/src/evm/core/classes/erc-721a-queryable.ts index 82667a577f9..a3570248266 100644 --- a/packages/sdk/src/evm/core/classes/erc-721a-queryable.ts +++ b/packages/sdk/src/evm/core/classes/erc-721a-queryable.ts @@ -60,9 +60,9 @@ export class Erc721AQueryable implements DetectableFeature { ): Promise { let tokenIds = await this.tokenIds(walletAddress); if (queryParams) { - const page = queryParams?.start || 0; + const start = queryParams?.start || 0; const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT; - const startIndex = page * count; + const startIndex = start * count; tokenIds = tokenIds.slice(startIndex, startIndex + count); } return await Promise.all( From 30a4c31e647332f04ace3d40610cc68f5cc7033b Mon Sep 17 00:00:00 2001 From: Kien Ngo Date: Wed, 4 Oct 2023 09:36:40 -0400 Subject: [PATCH 08/11] Remove tests --- packages/sdk/test/evm/edition.test.ts | 16 ---------------- packages/sdk/test/evm/nft.test.ts | 11 ----------- 2 files changed, 27 deletions(-) diff --git a/packages/sdk/test/evm/edition.test.ts b/packages/sdk/test/evm/edition.test.ts index 5356709e1bf..fcce25dda30 100644 --- a/packages/sdk/test/evm/edition.test.ts +++ b/packages/sdk/test/evm/edition.test.ts @@ -314,20 +314,4 @@ describe("Edition Contract", async () => { expect(page3[0].metadata.id).to.eq("6"); expect(page3[1].metadata.id).to.eq("7"); }); - - it("getOwned pagination should return all records when queryParams.count is greater than the total supply", async () => { - const nfts = [] as { metadata: { name: string }; supply: number }[]; - for (let i = 0; i < 10; i++) { - nfts.push({ - metadata: { name: `Test${i}` }, - supply: 10, - }); - } - await bundleContract.mintBatch(nfts); - const items = await bundleContract.getOwned(undefined, { - count: 1000, - start: 0, - }); - expect(items).to.be.an("array").length(nfts.length); - }); }); diff --git a/packages/sdk/test/evm/nft.test.ts b/packages/sdk/test/evm/nft.test.ts index 2876a8bfca0..b5a6362fb82 100644 --- a/packages/sdk/test/evm/nft.test.ts +++ b/packages/sdk/test/evm/nft.test.ts @@ -305,15 +305,4 @@ describe("NFT Contract", async () => { expect(nftPage2[0].metadata.id).to.eq("6"); expect(nftPage2[1].metadata.id).to.eq("7"); }); - - it("getOwned pagination should return all records when queryParams.count is greater than the total supply", async () => { - const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10] - const metadata = _tokenIds.map((num) => ({ name: `Test${num}` })); - await nftContract.mintBatch(metadata); - const nfts = await nftContract.getOwned(undefined, { - count: 1000, - start: 0, - }); - expect(nfts).to.be.an("array").length(_tokenIds.length); - }); }); From 3eda129633e6fe4a2af9b5f2031a7fe0b0b988c2 Mon Sep 17 00:00:00 2001 From: Kien Ngo Date: Wed, 4 Oct 2023 19:57:40 -0400 Subject: [PATCH 09/11] Update pagination logic; add mroe unit tests --- .../evm/core/classes/erc-1155-enumerable.ts | 3 +- .../evm/core/classes/erc-721-enumerable.ts | 3 +- packages/sdk/src/evm/core/classes/erc-721.ts | 3 +- .../evm/core/classes/erc-721a-queryable.ts | 3 +- packages/sdk/test/evm/edition.test.ts | 53 ++++++++++++++++--- packages/sdk/test/evm/nft.test.ts | 32 +++++++++-- 6 files changed, 79 insertions(+), 18 deletions(-) diff --git a/packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts b/packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts index 7a1b8c2f5a8..8a060fa1493 100644 --- a/packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts +++ b/packages/sdk/src/evm/core/classes/erc-1155-enumerable.ts @@ -128,8 +128,7 @@ export class Erc1155Enumerable implements DetectableFeature { if (queryParams) { const start = queryParams?.start || 0; const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT; - const startIndex = start * count; - ownedBalances = ownedBalances.slice(startIndex, startIndex + count); + ownedBalances = ownedBalances.slice(start, start + count); } const nfts = ( await Promise.all( diff --git a/packages/sdk/src/evm/core/classes/erc-721-enumerable.ts b/packages/sdk/src/evm/core/classes/erc-721-enumerable.ts index 3da9bea7337..89c79e5997a 100644 --- a/packages/sdk/src/evm/core/classes/erc-721-enumerable.ts +++ b/packages/sdk/src/evm/core/classes/erc-721-enumerable.ts @@ -61,8 +61,7 @@ export class Erc721Enumerable implements DetectableFeature { if (queryParams) { const start = queryParams?.start || 0; const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT; - const startIndex = start * count; - tokenIds = tokenIds.slice(startIndex, startIndex + count); + tokenIds = tokenIds.slice(start, start + count); } return await Promise.all( tokenIds.map((tokenId) => this.erc721.get(tokenId.toString())), diff --git a/packages/sdk/src/evm/core/classes/erc-721.ts b/packages/sdk/src/evm/core/classes/erc-721.ts index 61e25d01e02..4a7996d95e8 100644 --- a/packages/sdk/src/evm/core/classes/erc-721.ts +++ b/packages/sdk/src/evm/core/classes/erc-721.ts @@ -443,8 +443,7 @@ export class Erc721< if (queryParams) { const start = queryParams?.start || 0; const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT; - const startIndex = start * count; - ownedTokens = ownedTokens.slice(startIndex, startIndex + count); + ownedTokens = ownedTokens.slice(start, start + count); } return await Promise.all( ownedTokens.map(async (i) => this.get(i.tokenId)), diff --git a/packages/sdk/src/evm/core/classes/erc-721a-queryable.ts b/packages/sdk/src/evm/core/classes/erc-721a-queryable.ts index a3570248266..80cb997e386 100644 --- a/packages/sdk/src/evm/core/classes/erc-721a-queryable.ts +++ b/packages/sdk/src/evm/core/classes/erc-721a-queryable.ts @@ -62,8 +62,7 @@ export class Erc721AQueryable implements DetectableFeature { if (queryParams) { const start = queryParams?.start || 0; const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT; - const startIndex = start * count; - tokenIds = tokenIds.slice(startIndex, startIndex + count); + tokenIds = tokenIds.slice(start, start + count); } return await Promise.all( tokenIds.map((tokenId) => this.erc721.get(tokenId.toString())), diff --git a/packages/sdk/test/evm/edition.test.ts b/packages/sdk/test/evm/edition.test.ts index fcce25dda30..7d764fc4ee8 100644 --- a/packages/sdk/test/evm/edition.test.ts +++ b/packages/sdk/test/evm/edition.test.ts @@ -290,7 +290,7 @@ describe("Edition Contract", async () => { expect(nfts[0].metadata.id).to.be.equal("1"); }); - it("should respect pagination for getOwned", async () => { + it("should respect pagination for getOwned (for edition.ts)", async () => { const nfts = [] as { metadata: { name: string }; supply: number }[]; for (let i = 0; i < 10; i++) { nfts.push({ @@ -301,17 +301,56 @@ describe("Edition Contract", async () => { await bundleContract.mintBatch(nfts); const total = await bundleContract.getTotalCount(); expect(total.toNumber()).to.eq(10); - const page1 = await bundleContract.getOwned(adminWallet.address, { + const nftPage1 = await bundleContract.getOwned(adminWallet.address, { count: 2, start: 0, }); - expect(page1).to.be.an("array").length(2); - const page3 = await bundleContract.getOwned(adminWallet.address, { + expect(nftPage1).to.be.an("array").length(2); + expect(nftPage1[0].metadata.id).to.eq("0"); + expect(nftPage1[1].metadata.id).to.eq("1"); + + const nftPage2 = await bundleContract.getOwned(adminWallet.address, { count: 3, start: 2, }); - expect(page3).to.be.an("array").length(3); - expect(page3[0].metadata.id).to.eq("6"); - expect(page3[1].metadata.id).to.eq("7"); + expect(nftPage2).to.be.an("array").length(3); + expect(nftPage2[0].metadata.id).to.eq("2"); + expect(nftPage2[1].metadata.id).to.eq("3"); + expect(nftPage1[2].metadata.id).to.eq("4"); + }); + + it("should respect pagination for getOwned (for erc-1155.ts)", async () => { + const nfts = [] as { metadata: { name: string }; supply: number }[]; + for (let i = 0; i < 10; i++) { + nfts.push({ + metadata: { name: `Test${i}` }, + supply: 10, + }); + } + await bundleContract.mintBatch(nfts); + const total = await bundleContract.getTotalCount(); + expect(total.toNumber()).to.eq(10); + const nftPage1 = await bundleContract.erc1155.getOwned( + adminWallet.address, + { + count: 2, + start: 0, + }, + ); + expect(nftPage1).to.be.an("array").length(2); + expect(nftPage1[0].metadata.id).to.eq("0"); + expect(nftPage1[1].metadata.id).to.eq("1"); + + const nftPage2 = await bundleContract.erc1155.getOwned( + adminWallet.address, + { + count: 3, + start: 2, + }, + ); + expect(nftPage2).to.be.an("array").length(3); + expect(nftPage2[0].metadata.id).to.eq("2"); + expect(nftPage2[1].metadata.id).to.eq("3"); + expect(nftPage1[2].metadata.id).to.eq("4"); }); }); diff --git a/packages/sdk/test/evm/nft.test.ts b/packages/sdk/test/evm/nft.test.ts index b5a6362fb82..00ae342d031 100644 --- a/packages/sdk/test/evm/nft.test.ts +++ b/packages/sdk/test/evm/nft.test.ts @@ -288,7 +288,7 @@ describe("NFT Contract", async () => { expect(records[1].tokenId).to.eq(2); }); - it("should respect pagination for getOwned", async () => { + it("should respect pagination for getOwned (for erc-721-standard.ts)", async () => { const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10] const metadata = _tokenIds.map((num) => ({ name: `Test${num}` })); await nftContract.mintBatch(metadata); @@ -297,12 +297,38 @@ describe("NFT Contract", async () => { start: 0, }); expect(nftPage1).to.be.an("array").length(2); + expect(nftPage1[0].metadata.id).to.eq("0"); + expect(nftPage1[1].metadata.id).to.eq("1"); + const nftPage2 = await nftContract.getOwned(undefined, { count: 3, start: 2, }); expect(nftPage2).to.be.an("array").length(3); - expect(nftPage2[0].metadata.id).to.eq("6"); - expect(nftPage2[1].metadata.id).to.eq("7"); + expect(nftPage2[0].metadata.id).to.eq("2"); + expect(nftPage2[1].metadata.id).to.eq("3"); + expect(nftPage1[2].metadata.id).to.eq("4"); + }); + + it("should respect pagination for getOwned (for erc-721.ts)", async () => { + const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10] + const metadata = _tokenIds.map((num) => ({ name: `Test${num}` })); + await nftContract.mintBatch(metadata); + const nftPage1 = await nftContract.erc721.getOwned(undefined, { + count: 2, + start: 0, + }); + expect(nftPage1).to.be.an("array").length(2); + expect(nftPage1[0].metadata.id).to.eq("0"); + expect(nftPage1[1].metadata.id).to.eq("1"); + + const nftPage2 = await nftContract.erc721.getOwned(undefined, { + count: 3, + start: 2, + }); + expect(nftPage2).to.be.an("array").length(3); + expect(nftPage2[0].metadata.id).to.eq("2"); + expect(nftPage2[1].metadata.id).to.eq("3"); + expect(nftPage1[2].metadata.id).to.eq("4"); }); }); From c3e03ff7b119971bb112c981600da82ac5e61520 Mon Sep 17 00:00:00 2001 From: Kien Ngo Date: Wed, 4 Oct 2023 20:26:04 -0400 Subject: [PATCH 10/11] Update test cases --- packages/sdk/test/evm/edition.test.ts | 32 +++++++++++++++++++++++++++ packages/sdk/test/evm/nft.test.ts | 26 ++++++++++++++++++++-- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/packages/sdk/test/evm/edition.test.ts b/packages/sdk/test/evm/edition.test.ts index 7d764fc4ee8..42d6efd7a66 100644 --- a/packages/sdk/test/evm/edition.test.ts +++ b/packages/sdk/test/evm/edition.test.ts @@ -353,4 +353,36 @@ describe("Edition Contract", async () => { expect(nftPage2[1].metadata.id).to.eq("3"); expect(nftPage1[2].metadata.id).to.eq("4"); }); + + it("getOwned should return all items when queryParams.count is greater than the total supply (edition.ts)", async () => { + const nfts = [] as { metadata: { name: string }; supply: number }[]; + for (let i = 0; i < 10; i++) { + nfts.push({ + metadata: { name: `Test${i}` }, + supply: 10, + }); + } + await bundleContract.mintBatch(nfts); + const items = await bundleContract.getOwned(undefined, { + count: 1000, + start: 0, + }); + expect(items).to.be.an("array").length(nfts.length); + }); + + it("getOwned should return all items when queryParams.count is greater than the total supply (erc-1155.ts)", async () => { + const nfts = [] as { metadata: { name: string }; supply: number }[]; + for (let i = 0; i < 10; i++) { + nfts.push({ + metadata: { name: `Test${i}` }, + supply: 10, + }); + } + await bundleContract.mintBatch(nfts); + const items = await bundleContract.getOwned(undefined, { + count: 1000, + start: 0, + }); + expect(items).to.be.an("array").length(nfts.length); + }); }); diff --git a/packages/sdk/test/evm/nft.test.ts b/packages/sdk/test/evm/nft.test.ts index 00ae342d031..8862a2ae5e2 100644 --- a/packages/sdk/test/evm/nft.test.ts +++ b/packages/sdk/test/evm/nft.test.ts @@ -288,7 +288,7 @@ describe("NFT Contract", async () => { expect(records[1].tokenId).to.eq(2); }); - it("should respect pagination for getOwned (for erc-721-standard.ts)", async () => { + it("should respect pagination for getOwned (erc-721-standard.ts)", async () => { const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10] const metadata = _tokenIds.map((num) => ({ name: `Test${num}` })); await nftContract.mintBatch(metadata); @@ -310,7 +310,7 @@ describe("NFT Contract", async () => { expect(nftPage1[2].metadata.id).to.eq("4"); }); - it("should respect pagination for getOwned (for erc-721.ts)", async () => { + it("should respect pagination for getOwned (erc-721.ts)", async () => { const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10] const metadata = _tokenIds.map((num) => ({ name: `Test${num}` })); await nftContract.mintBatch(metadata); @@ -331,4 +331,26 @@ describe("NFT Contract", async () => { expect(nftPage2[1].metadata.id).to.eq("3"); expect(nftPage1[2].metadata.id).to.eq("4"); }); + + it("getOwned should return all item when queryParams.count is greater than the total supply (erc-721-standard.ts)", async () => { + const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10] + const metadata = _tokenIds.map((num) => ({ name: `Test${num}` })); + await nftContract.mintBatch(metadata); + const nfts = await nftContract.getOwned(undefined, { + count: 1000, + start: 0, + }); + expect(nfts).to.be.an("array").length(_tokenIds.length); + }); + + it("getOwned should return all items when queryParams.count is greater than the total supply (erc-721.ts)", async () => { + const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10] + const metadata = _tokenIds.map((num) => ({ name: `Test${num}` })); + await nftContract.mintBatch(metadata); + const nfts = await nftContract.erc721.getOwned(undefined, { + count: 1000, + start: 0, + }); + expect(nfts).to.be.an("array").length(_tokenIds.length); + }); }); From 502f66d5da9044c517fb8f57672a28d8bd7ad8e2 Mon Sep 17 00:00:00 2001 From: Kien Ngo Date: Wed, 4 Oct 2023 20:54:04 -0400 Subject: [PATCH 11/11] Fix typo in test units --- packages/sdk/test/evm/edition.test.ts | 4 ++-- packages/sdk/test/evm/nft.test.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/sdk/test/evm/edition.test.ts b/packages/sdk/test/evm/edition.test.ts index 42d6efd7a66..3da2a6182b6 100644 --- a/packages/sdk/test/evm/edition.test.ts +++ b/packages/sdk/test/evm/edition.test.ts @@ -316,7 +316,7 @@ describe("Edition Contract", async () => { expect(nftPage2).to.be.an("array").length(3); expect(nftPage2[0].metadata.id).to.eq("2"); expect(nftPage2[1].metadata.id).to.eq("3"); - expect(nftPage1[2].metadata.id).to.eq("4"); + expect(nftPage2[2].metadata.id).to.eq("4"); }); it("should respect pagination for getOwned (for erc-1155.ts)", async () => { @@ -351,7 +351,7 @@ describe("Edition Contract", async () => { expect(nftPage2).to.be.an("array").length(3); expect(nftPage2[0].metadata.id).to.eq("2"); expect(nftPage2[1].metadata.id).to.eq("3"); - expect(nftPage1[2].metadata.id).to.eq("4"); + expect(nftPage2[2].metadata.id).to.eq("4"); }); it("getOwned should return all items when queryParams.count is greater than the total supply (edition.ts)", async () => { diff --git a/packages/sdk/test/evm/nft.test.ts b/packages/sdk/test/evm/nft.test.ts index 8862a2ae5e2..7fb41216e9c 100644 --- a/packages/sdk/test/evm/nft.test.ts +++ b/packages/sdk/test/evm/nft.test.ts @@ -307,7 +307,7 @@ describe("NFT Contract", async () => { expect(nftPage2).to.be.an("array").length(3); expect(nftPage2[0].metadata.id).to.eq("2"); expect(nftPage2[1].metadata.id).to.eq("3"); - expect(nftPage1[2].metadata.id).to.eq("4"); + expect(nftPage2[2].metadata.id).to.eq("4"); }); it("should respect pagination for getOwned (erc-721.ts)", async () => { @@ -329,7 +329,7 @@ describe("NFT Contract", async () => { expect(nftPage2).to.be.an("array").length(3); expect(nftPage2[0].metadata.id).to.eq("2"); expect(nftPage2[1].metadata.id).to.eq("3"); - expect(nftPage1[2].metadata.id).to.eq("4"); + expect(nftPage2[2].metadata.id).to.eq("4"); }); it("getOwned should return all item when queryParams.count is greater than the total supply (erc-721-standard.ts)", async () => {