Skip to content

fix: update document store functions#132

Merged
rongquan1 merged 3 commits intomainfrom
fix/document-store-commands
Feb 25, 2026
Merged

fix: update document store functions#132
rongquan1 merged 3 commits intomainfrom
fix/document-store-commands

Conversation

@RishabhS7
Copy link
Copy Markdown
Contributor

@RishabhS7 RishabhS7 commented Feb 25, 2026

Summary

Fixes for document store function updates.
Types and tests fixes

Summary by CodeRabbit

  • New Features

    • Exposed new public APIs for role lookup and for transferring document-store ownership.
  • Improvements

    • Role resolution is now dynamic and validates that requested roles exist on the contract.
    • Ownership transfer performs pre-checks to avoid partial operations and provides clearer errors.
    • Transfer return values simplified for easier integration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 25, 2026

📝 Walkthrough

Walkthrough

Refactors role resolution to use dynamic contract-method lookup with validation, exposes getRoleString, updates transfer-ownership to await concrete transactions (not promises), adds Ethers v5/v6 and ABI/runtime contract selection, and updates role aliases to contract names (DEFAULT_ADMIN_ROLE, ISSUER_ROLE, REVOKER_ROLE).

Changes

Cohort / File(s) Summary
Role resolution
src/document-store/document-store-roles.ts
Replaced hardcoded role switch with dynamic contract-method lookup; rolesList now contains contract role names (DEFAULT_ADMIN_ROLE, ISSUER_ROLE, REVOKER_ROLE); throws "Invalid role" if contract lacks the named method; exported getRoleString.
Transfer ownership flow
src/document-store/transferOwnership.ts
Added Ethers v5/v6 typing and runtime ABI/contract selection; performs grant/revoke pre-checks via static calls before transactions; awaits and returns concrete `ContractTransactionV5
Public API exports
src/document-store/index.ts, src/index.ts
Exported getRoleString from document-store surface; re-exported getRoleString and documentStoreTransferOwnership from top-level src/index.ts.

Sequence Diagram(s)

sequenceDiagram
  participant Caller as Caller
  participant TransferFn as transferOwnership()
  participant Utils as getRoleString / helpers
  participant Provider as Provider
  participant Contract as DocumentStoreContract

  Caller->>TransferFn: call(documentStoreAddr, newOwner, ...)
  TransferFn->>Utils: getRoleString(documentStoreAddr, "DEFAULT_ADMIN_ROLE")
  TransferFn->>Provider: getEthersContractFromProvider(addr, ABI)
  TransferFn->>Contract: staticCall/grantRole pre-check
  Contract-->>TransferFn: pre-check OK / error
  TransferFn->>Contract: staticCall/revokeRole pre-check
  Contract-->>TransferFn: pre-check OK / error
  TransferFn->>Contract: send grantRole(tx)
  Contract-->>TransferFn: grant tx (ContractTransaction)
  TransferFn->>Contract: send revokeRole(tx)
  Contract-->>TransferFn: revoke tx (ContractTransaction)
  TransferFn-->>Caller: return { grantTransaction, revokeTransaction }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • rongquan1

Poem

🐇 I sniffed the roles across the chain,

DEFAULT_ADMIN now calls my name.
Grants and revokes in tidy rows,
Transactions landed — off I goes.
Hooray, new exports — hop, hop, prance! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is largely incomplete, missing critical details about changes and providing minimal context about the actual modifications made throughout the codebase. Expand description with specific details: explain the dynamic role resolution refactoring, pre-check validations in transferOwnership, API changes (rolesList values, return types), and reference related issues.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title is partially related to the changeset, referencing document store functions but lacking specificity about the main changes involving role resolution, pre-checks, and API modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/document-store-commands

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/document-store/transferOwnership.ts (1)

53-56: Truthiness checks on grantTransaction / revokeTransaction are unreachable.

Both documentStoreGrantRole and documentStoreRevokeRole either return a transaction object or throw an error — they never return a falsy value. If the underlying call fails, the await on lines 45/58 will throw before reaching these checks.

These guards are dead code; removing them would reduce false reassurance.

Proposed simplification
   const grantTransaction = await documentStoreGrantRole(
     documentStoreAddress,
     roleString,
     account,
     signer,
     options,
   );
-  //check if the grant transaction is successful
-  if (!grantTransaction) {
-    //add custom error message not proceeding with the revoke transaction
-    throw new Error('Grant transaction failed, not proceeding with revoke transaction');
-  }
   //call revoke function here
   const revokeTransaction = await documentStoreRevokeRole(
     documentStoreAddress,
     roleString,
     ownerAddress,
     signer,
     options,
   );
-  //check if the revoke transaction is successful
-  if (!revokeTransaction) {
-    throw new Error('Revoke transaction failed');
-  }
   return { grantTransaction, revokeTransaction };

Also applies to: 66-68

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/document-store/transferOwnership.ts` around lines 53 - 56, The truthiness
checks for grantTransaction and revokeTransaction in transferOwnership are dead
code because documentStoreGrantRole and documentStoreRevokeRole either return a
transaction or throw; remove the if (!grantTransaction) { ... } and if
(!revokeTransaction) { ... } blocks around the variables grantTransaction and
revokeTransaction, and instead wrap the await calls to
documentStoreGrantRole/documentStoreRevokeRole (or the surrounding
transferOwnership logic) in a try/catch that adds contextual error messages
(e.g., "grant failed" / "revoke failed") before rethrowing, or simply let the
original errors propagate for callers to handle.
src/document-store/document-store-roles.ts (1)

