Repository: Cardinal-Cryptography/zkOS-monorepo
Pull request #160: Return account states list
Author: login: kroist
Created: 2025-03-13T08:16:26Z | Merged: 2025-03-13T12:47:56Z

- add an endpoint which returns the list of all accounts state from storage, so the SDK user can easily retrieve them.
- remove `saveRawAccountAndIncrementNextAccountIndex` function and embed `accountIndex` increment in `saveRawAccount` function


Diff:
diff --git a/ts/shielder-sdk/__tests/client/client.test.ts b/ts/shielder-sdk/__tests/client/client.test.ts
index 324f7861..5b1b86ea 100644
--- a/ts/shielder-sdk/__tests/client/client.test.ts
+++ b/ts/shielder-sdk/__tests/client/client.test.ts
@@ -66,7 +66,8 @@ describe("ShielderClient", () => {
     } as unknown as Mocked<PublicClient>;
 
     mockAccountRegistry = {
-      getAccountState: vitest.fn()
+      getAccountState: vitest.fn(),
+      getAccountStatesList: vitest.fn()
     } as unknown as Mocked<AccountRegistry>;
 
     mockStateSynchronizer = {
@@ -216,6 +217,20 @@ describe("ShielderClient", () => {
     });
   });
 
+  describe("accountStatesList", () => {
+    it("should return account states list", async () => {
+      const mockAccountStates = [mockState];
+      mockAccountRegistry.getAccountStatesList.mockResolvedValue(
+        mockAccountStates
+      );
+
+      const accountStates = await client.accountStatesList();
+
+      expect(accountStates).toEqual(mockAccountStates);
+      expect(mockAccountRegistry.getAccountStatesList).toHaveBeenCalledTimes(1);
+    });
+  });
+
   describe("accountState", () => {
     it("should return current account state", async () => {
       const state = await client.accountState(nativeToken());
diff --git a/ts/shielder-sdk/__tests/state/accountRegistry.test.ts b/ts/shielder-sdk/__tests/state/accountRegistry.test.ts
index ad991201..9f04baa7 100644
--- a/ts/shielder-sdk/__tests/state/accountRegistry.test.ts
+++ b/ts/shielder-sdk/__tests/state/accountRegistry.test.ts
@@ -7,7 +7,7 @@ import { Scalar } from "@cardinal-cryptography/shielder-sdk-crypto";
 import { nativeToken, erc20Token } from "../../src/utils";
 import { AccountStateMerkleIndexed } from "../../src/state/types";
 import { Token } from "../../src/types";
-import { AccountObject } from "../../src/storage/storageSchema";
+import { AccountObject, createStorage } from "../../src/storage/storageSchema";
 
 const nativeTokenAddress = "0x0000000000000000000000000000000000000000";
 const testErc20Address = "0x1111111111111111111111111111111111111111";
@@ -165,9 +165,6 @@ describe("AccountRegistry", () => {
         accountIndex,
         mockAccountObject
       );
-      expect(
-        storageManager.saveRawAccountAndIncrementNextAccountIndex
-      ).not.toHaveBeenCalled();
     });
 
     it("should create new account state when not found", async () => {
@@ -200,10 +197,10 @@ describe("AccountRegistry", () => {
         accountState,
         nextAccountIndex
       );
-      expect(storageManager.saveRawAccount).not.toHaveBeenCalled();
-      expect(
-        storageManager.saveRawAccountAndIncrementNextAccountIndex
-      ).toHaveBeenCalledWith(nextAccountIndex, mockAccountObject);
+      expect(storageManager.saveRawAccount).toHaveBeenCalledWith(
+        nextAccountIndex,
+        mockAccountObject
+      );
     });
   });
 
@@ -238,4 +235,54 @@ describe("AccountRegistry", () => {
       });
     });
   });
