Repository: settlemint/sdk
Pull request #960: fix: improved docs
Author: login: janb87
Labels: name: fix
description: Bug fix
Created: 2025-04-30T16:15:10Z | Merged: 2025-04-30T16:35:20Z

## Summary by Sourcery

Improve documentation and examples for the SettleMint Smart Contract Portal SDK, focusing on enhancing code examples, documentation clarity, and adding more comprehensive explanations for SDK usage.

Enhancements:
- Updated example scripts with more comprehensive logging and error handling
- Added contract retrieval example to deployment script
- Sorted example files for consistent documentation generation

Documentation:
- Reorganized README.md table of contents
- Added detailed comments and explanations to code examples
- Improved documentation for waitForTransactionReceipt function

Tests:
- Added additional assertions for contract deployment and retrieval in end-to-end tests


Diff:
diff --git a/scripts/generate-readme.ts b/scripts/generate-readme.ts
index d1619b868..83821c603 100644
--- a/scripts/generate-readme.ts
+++ b/scripts/generate-readme.ts
@@ -54,7 +54,8 @@ async function generateReadme() {
         : [];
       const exampleFiles = exampleDirContents
         .filter((entry) => entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")))
-        .map((entry) => join(entry.parentPath, entry.name));
+        .map((entry) => join(entry.parentPath, entry.name))
+        .sort((a, b) => a.localeCompare(b));
       const examples =
         exampleFiles.length > 0
           ? await Promise.all(
diff --git a/sdk/portal/README.md b/sdk/portal/README.md
index 92ecc47ca..d2e36b7b7 100644
--- a/sdk/portal/README.md
+++ b/sdk/portal/README.md
@@ -28,9 +28,9 @@
 
 - [About](#about)
 - [Examples](#examples)
+  - [Deploy contract](#deploy-contract)
   - [Get pending transactions](#get-pending-transactions)
   - [Send transaction using hd wallet](#send-transaction-using-hd-wallet)
-  - [Deploy contract](#deploy-contract)
 - [API Reference](#api-reference)
   - [Functions](#functions)
     - [createPortalClient()](#createportalclient)
@@ -55,9 +55,131 @@ The SettleMint Smart Contract Portal SDK provides a seamless way to interact wit
 The SDK offers a type-safe interface for all Portal API operations, with comprehensive error handling and validation. It integrates smoothly with modern TypeScript applications while providing a simple and intuitive developer experience.
 ## Examples
 
+### Deploy contract
+
+```ts
+/**
+ * This example demonstrates how to deploy a contract.
+ *
+ * The process involves:
+ * 1. Creating a portal client
+ * 2. Deploying a forwarder contract
+ * 3. Waiting for the forwarder contract deployment to be finalized
+ * 4. Deploying a stablecoin factory contract
+ * 5. Getting all contracts and filtering by ABI name
+ *
+ * This pattern is useful for applications that need to deploy smart contracts
+ * in the SettleMint Portal, providing a way to track the progress of blockchain operations.
+ */
+import { loadEnv } from "@settlemint/sdk-utils/environment";
+import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
+import { getAddress } from "viem";
+import { createPortalClient } from "../portal.js"; // Replace this path with "@settlemint/sdk-portal"
+import { waitForTransactionReceipt } from "../utils/wait-for-transaction-receipt.js";
+import type { introspection } from "./schemas/portal-env.d.ts"; // Replace this path with the generated introspection type
+
+const env = await loadEnv(false, false);
+const logger = createLogger();
+
+const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
+  introspection: introspection;
+  disableMasking: true;
+  scalars: {
+    // Change unknown to the type you are using to store metadata
+    JSON: unknown;
+  };
+}>(
+  {
+    instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
+    accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
+  },
+  {
+    fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
+  },
+);
+
+// Replace with the address of your private key which you use to deploy smart contracts
+const FROM = getAddress("0x4B03331cF2db1497ec58CAa4AFD8b93611906960");
+
+/**
+ * Deploy a forwarder contract
+ */
+const deployForwarder = await portalClient.request(
+  portalGraphql(`
+    mutation DeployContractForwarder($from: String!) {
+      DeployContractForwarder(from: $from, gasLimit: "0x3d0900") {
+        transactionHash
+      }
+    }
+  `),
+  {
+    from: FROM,
+  },
+);
+
+/**
+ * Wait for the forwarder contract deployment to be finalized
+ */
+const transaction = await waitForTransactionReceipt(deployForwarder.DeployContractForwarder?.transactionHash!, {
+  portalGraphqlEndpoint: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
+  accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
+});
+
+/**
+ * Deploy a stablecoin factory contract
+ */
+const deployStableCoinFactory = await portalClient.request(
+  portalGraphql(`
+    mutation DeployContractStableCoinFactory($from: String!, $constructorArguments: DeployContractStableCoinFactoryInput!) {
+      DeployContractStableCoinFactory(from: $from, constructorArguments: $constructorArguments, gasLimit: "0x3d0900") {
+        transactionHash
+      }
+    }
+  `),
+  {
+    from: FROM,
+    constructorArguments: {
+      forwarder: getAddress(transaction?.receipt.contractAddress!),
+    },
+  },
+);
+
+console.log(deployStableCoinFactory?.DeployContractStableCoinFactory?.transactionHash);
+
+const contractAddresses = await portalClient.request(
+  portalGraphql(`
+    query GetContracts {
+        getContracts {
+            count
+            records {
+                address
+                abiName
+                createdAt
+            }
+        }
+    }
+  `),
+);
+// Print total count
+console.log(`Total contracts: ${contractAddresses.getContracts?.count}`);
+
+// Contracts for StableCoinFactory
+console.log(contractAddresses.getContracts?.records.filter((record) => record.abiName === "StableCoinFactory"));
+
+```
 ### Get pending transactions
 
 ```ts
+/**
+ * This example demonstrates how to get the number of pending transactions.
+ *
+ * The process involves:
+ * 1. Creating a portal client
+ * 2. Making a GraphQL query to get the number of pending transactions
+ *
+ * This pattern is useful for applications that need to monitor the status of pending transactions
+ * in the SettleMint Portal, providing a way to track the progress of blockchain operations.
+ */
 import { loadEnv } from "@settlemint/sdk-utils/environment";
 import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
 import { createPortalClient } from "../portal.js"; // Replace this path with "@settlemint/sdk-portal"
@@ -99,6 +221,19 @@ console.log(`There are ${result.getPendingTransactions?.count} pending transacti
 ### Send transaction using hd wallet
 
 ```ts
+/**
+ * This example demonstrates how to send a transaction using an HD wallet.
+ *
+ * The process involves:
+ * 1. Creating a wallet for a user using the HD private key
+ * 2. Setting up a pincode for wallet verification
+ * 3. Handling the wallet verification challenge
+ * 4. Sending a transaction to the blockchain
+ *
+ * This pattern is useful for applications that need to manage multiple user wallets
+ * derived from a single HD wallet, providing a secure and scalable approach to
+ * blockchain interactions in enterprise applications.
+ */
 import { loadEnv } from "@settlemint/sdk-utils/environment";
 import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
 import type { Address } from "viem";
@@ -221,85 +356,6 @@ const result = await portalClient.request(
 // Log the transaction hash
 console.log("Transaction hash:", result.StableCoinFactoryCreate?.transactionHash);
 
-```
-### Deploy contract
-
-```ts
-import { loadEnv } from "@settlemint/sdk-utils/environment";
-import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
-import { getAddress } from "viem";
-import { createPortalClient } from "../portal.js"; // Replace this path with "@settlemint/sdk-portal"
-import { waitForTransactionReceipt } from "../utils/wait-for-transaction-receipt.js";
-import type { introspection } from "./schemas/portal-env.d.ts"; // Replace this path with the generated introspection type
-
-const env = await loadEnv(false, false);
-const logger = createLogger();
-
-const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
-  introspection: introspection;
-  disableMasking: true;
-  scalars: {
-    // Change unknown to the type you are using to store metadata
-    JSON: unknown;
-  };
-}>(
-  {
-    instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
-    accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
-  },
-  {
-    fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
-  },
-);
-
-// Replace with the address of your private key which you use to deploy smart contracts
-const FROM = getAddress("0x4B03331cF2db1497ec58CAa4AFD8b93611906960");
-
-/**
- * Deploy a forwarder contract
- */
-const deployForwarder = await portalClient.request(
-  portalGraphql(`
-    mutation DeployContractForwarder($from: String!) {
-      DeployContractForwarder(from: $from, gasLimit: "0x3d0900") {
-        transactionHash
-      }
-    }
-  `),
-  {
-    from: FROM,
-  },
-);
-
-/**
- * Wait for the forwarder contract deployment to be finalized
- */
-const transaction = await waitForTransactionReceipt(deployForwarder.DeployContractForwarder?.transactionHash!, {
-  portalGraphqlEndpoint: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
-  accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
-});
-
-/**
- * Deploy a stablecoin factory contract
- */
-const deployStableCoinFactory = await portalClient.request(
-  portalGraphql(`
-    mutation DeployContractStableCoinFactory($from: String!, $constructorArguments: DeployContractStableCoinFactoryInput!) {
-      DeployContractStableCoinFactory(from: $from, constructorArguments: $constructorArguments, gasLimit: "0x3d0900") {
-        transactionHash
-      }
-    }
-  `),
-  {
-    from: FROM,
-    constructorArguments: {
-      forwarder: getAddress(transaction?.receipt.contractAddress!),
-    },
-  },
-);
-
-console.log(deployStableCoinFactory?.DeployContractStableCoinFactory?.transactionHash);
-
 ```
 
 ## API Reference
@@ -444,22 +500,39 @@ const result = await handleWalletVerificationChallenge({
 
 > **waitForTransactionReceipt**(`transactionHash`, `options`): `Promise`\<[`Transaction`](#transaction)\>
 
-Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:70](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L70)
+Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:82](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L82)
 
-Wait for the transaction receipt
+Waits for a blockchain transaction receipt by subscribing to transaction updates via GraphQL.
+This function polls until the transaction is confirmed or the timeout is reached.
 
 ##### Parameters
 
 | Parameter | Type | Description |
 | ------ | ------ | ------ |
-| `transactionHash` | `string` | transaction hash |
-| `options` | [`WaitForTransactionReceiptOptions`](#waitfortransactionreceiptoptions) | options |
+| `transactionHash` | `string` | The hash of the transaction to wait for |
+| `options` | [`WaitForTransactionReceiptOptions`](#waitfortransactionreceiptoptions) | Configuration options for the waiting process |
 
 ##### Returns
 
 `Promise`\<[`Transaction`](#transaction)\>
 
-receipt
+The transaction details including receipt information when the transaction is confirmed
+
+##### Throws
+
+Error if the transaction receipt cannot be retrieved within the specified timeout
+
+##### Example
+
+```ts
+import { waitForTransactionReceipt } from "@settlemint/sdk-portal";
+
+const transaction = await waitForTransactionReceipt("0x123...", {
+  portalGraphqlEndpoint: "https://example.settlemint.com/graphql",
+  accessToken: "your-access-token",
+  timeout: 30000 // 30 seconds timeout
+});
+```
 
 ### Interfaces
 
diff --git a/sdk/portal/src/examples/deploy-contract.ts b/sdk/portal/src/examples/deploy-contract.ts
index e94cef731..444567fb4 100644
--- a/sdk/portal/src/examples/deploy-contract.ts
+++ b/sdk/portal/src/examples/deploy-contract.ts
@@ -1,3 +1,16 @@
+/**
+ * This example demonstrates how to deploy a contract.
+ *
+ * The process involves:
+ * 1. Creating a portal client
+ * 2. Deploying a forwarder contract
+ * 3. Waiting for the forwarder contract deployment to be finalized
+ * 4. Deploying a stablecoin factory contract
+ * 5. Getting all contracts and filtering by ABI name
+ *
+ * This pattern is useful for applications that need to deploy smart contracts
+ * in the SettleMint Portal, providing a way to track the progress of blockchain operations.
+ */
 import { loadEnv } from "@settlemint/sdk-utils/environment";
 import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
 import { getAddress } from "viem";
@@ -72,3 +85,23 @@ const deployStableCoinFactory = await portalClient.request(
 );
 
 console.log(deployStableCoinFactory?.DeployContractStableCoinFactory?.transactionHash);
+
+const contractAddresses = await portalClient.request(
+  portalGraphql(`
+    query GetContracts {
+        getContracts {
+            count
+            records {
+                address
+                abiName
+                createdAt
+            }
+        }
+    }
+  `),
+);
+// Print total count
+console.log(`Total contracts: ${contractAddresses.getContracts?.count}`);
+
+// Contracts for StableCoinFactory
+console.log(contractAddresses.getContracts?.records.filter((record) => record.abiName === "StableCoinFactory"));
diff --git a/sdk/portal/src/examples/get-pending-transactions.ts b/sdk/portal/src/examples/get-pending-transactions.ts
index d72f04def..0f148d024 100644
--- a/sdk/portal/src/examples/get-pending-transactions.ts
+++ b/sdk/portal/src/examples/get-pending-transactions.ts
@@ -1,3 +1,13 @@
+/**
+ * This example demonstrates how to get the number of pending transactions.
+ *
+ * The process involves:
+ * 1. Creating a portal client
+ * 2. Making a GraphQL query to get the number of pending transactions
+ *
+ * This pattern is useful for applications that need to monitor the status of pending transactions
+ * in the SettleMint Portal, providing a way to track the progress of blockchain operations.
+ */
 import { loadEnv } from "@settlemint/sdk-utils/environment";
 import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
 import { createPortalClient } from "../portal.js"; // Replace this path with "@settlemint/sdk-portal"
diff --git a/sdk/portal/src/examples/send-transaction-using-hd-wallet.ts b/sdk/portal/src/examples/send-transaction-using-hd-wallet.ts
index bb4bc1340..d1c43ad59 100644
--- a/sdk/portal/src/examples/send-transaction-using-hd-wallet.ts
+++ b/sdk/portal/src/examples/send-transaction-using-hd-wallet.ts
@@ -1,3 +1,16 @@
+/**
+ * This example demonstrates how to send a transaction using an HD wallet.
+ *
+ * The process involves:
+ * 1. Creating a wallet for a user using the HD private key
+ * 2. Setting up a pincode for wallet verification
+ * 3. Handling the wallet verification challenge
+ * 4. Sending a transaction to the blockchain
+ *
+ * This pattern is useful for applications that need to manage multiple user wallets
+ * derived from a single HD wallet, providing a secure and scalable approach to
+ * blockchain interactions in enterprise applications.
+ */
 import { loadEnv } from "@settlemint/sdk-utils/environment";
 import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
 import type { Address } from "viem";
diff --git a/sdk/portal/src/utils/wait-for-transaction-receipt.ts b/sdk/portal/src/utils/wait-for-transaction-receipt.ts
index 45189fd3a..f0f9cb8ed 100644
--- a/sdk/portal/src/utils/wait-for-transaction-receipt.ts
+++ b/sdk/portal/src/utils/wait-for-transaction-receipt.ts
@@ -62,10 +62,22 @@ export interface WaitForTransactionReceiptOptions {
 }
 
 /**
- * Wait for the transaction receipt
- * @param transactionHash transaction hash
- * @param options options
- * @returns receipt
+ * Waits for a blockchain transaction receipt by subscribing to transaction updates via GraphQL.
+ * This function polls until the transaction is confirmed or the timeout is reached.
+ *
+ * @param transactionHash - The hash of the transaction to wait for
+ * @param options - Configuration options for the waiting process
+ * @returns The transaction details including receipt information when the transaction is confirmed
+ * @throws Error if the transaction receipt cannot be retrieved within the specified timeout
+ *
+ * @example
+ * import { waitForTransactionReceipt } from "@settlemint/sdk-portal";
+ *
+ * const transaction = await waitForTransactionReceipt("0x123...", {
+ *   portalGraphqlEndpoint: "https://example.settlemint.com/graphql",
+ *   accessToken: "your-access-token",
+ *   timeout: 30000 // 30 seconds timeout
+ * });
  */
 export async function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions) {
   const wsClient = createClient({
diff --git a/test/portal.e2e.test.ts b/test/portal.e2e.test.ts
index 5f350d0c1..6234f2b32 100644
--- a/test/portal.e2e.test.ts
+++ b/test/portal.e2e.test.ts
@@ -95,6 +95,29 @@ describe("Portal E2E Tests", () => {
         },
       );
       expect(deployStableCoinFactory.DeployContractStableCoinFactory?.transactionHash).toBeString();
+
+      const contractAddresses = await portalClient.request(
+        portalGraphql(`
+          query GetContracts {
+              getContracts {
+                  count
+                  records {
+                      address
+                      abiName
+                      createdAt
+                  }
+              }
+          }
+        `),
+      );
+
+      expect(contractAddresses.getContracts?.count).toBeGreaterThan(0);
+      expect(contractAddresses.getContracts?.records).toBeArray();
+      expect(
+        contractAddresses.getContracts?.records.some(
+          (record) => record.address === transaction?.receipt.contractAddress,
+        ),
+      ).toBeTrue();
     },
     { timeout: 60_000 },
   );
diff --git a/turbo.json b/turbo.json
index 8b2b383ab..e3120bc3a 100644
--- a/turbo.json
+++ b/turbo.json
@@ -52,12 +52,17 @@
     },
     "docs": {
       "dependsOn": ["^build", "codegen"],
-      "inputs": ["src/**", "scripts/create-docs.ts", "../../typedoc.config.mjs", "../../package.json", "examples/**"],
+      "inputs": ["src/**", "scripts/create-docs.ts", "../../typedoc.config.mjs", "../../package.json"],
       "outputs": ["docs/**", "!docs/ABOUT.md"]
     },
     "//#generate-readme": {
       "dependsOn": ["^build"],
-      "inputs": ["scripts/generate-readme.ts", "scripts/templates/README-template.md", "sdk/**/docs/**"],
+      "inputs": [
+        "scripts/generate-readme.ts",
+        "scripts/templates/README-template.md",
+        "sdk/**/docs/**",
+        "sdk/**/examples/**"
+      ],
       "outputs": ["sdk/**/README.md"]
     }
   }


Reviews:
user: login: sourcery-ai[bot]
body: Hey @janb87 - I've reviewed your changes - here's some feedback:

- Consider updating the PR title and description to reflect the functional changes made to the `deploy-contract` example and the e2e tests, not just documentation improvements.

<details>
<summary>Here's what I looked at during the review</summary>

- 🟢 **General issues**: all looks good
- 🟢 **Security**: all looks good
- 🟡 **Review instructions**: 2 issues found
- 🟡 **Testing**: 1 issue found
- 🟢 **Complexity**: all looks good
- 🟢 **Documentation**: all looks good
</details>

***

<details>
<summary>Sourcery is free for open source - if you like our reviews please consider sharing them ✨</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https://sourcery.ai)
- [Facebook](https://www.facebook.com/sharer/sharer.php?u=https://sourcery.ai)

</details>

<sub>
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
</sub>
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T16:16:33Z

Review comments:
diff_hunk: @@ -95,6 +95,29 @@ describe("Portal E2E Tests", () => {
         },
       );
       expect(deployStableCoinFactory.DeployContractStableCoinFactory?.transactionHash).toBeString();
+
+      const contractAddresses = await portalClient.request(
+        portalGraphql(`
+          query GetContracts {
+              getContracts {
+                  count
+                  records {
+                      address
+                      abiName
+                      createdAt
+                  }
+              }
+          }
+        `),
+      );
+
+      expect(contractAddresses.getContracts?.count).toBeGreaterThan(0);
+      expect(contractAddresses.getContracts?.records).toBeArray();
+      expect(
+        contractAddresses.getContracts?.records.some(
+          (record) => record.address === transaction?.receipt.contractAddress,
+        ),
+      ).toBeTrue();
path: test/portal.e2e.test.ts
user: login: sourcery-ai[bot]
body: **suggestion (testing):** Consider adding an assertion for `transaction?.receipt.contractAddress` before use

Assert that `transaction?.receipt.contractAddress` is defined before the `some` check to avoid confusing failures if it's null or undefined.

```suggestion
      expect(contractAddresses.getContracts?.records).toBeArray();
      expect(transaction?.receipt.contractAddress).toBeDefined();
      expect(
        contractAddresses.getContracts?.records.some(
          (record) => record.address === transaction?.receipt.contractAddress,
        ),
      ).toBeTrue();
```
created_at: 2025-04-30T16:16:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -72,3 +85,23 @@ const deployStableCoinFactory = await portalClient.request(
 );
 
 console.log(deployStableCoinFactory?.DeployContractStableCoinFactory?.transactionHash);
+
+const contractAddresses = await portalClient.request(
+  portalGraphql(`
+    query GetContracts {
+        getContracts {
+            count
+            records {
+                address
+                abiName
+                createdAt
+            }
+        }
+    }
+  `),
+);
+// Print total count
+console.log(`Total contracts: ${contractAddresses.getContracts?.count}`);
path: sdk/portal/src/examples/deploy-contract.ts
user: login: sourcery-ai[bot]
body: **suggestion (review_instructions):** Consider adding error handling for the case when contractAddresses.getContracts is undefined.

The optional chaining operator is used for accessing count, but if getContracts itself is undefined, this could lead to unexpected output. Consider adding a null check or providing a fallback value for more robust code.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*.ts`

**Instructions:**
Always write correct, up to date, bug free, fully functional and working, secure, performant and efficient code.

</details>
created_at: 2025-04-30T16:16:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -72,3 +85,23 @@ const deployStableCoinFactory = await portalClient.request(
 );
 
 console.log(deployStableCoinFactory?.DeployContractStableCoinFactory?.transactionHash);
+
+const contractAddresses = await portalClient.request(
+  portalGraphql(`
+    query GetContracts {
+        getContracts {
+            count
+            records {
+                address
+                abiName
+                createdAt
+            }
+        }
+    }
+  `),
+);
+// Print total count
+console.log(`Total contracts: ${contractAddresses.getContracts?.count}`);
+
+// Contracts for StableCoinFactory
+console.log(contractAddresses.getContracts?.records.filter((record) => record.abiName === "StableCoinFactory"));
path: sdk/portal/src/examples/deploy-contract.ts
user: login: sourcery-ai[bot]
body: **issue (review_instructions):** This line lacks proper error handling if getContracts is undefined or records is missing.

While optional chaining is used for getContracts, if it's undefined, attempting to access records will cause a runtime error. Consider using optional chaining for records as well: contractAddresses.getContracts?.records?.filter(...) or adding a conditional check before this operation.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*.ts`

**Instructions:**
Always write correct, up to date, bug free, fully functional and working, secure, performant and efficient code.

</details>
created_at: 2025-04-30T16:16:33Z
author_association: CONTRIBUTOR

PR comments:
user: login: sourcery-ai[bot]
created_at: 2025-04-30T16:15:15Z
body: <!-- Generated by sourcery-ai[bot]: start review_guide -->

## Reviewer's Guide

This pull request improves documentation by adding detailed JSDoc comments to code examples and the `waitForTransactionReceipt` utility function, regenerating the `README.md` to reflect these additions. It also enhances the `deploy-contract` example and its E2E test to demonstrate querying contracts post-deployment, and updates the README generation script to sort examples alphabetically.

### File-Level Changes

| Change | Details | Files |
| ------ | ------- | ----- |
| Added detailed JSDoc descriptions to code examples. | <ul><li>Added comprehensive JSDoc comments explaining purpose and steps.</li><li>Updated README.md to include these descriptions.</li><li>Reordered examples section in README TOC.</li></ul> | `sdk/portal/README.md`<br/>`sdk/portal/src/examples/deploy-contract.ts`<br/>`sdk/portal/src/examples/get-pending-transactions.ts`<br/>`sdk/portal/src/examples/send-transaction-using-hd-wallet.ts` |
| Updated API documentation for `waitForTransactionReceipt`. | <ul><li>Expanded JSDoc for the function with details on parameters, return value, exceptions, and usage example.</li><li>Regenerated README.md API reference section.</li></ul> | `sdk/portal/README.md`<br/>`sdk/portal/src/utils/wait-for-transaction-receipt.ts` |
| Added contract query step to deployment example and test. | <ul><li>Added `getContracts` GraphQL query after contract deployment.</li><li>Included logging/assertions to verify the deployed contract.</li></ul> | `sdk/portal/src/examples/deploy-contract.ts`<br/>`test/portal.e2e.test.ts` |
| Sorted examples in README generation script. | <ul><li>Applied alphabetical sorting to example files before processing.</li></ul> | `scripts/generate-readme.ts` |

---

<details>
<summary>Tips and commands</summary>

#### Interacting with Sourcery

- **Trigger a new review:** Comment `@sourcery-ai review` on the pull request.
- **Continue discussions:** Reply directly to Sourcery's review comments.
- **Generate a GitHub issue from a review comment:** Ask Sourcery to create an
  issue from a review comment by replying to it. You can also reply to a
  review comment with `@sourcery-ai issue` to create an issue from it.
- **Generate a pull request title:** Write `@sourcery-ai` anywhere in the pull
  request title to generate a title at any time. You can also comment
  `@sourcery-ai title` on the pull request to (re-)generate the title at any time.
- **Generate a pull request summary:** Write `@sourcery-ai summary` anywhere in
  the pull request body to generate a PR summary at any time exactly where you
  want it. You can also comment `@sourcery-ai summary` on the pull request to
  (re-)generate the summary at any time.
- **Generate reviewer's guide:** Comment `@sourcery-ai guide` on the pull
  request to (re-)generate the reviewer's guide at any time.
- **Resolve all Sourcery comments:** Comment `@sourcery-ai resolve` on the
  pull request to resolve all Sourcery comments. Useful if you've already
  addressed all the comments and don't want to see them anymore.
- **Dismiss all Sourcery reviews:** Comment `@sourcery-ai dismiss` on the pull
  request to dismiss all existing Sourcery reviews. Especially useful if you
  want to start fresh with a new review - don't forget to comment
  `@sourcery-ai review` to trigger a new review!

#### Customizing Your Experience

Access your [dashboard](https://app.sourcery.ai) to:
- Enable or disable review features such as the Sourcery-generated pull request
  summary, the reviewer's guide, and others.
- Change the review language.
- Add, remove or edit custom review instructions.
- Adjust other review settings.

#### Getting Help

- [Contact our support team](mailto:support@sourcery.ai) for questions or feedback.
- Visit our [documentation](https://docs.sourcery.ai) for detailed guides and information.
- Keep in touch with the Sourcery team by following us on [X/Twitter](https://x.com/SourceryAI), [LinkedIn](https://www.linkedin.com/company/sourcery-ai/) or [GitHub](https://github.com/sourcery-ai).

</details>

<!-- Generated by sourcery-ai[bot]: end review_guide -->
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-30T16:16:27Z
body: # 📦 Packages
| Package | NPM | Docker |
| ------- | -------------------- | -------------------- |
| SDK Cli | `@settlemint/sdk-cli@2.2.0-pra4a76212` |  |
| SDK The Graph | `@settlemint/sdk-thegraph@2.2.0-pra4a76212` |  |
| SDK Portal | `@settlemint/sdk-portal@2.2.0-pra4a76212` |  |
| SDK Hasura | `@settlemint/sdk-hasura@2.2.0-pra4a76212` |  |
| SDK JS | `@settlemint/sdk-js@2.2.0-pra4a76212` |  |
| SDK Utils | `@settlemint/sdk-utils@2.2.0-pra4a76212` | |
| SDK Next | `@settlemint/sdk-next@2.2.0-pra4a76212` | |
| SDK Minio | `@settlemint/sdk-minio@2.2.0-pra4a76212` | |
| SDK IPFS | `@settlemint/sdk-ipfs@2.2.0-pra4a76212` | |
| SDK Blockscout | `@settlemint/sdk-blockscout@2.2.0-pra4a76212` | |
| SDK MCP | `@settlemint/sdk-mcp@2.2.0-pra4a76212` | |

[^uniqueIdentifier]: Build, test and publish
author_association: NONE