33-40: Dynamic role lookup looks correct but allows calling any contract method, not just role constants.

The validation on line 35 checks that role maps to any function on the contract, not specifically a role-constant getter. A caller could pass e.g. 'name' or 'owner' and get a successful call. Consider an allowlist if you want to restrict to role methods only.

This is low-risk since the call is read-only via a provider, but worth noting for defense-in-depth.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/document-store/document-store-roles.ts` around lines 33 - 40, The dynamic
role lookup in documentStore allows calling any contract function because it
only checks typeof documentStore[role] === 'function'; tighten this by
introducing an explicit allowlist of role getter names (e.g.,
'DEFAULT_ADMIN_ROLE', 'ISSUER_ROLE', 'REVOKER_ROLE') and validate the incoming
role against that list before invoking (documentStore[role]()); if role is not
in the allowlist throw an error; keep the final call as the read-only provider
call but only after allowlist validation to enforce role-only access.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/document-store/document-store-roles.ts`:
- Line 43: rolesList currently contains shorthand names that don't match
getRoleString's expected contract method names, causing "Invalid role" when
passed to getRoleString; update the exported rolesList constant to use the exact
role identifiers used by the contract and getRoleString — namely
'DEFAULT_ADMIN_ROLE', 'ISSUER_ROLE', and 'REVOKER_ROLE' — so any external code
using rolesList will be compatible with getRoleString and contract method
lookups.

In `@src/document-store/transferOwnership.ts`:
- Around line 45-68: The current flow can leave both parties with the role if
grant succeeds but revoke fails; to fix, perform dry-run (callStatic) checks for
both grant and revoke before sending any on‑chain transaction: call the
static/preflight variant used by documentStoreGrantRole and
documentStoreRevokeRole (or directly use the contract's callStatic.grantRole and
callStatic.revokeRole with the same args: documentStoreAddress, roleString,
account, ownerAddress and signer/options) and abort with a clear error if either
static call would fail; only after both static checks pass, submit the real
grant (documentStoreGrantRole) and then the real revoke
(documentStoreRevokeRole), keeping the existing grantTransaction and
revokeTransaction checks.

---

Nitpick comments:
In `@src/document-store/document-store-roles.ts`:
- Around line 33-40: The dynamic role lookup in documentStore allows calling any
contract function because it only checks typeof documentStore[role] ===
'function'; tighten this by introducing an explicit allowlist of role getter
names (e.g., 'DEFAULT_ADMIN_ROLE', 'ISSUER_ROLE', 'REVOKER_ROLE') and validate
the incoming role against that list before invoking (documentStore[role]()); if
role is not in the allowlist throw an error; keep the final call as the
read-only provider call but only after allowlist validation to enforce role-only
access.

