Repository: alchemyplatform/alchemy-sdk-js
Pull request #293 (2023-03-31 18:57:01)

Add pagination to getOwnersForNft

joshzhang5: Current dependencies on/for this PR:
* main
  * **PR #293** <a href="https://app.graphite.dev/github/pr/alchemyplatform/alchemy-sdk-js/293" target="_blank"><img src="https://static.graphite.dev/graphite-32x32.png" alt="Graphite" width="10px" height="10px"/></a>  👈

This comment was auto-generated by [Graphite](https://app.graphite.dev/github/pr/alchemyplatform/alchemy-sdk-js/293?utm_source=stack-comment).

Patch:
diff --git a/.gitignore b/.gitignore
index 3f6b02b6..1df2e86e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,6 @@ temp
 alchemy.env
 
 .npmrc
+
+# VSCode History Extension
+.history
diff --git a/src/api/nft-namespace.ts b/src/api/nft-namespace.ts
index 21b7e9a6..90e5bd11 100644
--- a/src/api/nft-namespace.ts
+++ b/src/api/nft-namespace.ts
@@ -44,6 +44,7 @@ import {
   GetOwnersForContractResponse,
   GetOwnersForContractWithTokenBalancesOptions,
   GetOwnersForContractWithTokenBalancesResponse,
+  GetOwnersForNftOptions,
   GetOwnersForNftResponse,
   GetTransfersForContractOptions,
   GetTransfersForOwnerOptions,
@@ -353,13 +354,15 @@ export class NftNamespace {
    *
    * @param contractAddress - The NFT contract address.
    * @param tokenId - Token id of the NFT.
+   * @param options - Optional parameters to use for the request.
    * @beta
    */
   getOwnersForNft(
     contractAddress: string,
-    tokenId: BigNumberish
+    tokenId: BigNumberish,
+    options?: GetOwnersForNftOptions
   ): Promise<GetOwnersForNftResponse> {
-    return getOwnersForNft(this.config, contractAddress, tokenId);
+    return getOwnersForNft(this.config, contractAddress, tokenId, options);
   }
 
   /**
diff --git a/src/internal/nft-api.ts b/src/internal/nft-api.ts
index 57ee9bee..6d875ca7 100644
--- a/src/internal/nft-api.ts
+++ b/src/internal/nft-api.ts
@@ -338,6 +338,7 @@ export async function getOwnersForNft(
   config: AlchemyConfig,
   contractAddress: string,
   tokenId: BigNumberish,
+  options?: GetOwnersForContractOptions,
   srcMethod = 'getOwnersForNft'
 ): Promise<GetOwnersForNftResponse> {
   return requestHttpWithBackoff(
@@ -347,7 +348,8 @@ export async function getOwnersForNft(
     srcMethod,
     {
       contractAddress,
-      tokenId: BigNumber.from(tokenId!).toString()
+      tokenId: BigNumber.from(tokenId!).toString(),
+      ...options
     }
   );
 }
diff --git a/src/types/types.ts b/src/types/types.ts
index 810c1779..acbf69c1 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -827,6 +827,9 @@ export interface OwnedBaseNft extends BaseNft {
 export interface GetOwnersForNftResponse {
   /** An array of owner addresses for the provided token. */
   readonly owners: string[];
+
+  /** Optional The key for the next page of results, if applicable. */
+  readonly pageKey?: string;
 }
 
 /**
@@ -1598,6 +1601,24 @@ export interface GetOwnersForContractWithTokenBalancesOptions {
   pageKey?: string;
 }
 
+/**
+ * Optional parameters object for the {@link getOwnersForNft} method.
+ *
+ * This interface configures options when fetching the owner addresses of the
+ * provided NFT contract.
+ *
+ * @public
+ */
+export interface GetOwnersForNftOptions {
+  /** Optional page key to paginate the next page for large requests. */
+  pageKey?: string;
+
+  /**
+   * Sets the total number of owners to return in the response.
+   */
+  pageSize?: number;
+}
+
 /**
  * The response object for the {@link getNftsForContract} function. The object
  * contains the NFTs without metadata inside the NFT contract.


Test patch:
diff --git a/test/integration/nft.test.ts b/test/integration/nft.test.ts
index ee49d18f..a96bbd1d 100644
--- a/test/integration/nft.test.ts
+++ b/test/integration/nft.test.ts
@@ -115,6 +115,38 @@ describe('E2E integration tests', () => {
     expect(response.owners.length).toBeGreaterThan(0);
   });
 
+  it('getOwnersForNft() with pageSize on erc1155 contract 0x84162fE2E695Fedbf4D3bcA1c3458FB616E44735', async () => {
+    const tokenId = '0';
+    const response = await alchemy.nft.getOwnersForNft(
+      '0x84162fE2E695Fedbf4D3bcA1c3458FB616E44735',
+      tokenId,
+      { pageSize: 51 }
+    );
+    expect(response.owners.length).toEqual(51);
+  });
+
+  it('getOwnersForNft() with pageKey on erc1155 contract 0x84162fE2E695Fedbf4D3bcA1c3458FB616E44735', async () => {
+    const tokenId = '0';
+    const firstPageResponse = await alchemy.nft.getOwnersForNft(
+      '0x84162fE2E695Fedbf4D3bcA1c3458FB616E44735',
+      tokenId,
+      { pageSize: 1 }
+    );
+    const pageKey = firstPageResponse.pageKey;
+    expect(pageKey).toBeDefined();
+
+    const nextPageResponse = await alchemy.nft.getOwnersForNft(
+      contractAddress,
+      tokenId,
+      { pageSize: 1, pageKey }
+    );
+    expect(nextPageResponse.owners.length).toEqual(1);
+    // cursory check that the pages contain different data
+    expect(
+      firstPageResponse.owners[0] === nextPageResponse.owners[0]
+    ).toBeFalsy();
+  });
+
   it('getNftForOwners() with pageSize', async () => {
     const response = await alchemy.nft.getNftsForOwner('0xshah.eth', {
       pageSize: 51
diff --git a/test/unit/nft-api.test.ts b/test/unit/nft-api.test.ts
index f5102642..0c59a27c 100644
--- a/test/unit/nft-api.test.ts
+++ b/test/unit/nft-api.test.ts
@@ -1024,6 +1024,8 @@ describe('NFT module', () => {
     const tokenIdHex = '0x1b7';
     const tokenIdNumber = '439';
     const owners = ['0x1', '0x2', '0x3'];
+    const pageKey = 'abcdefg';
+    const pageSize = 500;
 
     beforeEach(() => {
       mock.onGet().reply(200, {
@@ -1032,7 +1034,10 @@ describe('NFT module', () => {
     });
 
     it('calls with the correct parameters', async () => {
-      await alchemy.nft.getOwnersForNft(contractAddress, tokenIdHex);
+      await alchemy.nft.getOwnersForNft(contractAddress, tokenIdHex, {
+        pageKey,
+        pageSize
+      });
       expect(mock.history.get.length).toEqual(1);
       expect(mock.history.get[0].params).toHaveProperty(
         'contractAddress',
@@ -1042,6 +1047,8 @@ describe('NFT module', () => {
         'tokenId',
         tokenIdNumber
       );
+      expect(mock.history.get[0].params).toHaveProperty('pageKey', pageKey);
+      expect(mock.history.get[0].params).toHaveProperty('pageSize', pageSize);
 
       const response = await alchemy.nft.getOwnersForNft(
         contractAddress,