+
+  describe("getAccountStatesList", () => {
+    beforeEach(() => {
+      const map = new Map<string, string>();
+      storageManager = new StorageManager(
+        createStorage({
+          getItem: async (key: string) => {
+            return map.get(key) ?? null;
+          },
+          setItem: async (key: string, value: string) => {
+            map.set(key, value);
+          }
+        })
+      );
+      accountRegistry = new AccountRegistry(
+        storageManager,
+        accountFactory,
+        accountStateSerde
+      );
+    });
+    it("should return list of account states", async () => {
+      const accountObject = createMockAccountObject();
+      const token = nativeToken();
+      const accountState = createMockAccountState(token);
+      const accountObject2 = createMockAccountObject(testErc20Address);
+      const token2 = erc20Token(testErc20Address);
+      const accountState2 = createMockAccountState(token2);
+
+      await storageManager.saveRawAccount(0, accountObject);
+      await storageManager.saveRawAccount(1, accountObject2);
+
+      vi.mocked(accountStateSerde.toAccountState)
+        .mockResolvedValueOnce(accountState)
+        .mockResolvedValueOnce(accountState2);
+
+      const result = await accountRegistry.getAccountStatesList();
+
+      expect(result).toEqual([accountState, accountState2]);
+      expect(accountStateSerde.toAccountState).toHaveBeenCalledWith(
+        accountObject,
+        0,
+        token
+      );
+      expect(accountStateSerde.toAccountState).toHaveBeenCalledWith(
+        accountObject2,
+        1,
+        token2
+      );
+    });
+  });
 });
diff --git a/ts/shielder-sdk/__tests/storage/storageManager.test.ts b/ts/shielder-sdk/__tests/storage/storageManager.test.ts
index e299b370..dba59d8d 100644
--- a/ts/shielder-sdk/__tests/storage/storageManager.test.ts
+++ b/ts/shielder-sdk/__tests/storage/storageManager.test.ts
@@ -89,11 +89,13 @@ describe("StorageManager", () => {
       // Check that the account was added to the map
       const setStorageCall = mockStorage.setStorage.mock.calls[0][0];
       expect(setStorageCall.accounts.get("0")).toEqual(sampleAccount);
+      expect(setStorageCall.nextAccountIndex).toBe(1);
     });
 
     it("should update an existing account", async () => {
       // Add an initial account
       mockStorageData.accounts.set("0", { ...sampleAccount, balance: 500n });
+      mockStorageData.nextAccountIndex = 1;
 
       // Update the account
       await storageManager.saveRawAccount(0, sampleAccount);
@@ -104,16 +106,15 @@ describe("StorageManager", () => {
       // Check that the account was updated
       const setStorageCall = mockStorage.setStorage.mock.calls[0][0];
       expect(setStorageCall.accounts.get("0")).toEqual(sampleAccount);
+      expect(setStorageCall.nextAccountIndex).toBe(1);
     });
 
-    it("should handle storage errors", async () => {
-      mockStorage.setStorage.mockRejectedValueOnce(new Error("Storage error"));
-
+    it("should throw an error if the account index is greater than the next account index", async () => {
       await expect(
-        storageManager.saveRawAccount(0, sampleAccount)
-      ).rejects.toThrow("Storage error");
-      expect(mockStorage.getStorage).toHaveBeenCalledTimes(1);
-      expect(mockStorage.setStorage).toHaveBeenCalledTimes(1);
+        storageManager.saveRawAccount(2, sampleAccount)
+      ).rejects.toThrow(
+        "Cannot save account at index 2 when next account index is 1"
+      );
     });
   });
 
@@ -136,39 +137,6 @@ describe("StorageManager", () => {
     });
   });
 
-  describe("saveRawAccountAndIncrementNextAccountIndex", () => {
-    it("should save account and increment next account index", async () => {
-      mockStorageData.nextAccountIndex = 1;
-
-      await storageManager.saveRawAccountAndIncrementNextAccountIndex(
-        0,
-        sampleAccount
-      );
-
-      expect(mockStorage.getStorage).toHaveBeenCalledTimes(1);
-      expect(mockStorage.setStorage).toHaveBeenCalledTimes(1);
-
-      // Check that the account was added and index incremented
-      const setStorageCall = mockStorage.setStorage.mock.calls[0][0];
-      expect(setStorageCall.accounts.get("0")).toEqual(sampleAccount);
-      expect(setStorageCall.nextAccountIndex).toBe(2);
-    });
-
-    it("should handle storage errors", async () => {
-      mockStorage.setStorage.mockRejectedValueOnce(new Error("Storage error"));
-
-      await expect(
-        storageManager.saveRawAccountAndIncrementNextAccountIndex(
-          0,
-          sampleAccount
-        )
-      ).rejects.toThrow("Storage error");
-
-      expect(mockStorage.getStorage).toHaveBeenCalledTimes(1);
-      expect(mockStorage.setStorage).toHaveBeenCalledTimes(1);
-    });
-  });
-
   describe("findAccountByTokenAddress", () => {
     it("should return null when no account with the token address exists", async () => {
       const result = await storageManager.findAccountByTokenAddress("0x1234");
diff --git a/ts/shielder-sdk/package.json b/ts/shielder-sdk/package.json
index 3ceae593..ec4bd0b4 100644
--- a/ts/shielder-sdk/package.json
+++ b/ts/shielder-sdk/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@cardinal-cryptography/shielder-sdk",
-  "version": "0.2.0-beta.2",
+  "version": "0.2.0-beta.3",
   "description": "A web package for interacting with Shielder, a part of zkOS privacy engine.",
   "license": "Apache-2.0",
   "keywords": [
diff --git a/ts/shielder-sdk/src/client/client.ts b/ts/shielder-sdk/src/client/client.ts
index 46dfe549..b6f40722 100644
--- a/ts/shielder-sdk/src/client/client.ts
+++ b/ts/shielder-sdk/src/client/client.ts
@@ -55,6 +55,14 @@ export class ShielderClient {
     }
   }
 
+  /**
+   * Get the list of all account states.
+   * @returns the list of all account states
+   */
+  async accountStatesList() {
+    return await this.accountRegistry.getAccountStatesList();
+  }
+
   /**
    * Get the current account state for token.
    * @param {Token} token - token to get the account state for
diff --git a/ts/shielder-sdk/src/state/accountRegistry.ts b/ts/shielder-sdk/src/state/accountRegistry.ts
index 8dfdbc74..77102acb 100644
--- a/ts/shielder-sdk/src/state/accountRegistry.ts
+++ b/ts/shielder-sdk/src/state/accountRegistry.ts
@@ -51,31 +51,15 @@ export class AccountRegistry {
     const indexedAccount =
       await this.storageManager.findAccountByTokenAddress(tokenAddress);
 
-    if (indexedAccount !== null) {
-      // Existing account
-      const { accountIndex } = indexedAccount;
-      const accountObject = await this.accountStateSerde.toAccountObject(
-        accountState,
-        accountIndex
-      );
-
-      // Save
-      await this.storageManager.saveRawAccount(accountIndex, accountObject);
-    } else {
-      // New account
-      const accountIndex = await this.storageManager.getNextAccountIndex();
+    const { accountIndex } = indexedAccount ?? {
+      accountIndex: await this.storageManager.getNextAccountIndex()
+    };
 
-      const accountObject = await this.accountStateSerde.toAccountObject(
-        accountState,
-        accountIndex
-      );
-
-      // Save and increment index
-      await this.storageManager.saveRawAccountAndIncrementNextAccountIndex(
-        accountIndex,
-        accountObject
-      );
-    }
+    const accountObject = await this.accountStateSerde.toAccountObject(
+      accountState,
+      accountIndex
+    );
+    await this.storageManager.saveRawAccount(accountIndex, accountObject);
   }
 
   async getTokenByAccountIndex(accountIndex: number): Promise<Token | null> {
@@ -87,4 +71,18 @@ export class AccountRegistry {
 
     return null;
   }
+
+  async getAccountStatesList(): Promise<AccountStateMerkleIndexed[]> {
+    const accounts = await this.storageManager.getAllAccounts();
+
+    return Promise.all(
+      accounts.map(({ accountIndex, accountObject }) =>
+        this.accountStateSerde.toAccountState(
+          accountObject,
+          accountIndex,
+          getTokenByAddress(accountObject.tokenAddress as `0x${string}`)
+        )
+      )
+    );
+  }
 }
diff --git a/ts/shielder-sdk/src/storage/storageManager.ts b/ts/shielder-sdk/src/storage/storageManager.ts
index 86a1ca8e..c9f89113 100644
--- a/ts/shielder-sdk/src/storage/storageManager.ts
+++ b/ts/shielder-sdk/src/storage/storageManager.ts
@@ -19,6 +19,13 @@ export class StorageManager {
    */
   async saveRawAccount(index: number, account: AccountObject): Promise<void> {
     const storageData = await this.storage.getStorage();
+    if (index === storageData.nextAccountIndex) {
+      storageData.nextAccountIndex += 1;
+    } else if (index > storageData.nextAccountIndex) {
+      throw new Error(
+        `Cannot save account at index ${index} when next account index is ${storageData.nextAccountIndex}`
+      );
+    }
     storageData.accounts.set(index.toString(), { ...account });
     await this.storage.setStorage(storageData);
   }
@@ -31,19 +38,6 @@ export class StorageManager {
     return storageData.nextAccountIndex;
   }
 
-  /**
-   * Increments the next account index
-   */
-  async saveRawAccountAndIncrementNextAccountIndex(
-    index: number,
-    account: AccountObject
-  ): Promise<void> {
-    const storageData = await this.storage.getStorage();
-    storageData.accounts.set(index.toString(), { ...account });
-    storageData.nextAccountIndex += 1;
-    await this.storage.setStorage(storageData);
-  }
-
   /**
    * Finds an account index by token address
    */
@@ -64,4 +58,19 @@ export class StorageManager {
 
     return null;
   }
+
+  /**
+   * Gets all accounts
+   */
+  async getAllAccounts(): Promise<
+    { accountIndex: number; accountObject: AccountObject }[]
+  > {
+    const storageData = await this.storage.getStorage();
+    return Array.from(storageData.accounts.entries()).map(
+      ([index, account]) => ({
+        accountIndex: parseInt(index),
+        accountObject: { ...account }
+      })
+    );
+  }
 }


Reviews:
user: login: guspiel
body: LGTM
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T12:26:22Z
user: login: kroist
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T12:30:40Z
user: login: kroist
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T12:30:57Z
user: login: kroist
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T12:31:02Z

Review comments:
diff_hunk: @@ -20,6 +20,13 @@ export class StorageManager {
   async saveRawAccount(index: number, account: AccountObject): Promise<void> {
     const storageData = await this.storage.getStorage();
     storageData.accounts.set(index.toString(), { ...account });
+    if (index === storageData.nextAccountIndex) {
+      storageData.nextAccountIndex += 1;
+    } else if (index >= storageData.nextAccountIndex) {
+      throw new Error(
+        `Cannot save account at index ${index} when next account index is ${storageData.nextAccountIndex}`
path: ts/shielder-sdk/src/storage/storageManager.ts
user: login: guspiel
body: I think you mean `index > storageData.nextAccountIndex` and `Cannot save account at index ${index} when next account index is` **>>greater than<<** `${storageData.nextAccountIndex}`, right?
created_at: 2025-03-13T12:15:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -20,6 +20,13 @@ export class StorageManager {
   async saveRawAccount(index: number, account: AccountObject): Promise<void> {
     const storageData = await this.storage.getStorage();
     storageData.accounts.set(index.toString(), { ...account });
+    if (index === storageData.nextAccountIndex) {
+      storageData.nextAccountIndex += 1;
+    } else if (index >= storageData.nextAccountIndex) {
path: ts/shielder-sdk/src/storage/storageManager.ts
user: login: guspiel
body: nit: Consider putting the check before `storageData.accounts.set(index.toString(), { ...account });`. I know the `throw` prevents `storageData` from being saved, but it took me a minute to realize that.
created_at: 2025-03-13T12:15:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -51,31 +51,16 @@ export class AccountRegistry {
     const indexedAccount =
       await this.storageManager.findAccountByTokenAddress(tokenAddress);
 
-    if (indexedAccount !== null) {
-      // Existing account
-      const { accountIndex } = indexedAccount;
-      const accountObject = await this.accountStateSerde.toAccountObject(
-        accountState,
-        accountIndex
-      );
-
-      // Save
-      await this.storageManager.saveRawAccount(accountIndex, accountObject);
-    } else {
-      // New account
-      const accountIndex = await this.storageManager.getNextAccountIndex();
+    const { accountIndex } = indexedAccount ?? {
+      accountIndex: await this.storageManager.getNextAccountIndex()
+    };
 
-      const accountObject = await this.accountStateSerde.toAccountObject(
-        accountState,
-        accountIndex
-      );
-
-      // Save and increment index
-      await this.storageManager.saveRawAccountAndIncrementNextAccountIndex(
-        accountIndex,
-        accountObject
-      );
-    }
+    const accountObject = await this.accountStateSerde.toAccountObject(
+      accountState,
+      accountIndex
+    );
+    // Save
path: ts/shielder-sdk/src/state/accountRegistry.ts
user: login: guspiel
body: nit: I'd really skip this comment now:P
created_at: 2025-03-13T12:23:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -20,6 +20,13 @@ export class StorageManager {
   async saveRawAccount(index: number, account: AccountObject): Promise<void> {
     const storageData = await this.storage.getStorage();
     storageData.accounts.set(index.toString(), { ...account });
+    if (index === storageData.nextAccountIndex) {
+      storageData.nextAccountIndex += 1;
+    } else if (index >= storageData.nextAccountIndex) {
+      throw new Error(
+        `Cannot save account at index ${index} when next account index is ${storageData.nextAccountIndex}`
path: ts/shielder-sdk/src/storage/storageManager.ts
user: login: kroist
body: good catch
created_at: 2025-03-13T12:30:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -20,6 +20,13 @@ export class StorageManager {
   async saveRawAccount(index: number, account: AccountObject): Promise<void> {
     const storageData = await this.storage.getStorage();
     storageData.accounts.set(index.toString(), { ...account });
+    if (index === storageData.nextAccountIndex) {
+      storageData.nextAccountIndex += 1;
+    } else if (index >= storageData.nextAccountIndex) {
path: ts/shielder-sdk/src/storage/storageManager.ts
user: login: kroist
body: moved the check to the top
created_at: 2025-03-13T12:30:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -51,31 +51,16 @@ export class AccountRegistry {
     const indexedAccount =
       await this.storageManager.findAccountByTokenAddress(tokenAddress);
 
-    if (indexedAccount !== null) {
-      // Existing account
-      const { accountIndex } = indexedAccount;
-      const accountObject = await this.accountStateSerde.toAccountObject(
-        accountState,
-        accountIndex
-      );
-
-      // Save
-      await this.storageManager.saveRawAccount(accountIndex, accountObject);
-    } else {
-      // New account
-      const accountIndex = await this.storageManager.getNextAccountIndex();
+    const { accountIndex } = indexedAccount ?? {
+      accountIndex: await this.storageManager.getNextAccountIndex()
+    };
 
-      const accountObject = await this.accountStateSerde.toAccountObject(
-        accountState,
-        accountIndex
-      );
-
-      // Save and increment index
-      await this.storageManager.saveRawAccountAndIncrementNextAccountIndex(
-        accountIndex,
-        accountObject
-      );
-    }
+    const accountObject = await this.accountStateSerde.toAccountObject(
+      accountState,
+      accountIndex
+    );
+    // Save
path: ts/shielder-sdk/src/state/accountRegistry.ts
user: login: kroist
body: removed
created_at: 2025-03-13T12:31:02Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-13T08:25:42Z
body: <table><tr><th>Transaction Name</th><th>Main</th><th>Current</th><th>Difference (%)</th></tr><tr><td>NewAccount (gas)</td><td>1998665</td><td>1998605</td><td>-0.00300%</td></tr><tr><td>Deposit (gas)</td><td>1743091</td><td>1743151</td><td>+0.00344%</td></tr><tr><td>Withdraw (gas)</td><td>1861264</td><td>1861168</td><td>-0.00516%</td></tr><tr><td>Deposit (size)</td><td>20255</td><td>20255</td><td>0.00000%</td></tr><tr><td>Withdraw (size)</td><td>21574</td><td>21574</td><td>0.00000%</td></tr><tr><td>NewAccount (size)</td><td>22867</td><td>22867</td><td>0.00000%</td></tr></table>
<!-- thollander/actions-comment-pull-request "hashFiles('report.html')" -->
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-13T08:26:12Z
body: # 📊 Coverage Report

## 📈 Total Coverage Summary

| Type | Covered | Total | Coverage |
|------|---------|--------|----------|
| 📝 Lines | 1455 | 2056 | 🟠 70.76% |
| 📄 Statements | 1455 | 2056 | 🟠 70.76% |
| ⚡ Functions | 107 | 114 | 🟡 93.85% |
| 🔀 Branches | 263 | 273 | 🟡 96.33% |

### Coverage Legend

- ✅ 100% Coverage
- 🟡 80-99% Coverage
- 🟠 50-79% Coverage
- ❌ 0-49% Coverage

## 📁 File Coverage

<details>
<summary>📋 Detailed Coverage Report</summary>

| File | Lines | Statements | Functions | Branches |
|------|-------|------------|-----------|----------|
| 🟡 [zkOS-monorepo/ts/shielder-sdk/src/actions/deposit.ts](zkOS-monorepo/ts/shielder-sdk/src/actions/deposit.ts) | 88.28% | 88.28% | 100% | 85.71% |
| 🟡 [zkOS-monorepo/ts/shielder-sdk/src/actions/newAccount.ts](zkOS-monorepo/ts/shielder-sdk/src/actions/newAccount.ts) | 84.37% | 84.37% | 100% | 78.94% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/actions/types.ts](zkOS-monorepo/ts/shielder-sdk/src/actions/types.ts) | 100% | 100% | 100% | 100% |
| 🟡 [zkOS-monorepo/ts/shielder-sdk/src/actions/utils.ts](zkOS-monorepo/ts/shielder-sdk/src/actions/utils.ts) | 97.36% | 97.36% | 100% | 90.9% |
| 🟠 [zkOS-monorepo/ts/shielder-sdk/src/actions/withdraw.ts](zkOS-monorepo/ts/shielder-sdk/src/actions/withdraw.ts) | 76.41% | 76.41% | 87.5% | 100% |
| ❌ [zkOS-monorepo/ts/shielder-sdk/src/chain/contract.ts](zkOS-monorepo/ts/shielder-sdk/src/chain/contract.ts) | 1.92% | 1.92% | 0% | 0% |
| ❌ [zkOS-monorepo/ts/shielder-sdk/src/chain/relayer.ts](zkOS-monorepo/ts/shielder-sdk/src/chain/relayer.ts) | 14.91% | 14.91% | 0% | 0% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/client/actions.ts](zkOS-monorepo/ts/shielder-sdk/src/client/actions.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/client/client.ts](zkOS-monorepo/ts/shielder-sdk/src/client/client.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/client/factories.ts](zkOS-monorepo/ts/shielder-sdk/src/client/factories.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/client/types.ts](zkOS-monorepo/ts/shielder-sdk/src/client/types.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/constants.ts](zkOS-monorepo/ts/shielder-sdk/src/constants.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/errors.ts](zkOS-monorepo/ts/shielder-sdk/src/errors.ts) | 100% | 100% | 100% | 100% |
| ❌ [zkOS-monorepo/ts/shielder-sdk/src/index.ts](zkOS-monorepo/ts/shielder-sdk/src/index.ts) | 0% | 0% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/state/accountFactory.ts](zkOS-monorepo/ts/shielder-sdk/src/state/accountFactory.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/state/accountRegistry.ts](zkOS-monorepo/ts/shielder-sdk/src/state/accountRegistry.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/state/accountStateSerde.ts](zkOS-monorepo/ts/shielder-sdk/src/state/accountStateSerde.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/state/idManager.ts](zkOS-monorepo/ts/shielder-sdk/src/state/idManager.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/state/localStateTransition.ts](zkOS-monorepo/ts/shielder-sdk/src/state/localStateTransition.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/state/sync/chainStateTransition.ts](zkOS-monorepo/ts/shielder-sdk/src/state/sync/chainStateTransition.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/state/sync/historyFetcher.ts](zkOS-monorepo/ts/shielder-sdk/src/state/sync/historyFetcher.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/state/sync/synchronizer.ts](zkOS-monorepo/ts/shielder-sdk/src/state/sync/synchronizer.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/state/sync/tokenAccountFinder.ts](zkOS-monorepo/ts/shielder-sdk/src/state/sync/tokenAccountFinder.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/state/types.ts](zkOS-monorepo/ts/shielder-sdk/src/state/types.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/storage/storageManager.ts](zkOS-monorepo/ts/shielder-sdk/src/storage/storageManager.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/storage/storageSchema.ts](zkOS-monorepo/ts/shielder-sdk/src/storage/storageSchema.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/types.ts](zkOS-monorepo/ts/shielder-sdk/src/types.ts) | 100% | 100% | 100% | 100% |
| ✅ [zkOS-monorepo/ts/shielder-sdk/src/utils.ts](zkOS-monorepo/ts/shielder-sdk/src/utils.ts) | 100% | 100% | 100% | 100% |

</details>

<!-- Sticky Pull Request Comment -->
author_association: NONE