In `@src/document-store/transferOwnership.ts`:
- Around line 53-56: The truthiness checks for grantTransaction and
revokeTransaction in transferOwnership are dead code because
documentStoreGrantRole and documentStoreRevokeRole either return a transaction
or throw; remove the if (!grantTransaction) { ... } and if (!revokeTransaction)
{ ... } blocks around the variables grantTransaction and revokeTransaction, and
instead wrap the await calls to documentStoreGrantRole/documentStoreRevokeRole
(or the surrounding transferOwnership logic) in a try/catch that adds contextual
error messages (e.g., "grant failed" / "revoke failed") before rethrowing, or
simply let the original errors propagate for callers to handle.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0c9694 and 4a89589.

📒 Files selected for processing (4)
  • src/document-store/document-store-roles.ts
  • src/document-store/index.ts
  • src/document-store/transferOwnership.ts
  • src/index.ts

Comment thread src/document-store/document-store-roles.ts Outdated
Comment thread src/document-store/transferOwnership.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/document-store/document-store-roles.ts (1)

43-43: rolesList correctly updated to contract method names.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/document-store/document-store-roles.ts` at line 43, The rolesList
constant was updated to match the contract method names; keep export const
rolesList = ['DEFAULT_ADMIN_ROLE', 'ISSUER_ROLE', 'REVOKER_ROLE'] as-is in
document-store-roles.ts (ensure the symbol rolesList remains exported and named
exactly so callers referencing rolesList or these role names match the smart
contract methods).
🧹 Nitpick comments (1)
src/document-store/transferOwnership.ts (1)

58-86: Redundant interface checks: ABI detection runs 3× across this function and both helpers.

From the grant-role.ts and revoke-role.ts snippets, both documentStoreGrantRole and documentStoreRevokeRole independently run checkSupportsInterface (twice each) unless isTransferable is explicitly passed in options. Since isTransferable is already resolved here (line 65), pass it down to both helpers to avoid 4 additional eth_call RPCs on every ownership transfer.

Additionally, lines 60–69 run the two interface checks sequentially; parallelizing them shaves one round-trip:

♻️ Proposed improvements
-  const isDocumentStore = await checkSupportsInterface(
-    documentStoreAddress,
-    supportInterfaceIds.IDocumentStore,
-    signer.provider,
-  );
-  const isTransferableDocumentStore = await checkSupportsInterface(
-    documentStoreAddress,
-    supportInterfaceIds.ITransferableDocumentStore,
-    signer.provider,
-  );
+  const [isDocumentStore, isTransferableDocumentStore] = await Promise.all([
+    checkSupportsInterface(documentStoreAddress, supportInterfaceIds.IDocumentStore, signer.provider),
+    checkSupportsInterface(documentStoreAddress, supportInterfaceIds.ITransferableDocumentStore, signer.provider),
+  ]);

Then thread the resolved flag into the helpers:

  const grantTransaction = await documentStoreGrantRole(
    documentStoreAddress,
    roleString,
    account,
    signer,
-   options,
+   { ...options, isTransferable: isTransferableDocumentStore },
  );
  // …and similarly for documentStoreRevokeRole
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/document-store/transferOwnership.ts` around lines 58 - 86, The code runs
checkSupportsInterface twice sequentially and duplicates those checks in
downstream helpers; run both interface checks in parallel (e.g. Promise.all)
when resolving isDocumentStore/isTransferableDocumentStore in
transferOwnership.ts (the existing calls to checkSupportsInterface for
supportInterfaceIds.IDocumentStore and
supportInterfaceIds.ITransferableDocumentStore), derive the documentStoreAbi as
now, then thread the resolved boolean (isTransferableDocumentStore) into the
helper calls documentStoreGrantRole and documentStoreRevokeRole so those
functions no longer re-run checkSupportsInterface; update those helper
signatures to accept an optional isTransferable flag and skip their internal
checks when that flag is provided.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/document-store/transferOwnership.ts`:
- Around line 99-109: The current brittle classification in transferOwnership.ts
(inside the catch handling around the callStatic pre-check) relies only on
substring matches of e.message; change it to first inspect structured ethers
error fields (e.reason, e.errorName, e.code, e.data or e.error?.name) and use
those values to classify the error into the existing buckets (unauthorized /
already-has-role / simulation-failed), falling back to the message-only
heuristic only if structured fields are absent; update the thrown Error to
include the discovered structured fields (errorName/reason/data) so callers see
actionable context while preserving the existing fallback text.
- Around line 132-158: Update the misleading comment to state that pre-checks
are performed twice (once here and again inside
documentStoreGrantRole/documentStoreRevokeRole) or indicate that an opt-out flag
should be threaded through if you choose to avoid double-checks; then remove the
dead null-guards around grantTransaction and revokeTransaction (the checks using
!grantTransaction / !revokeTransaction) because documentStoreGrantRole and
documentStoreRevokeRole are typed to throw on failure and always return a
ContractTransaction, so simply await the transactions and let exceptions
propagate or handle them via try/catch if needed; reference the variables
grantTransaction, revokeTransaction and the helper functions
documentStoreGrantRole/documentStoreRevokeRole when making these changes.

---

Duplicate comments:
In `@src/document-store/document-store-roles.ts`:
- Line 43: The rolesList constant was updated to match the contract method
names; keep export const rolesList = ['DEFAULT_ADMIN_ROLE', 'ISSUER_ROLE',
'REVOKER_ROLE'] as-is in document-store-roles.ts (ensure the symbol rolesList
remains exported and named exactly so callers referencing rolesList or these
role names match the smart contract methods).

---

Nitpick comments:
In `@src/document-store/transferOwnership.ts`:
- Around line 58-86: The code runs checkSupportsInterface twice sequentially and
duplicates those checks in downstream helpers; run both interface checks in
parallel (e.g. Promise.all) when resolving
isDocumentStore/isTransferableDocumentStore in transferOwnership.ts (the
existing calls to checkSupportsInterface for supportInterfaceIds.IDocumentStore
and supportInterfaceIds.ITransferableDocumentStore), derive the documentStoreAbi
as now, then thread the resolved boolean (isTransferableDocumentStore) into the
helper calls documentStoreGrantRole and documentStoreRevokeRole so those
functions no longer re-run checkSupportsInterface; update those helper
signatures to accept an optional isTransferable flag and skip their internal
checks when that flag is provided.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a89589 and 54584a7.

📒 Files selected for processing (2)
  • src/document-store/document-store-roles.ts
  • src/document-store/transferOwnership.ts

Comment thread src/document-store/transferOwnership.ts Outdated
Comment thread src/document-store/transferOwnership.ts
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
src/document-store/transferOwnership.ts (2)

125-139: Remove unreachable null-guards after awaited helper calls.

The if (!grantTransaction) and if (!revokeTransaction) branches look redundant if helper contracts are typed to return a transaction or throw. Keeping them adds dead branches and misleading failure paths.

♻️ Proposed cleanup
   const grantTransaction = await documentStoreGrantRole(
@@
   );
-
-  if (!grantTransaction) {
-    throw new Error('Grant transaction failed, not proceeding with revoke transaction');
-  }

   const revokeTransaction = await documentStoreRevokeRole(
@@
   );
-
-  if (!revokeTransaction) {
-    throw new Error('Revoke transaction failed');
-  }
#!/bin/bash
set -euo pipefail

# Verify helper return types and ensure they are non-nullable transaction responses
fd 'grant-role.ts|revoke-role.ts|transferOwnership.ts' src/document-store -t f

rg -n -C3 'export const documentStoreGrantRole|export const documentStoreRevokeRole|Promise<|ContractTransaction|ContractTransactionResponse|\bnull\b|\bundefined\b' src/document-store
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/document-store/transferOwnership.ts` around lines 125 - 139, The
null-check branches after awaiting documentStoreGrantRole and
documentStoreRevokeRole are redundant; verify that documentStoreGrantRole and
documentStoreRevokeRole are typed to return a non-null ContractTransaction (or
throw on failure) and remove the if (!grantTransaction) and if
(!revokeTransaction) guards and their throws in transferOwnership.ts so errors
propagate naturally from the awaited helper calls; keep the awaits (assign to
grantTransaction/revokeTransaction if needed) but eliminate the dead conditional
branches to simplify control flow.

99-114: ⚠️ Potential issue | 🟡 Minor

Preserve revert context instead of throwing generic pre-check errors.

Both catch blocks discard actionable revert details by rethrowing fixed strings. This makes operational debugging harder when pre-checks fail.

♻️ Proposed improvement
   } catch (e) {
-    console.error('callStatic failed:', e);
-    throw new Error('Pre-check (callStatic) for grant-role failed');
+    const details = e instanceof Error ? e.message : String(e);
+    throw new Error(`Pre-check (callStatic) for grant-role failed: ${details}`);
   }
@@
   } catch (e) {
-    console.error('callStatic failed:', e);
-    throw new Error('Pre-check (callStatic) for revoke-role failed');
+    const details = e instanceof Error ? e.message : String(e);
+    throw new Error(`Pre-check (callStatic) for revoke-role failed: ${details}`);
   }
#!/bin/bash
set -euo pipefail

# Verify whether the codebase already has a structured ethers error parsing pattern
rg -n -C3 'errorName|reason|shortMessage|callStatic failed|Pre-check \(callStatic\)' src
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/document-store/transferOwnership.ts` around lines 99 - 114, The catch
blocks for the callStatic pre-checks (the grant-role and revoke-role handlers
around the calls to (documentStoreContract as ContractV6).revokeRole.staticCall
and (documentStoreContract as ContractV5).callStatic.revokeRole) currently throw
generic Errors and lose the revert context; change them to preserve and surface
the original revert details by including the captured error in the thrown Error
(e.g. include error.reason / error.error?.message / error.shortMessage or use
new Error('Pre-check (callStatic) for revoke-role failed: ' + String(e)) or
throw new Error('...', { cause: e })), so the thrown error or log contains the
original ethers revert message/stack for easier debugging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/document-store/transferOwnership.ts`:
- Around line 125-139: The null-check branches after awaiting
documentStoreGrantRole and documentStoreRevokeRole are redundant; verify that
documentStoreGrantRole and documentStoreRevokeRole are typed to return a
non-null ContractTransaction (or throw on failure) and remove the if
(!grantTransaction) and if (!revokeTransaction) guards and their throws in
transferOwnership.ts so errors propagate naturally from the awaited helper
calls; keep the awaits (assign to grantTransaction/revokeTransaction if needed)
but eliminate the dead conditional branches to simplify control flow.
- Around line 99-114: The catch blocks for the callStatic pre-checks (the
grant-role and revoke-role handlers around the calls to (documentStoreContract
as ContractV6).revokeRole.staticCall and (documentStoreContract as
ContractV5).callStatic.revokeRole) currently throw generic Errors and lose the
revert context; change them to preserve and surface the original revert details
by including the captured error in the thrown Error (e.g. include error.reason /
error.error?.message / error.shortMessage or use new Error('Pre-check
(callStatic) for revoke-role failed: ' + String(e)) or throw new Error('...', {
cause: e })), so the thrown error or log contains the original ethers revert
message/stack for easier debugging.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 54584a7 and 9919cf7.

📒 Files selected for processing (1)
  • src/document-store/transferOwnership.ts

@rongquan1 rongquan1 merged commit b87af71 into main Feb 25, 2026
21 checks passed
@rongquan1 rongquan1 deleted the fix/document-store-commands branch February 25, 2026 09:38
nghaninn pushed a commit that referenced this pull request Feb 25, 2026
## [2.9.1](v2.9.0...v2.9.1) (2026-02-25)

### Bug Fixes

* update document store functions ([#132](#132)) ([b87af71](b87af71))
@tradetrustimda
Copy link
Copy Markdown

🎉 This PR is included in version 2.9.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants