Skip to content

fix: mandatory status and expiry pointers - #159

Merged
rongquan1 merged 1 commit into
mainfrom
fix/mandatory-status-and-expiry-pointers
Aug 7, 2026
Merged

fix: mandatory status and expiry pointers#159
rongquan1 merged 1 commit into
mainfrom
fix/mandatory-status-and-expiry-pointers

Conversation

@rongquan1

@rongquan1 rongquan1 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • Bug Fixes

    • Improved validation of selectively disclosed credentials, ensuring revocation and expiration metadata cannot be removed.
    • Presentations now reject credentials that are revoked or expired.
  • Tests

    • Added coverage for credential status and expiration enforcement during presentation signing.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 28f7075b-a057-4575-b121-f106daa57303

📥 Commits

Reviewing files that changed from the base of the PR and between 618b397 and a46ae8e.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • package.json
  • src/__tests__/w3c/presentation.test.ts

📝 Walkthrough

Walkthrough

The change updates W3C package versions and adds presentation tests for selective disclosure. The tests verify that revocation and expiration metadata remain present and that signing rejects revoked or expired credentials.

Changes

Credential Policy Validation

Layer / File(s) Summary
Credential policy tests and dependency update
package.json, src/__tests__/w3c/presentation.test.ts
W3C dependencies move to version ^2.4.2. New helpers and tests verify that selective disclosure preserves credentialStatus and validUntil, and that presentation signing rejects revoked and expired credentials.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • TrustVC/trustvc#104: Introduced the W3C VC Data Model 2.0 and selective-disclosure behavior covered by these tests.
  • TrustVC/trustvc#154: Added related Verifiable Presentation policy tests extended by this change.

Suggested reviewers: rishabhs7

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request has no description and omits the required Summary, Changes, and Issues sections. Add the required Summary, Changes, and Issues sections with the background, dependency and test changes, and related issue references.
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: enforcing mandatory status and expiry pointers.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mandatory-status-and-expiry-pointers

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.

…e presented

Selective disclosure lets a holder omit any statement the issuer did not mark
mandatory, and the credential still verifies. `credentialStatus` and the end of
the validity window were not mandatory, so a holder could derive them away and
present a revoked or expired credential that passed every check:

  issued with credentialStatus index 5 (revoked)
  holder derives -> credentialStatus present? false
  presenting the stripped credential -> SIGNED
  DOCUMENT_INTEGRITY: VALID / DOCUMENT_STATUS: VALID / ISSUER_IDENTITY: VALID

The removal is undetectable — the derived proof records nothing about what was
withheld, and dropping the then-unused status-list `@context` entry leaves the
canonical RDF, and so the signature, intact. Verification cannot catch it, so
the fix is at issuance: @trustvc/w3c-vc 2.4.2 adds `/credentialStatus`,
`/validUntil` and `/expirationDate` to its core mandatory pointers.

Both attacks are now refused through the trustvc API:

  status survived the strip attempt: true
  -> REFUSED: credential at index 0 has been revocation (credentialStatus).
  expiry survived the strip attempt: true
  -> REFUSED: credential at index 0 has expired (2021-01-01T00:00:00Z).

Add two presentation tests for this. They are not re-testing w3c-vc: they pin a
trustvc-level guarantee that now depends on another package's issuance defaults.
Without them, a downgrade or a change to that default leaves every trustvc test
passing while the hole silently reopens. Each asserts the field SURVIVED the
strip attempt before asserting the refusal, so a failure says which link broke.

Note this changes derivation output for consumers: a credential with a status or
an expiry now discloses those fields whether or not the holder selected them. It
is also not retroactive — anything already signed stays strippable and must be
reissued.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@rongquan1
rongquan1 force-pushed the fix/mandatory-status-and-expiry-pointers branch from 29f6389 to a46ae8e Compare August 6, 2026 10:00
@sonarqubecloud

sonarqubecloud Bot commented Aug 6, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 16

🧹 Nitpick comments (12)
src/eip7702-functions/token-registry-functions-gasless/mint.ts (2)

10-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Type the address fields as 0x-prefixed strings.

paymasterAddress and tokenRegistryAddress are typed as string, then cast to `0x${string}` at lines 46 and 52. The casts hide malformed input. DeployTokenRegistryGaslessOptions in src/eip7702-functions/deploy/token-registry.ts already uses the template literal type. Use the same type here and drop the casts.

Also applies to: 45-60

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/eip7702-functions/token-registry-functions-gasless/mint.ts` around lines
10 - 15, Update MintGaslessOptions.paymasterAddress and tokenRegistryAddress to
use the `0x${string}` template-literal type, matching
DeployTokenRegistryGaslessOptions. Remove the corresponding casts at the mint
call sites so malformed address inputs are rejected by the type system.

6-8: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate GaslessSmartAccountClient interface in two modules. Both files declare the same non-exported client interface. The declarations can drift apart, and consumers of the public API cannot type the client they must pass in.

  • src/eip7702-functions/token-registry-functions-gasless/mint.ts#L6-L8: remove the local declaration and import the shared exported type.
  • src/eip7702-functions/deploy/token-registry.ts#L4-L6: remove the local declaration and import the same shared exported type.

Define and export the type once, for example in a shared types.ts under src/eip7702-functions, and re-export it from src/eip7702-functions/index.ts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/eip7702-functions/token-registry-functions-gasless/mint.ts` around lines
6 - 8, Define and export a single GaslessSmartAccountClient type in shared
eip7702-functions types, re-export it from the package index, and replace the
local declarations with imports in
src/eip7702-functions/token-registry-functions-gasless/mint.ts lines 6-8 and
src/eip7702-functions/deploy/token-registry.ts lines 4-6. Ensure both modules
use the same shared exported type.
.github/workflows/linters.yml (1)

44-44: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Do not install Commitlint with npm install --force.

@commitlint/config-conventional is already declared in devDependencies and locked in package-lock.json, so this workflow lets the action install an unsealed 21.2.0 copy instead of using the repository dependency. Remove the package specifier and --force, and run npm ci --ignore-scripts in commit-lint.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/linters.yml at line 44, Update the commit-lint job’s
dependency installation command to use the repository-locked dependencies:
replace the forced package-specific npm install with npm ci --ignore-scripts,
removing both the package specifier and --force.

Source: Linters/SAST tools

src/__tests__/e2e/fixtures/sample-boe-credential.ts (1)

14-21: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Confirm the key is a throwaway test key.

Betterleaks flags line 20. The comment states the key matches existing test fixtures, so this looks intentional. Add an inline suppression comment for the secret scanner so future scans stay clean, and confirm the key is never used outside tests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/e2e/fixtures/sample-boe-credential.ts` around lines 14 - 21,
Keep SAMPLE_BOE_SIGNING_KEY limited to test fixtures and verify it is not
referenced by production code. Add the repository’s recognized inline
secret-scanner suppression comment directly beside secretKeyMultibase,
documenting that this is an intentional throwaway test key.

Source: Linters/SAST tools

src/__tests__/obligation-registry-functions/deploy.test.ts (1)

44-77: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the ethers v5 deployment branch.

Both tests set isV6EthersProvider to true. The v5 branch in src/obligation-registry-functions/deploy.ts (lines 92-101 and 155-170), including getDeployedAddress, stays untested. Add a case with isV6EthersProvider returning false and a mock contract exposing deployTransaction.wait() and address.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/obligation-registry-functions/deploy.test.ts` around lines 44 -
77, Add a test for the ethers v5 path in deployObligationRegistry by making
isV6EthersProvider return false and mocking the deployed contract with address
plus deployTransaction.wait(). Assert the resolved registry and escrow factory
addresses and verify deployment arguments, covering the getDeployedAddress flow
while keeping the existing v6 test unchanged.
src/__tests__/verify/obligationRecordVerifier.utils.test.ts (1)

28-85: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a case for the chain-ID mismatch branch.

Every test passes chainId: 80002, which matches the mocked provider network. The guard in isTokenMintedOnObligationRegistry that returns UNRECOGNIZED_DOCUMENT on a chain mismatch stays untested. Add a case with a mismatched chainId and one that omits chainId.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/verify/obligationRecordVerifier.utils.test.ts` around lines 28
- 85, The tests for isTokenMintedOnObligationRegistry cover only the matching
chain ID; add cases using a mismatched chainId and omitting chainId to exercise
the chain-mismatch guard. Assert both return minted: false with the
UNRECOGNIZED_DOCUMENT status, preserving the existing matching-chain tests.
src/obligation-registry-functions/deploy.ts (2)

37-53: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

getDeployedAddress never reads the receipt.

The function returns fallbackAddress first. The only call site (line 167) always passes contract.address, which ethers v5 always populates. The receipt branch and the error path are therefore unreachable. The parameter name also implies the opposite precedence.

Prefer the receipt address, then fall back to contract.address, and reuse the helper in deployObligationEscrowFactory (line 99) for consistent behavior.

♻️ Proposed refactor
 const getDeployedAddress = (
   receipt: ContractReceiptV5 | ContractReceiptV6,
   fallbackAddress?: string,
 ): string => {
-  if (fallbackAddress) {
-    return fallbackAddress;
-  }
-
   const contractAddress =
     'contractAddress' in receipt ? receipt.contractAddress || undefined : undefined;
 
-  if (!contractAddress) {
+  const resolved = contractAddress ?? fallbackAddress;
+  if (!resolved) {
     throw new Error('Unable to resolve deployed contract address from receipt');
   }
 
-  return contractAddress;
+  return resolved;
 };
   return {
-    obligationEscrowFactoryAddress: contract.address,
+    obligationEscrowFactoryAddress: getDeployedAddress(receipt, contract.address),
     receipt,
   };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/obligation-registry-functions/deploy.ts` around lines 37 - 53, Update
getDeployedAddress to prefer a valid contractAddress from the receipt and use
fallbackAddress only when the receipt does not provide one, preserving the
existing error when neither exists. Rename the fallback parameter if needed to
reflect its role, and replace the inline address-resolution logic in
deployObligationEscrowFactory with this helper so both deployment paths share
the same behavior.

114-126: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Reuse the resolved chain ID for the internal escrow factory deployment.

If options.escrowFactoryAddress is absent, deployObligationEscrowFactory resolves the chain ID and the fee options itself (lines 63-69). deployObligationRegistry then resolves them again. That causes two extra provider calls per deployment. Resolve chainId before line 115 and pass it in options.

♻️ Proposed refactor
-  let obligationEscrowFactoryAddress = options.escrowFactoryAddress;
+  const chainId = options.chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID);
+
+  let obligationEscrowFactoryAddress = options.escrowFactoryAddress;
   if (!obligationEscrowFactoryAddress) {
-    const deployedFactory = await deployObligationEscrowFactory(signer, options);
+    const deployedFactory = await deployObligationEscrowFactory(signer, { ...options, chainId });
     obligationEscrowFactoryAddress = deployedFactory.obligationEscrowFactoryAddress;
   }
 
-  const chainId = options.chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID);
   const txOptions = await getTxOptions(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/obligation-registry-functions/deploy.ts` around lines 114 - 126, Resolve
chainId before the conditional escrow-factory deployment in
deployObligationRegistry, and pass that resolved value through the options
supplied to deployObligationEscrowFactory so its existing chain and fee-option
resolution is reused. Then use the same chainId for getTxOptions, preserving the
provided options.escrowFactoryAddress path without unnecessary provider calls.
src/core/documentBuilder.ts (1)

379-393: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: match the unsupported-registry error by type, not by message text.

withRegistryNetworkError compares error.message to a string. If the message text changes in one place only, a genuine unsupported-registry error is reported as a network error. A dedicated error class or a sentinel property removes that coupling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/documentBuilder.ts` around lines 379 - 393, Update
withRegistryNetworkError to identify unsupported-registry failures using a
dedicated error type or sentinel property instead of comparing error.message
with unsupportedRegistryError. Preserve rethrowing the original
unsupported-registry error and continue wrapping other failures with
networkError.
src/__tests__/obligation-registry-functions/mint.test.ts (1)

114-129: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: the v6 matrix run repeats the v5 signer case.

This test always creates a WalletV5 signer, so the ethers v6 run repeats the same assertion. Move the case outside describe.each, or create a WalletV6 signer when ethersVersion === 'v6'.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/obligation-registry-functions/mint.test.ts` around lines 114 -
129, Update the “throws when provider is missing” test in the obligation
registry test suite so it does not duplicate the WalletV5 case during the ethers
v6 matrix run. Move the test outside describe.each, or select WalletV6 when
ethersVersion is v6 while preserving the existing Provider is required
assertion.
src/__tests__/obligation-registry-functions/ownerOf.test.ts (1)

15-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: add ethers v6 coverage.

The sibling obligation-registry tests run a v5/v6 provider matrix. This file tests only ethers v5, so the v6 contract-read path for ownerOfObligationRegistry is untested.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/obligation-registry-functions/ownerOf.test.ts` around lines 15
- 43, Extend the ownerOfObligationRegistry test suite to cover both ethers v5
and v6 provider paths, matching the provider matrix used by sibling
obligation-registry tests. Parameterize or duplicate the existing owner-address
and missing-registry-address cases while preserving their current assertions and
setup behavior.
src/utils/documents/obligation.ts (1)

26-38: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: reuse getObligationRecordsCredentialStatus here.

isObligationRecord repeats the credential-status normalization already implemented at line 21. Delegating keeps one normalization path.

♻️ Proposed simplification
   if (!isSignedDocument(document)) {
     return false;
   }
-
-  const credentialStatuses = Array.isArray(document.credentialStatus)
-    ? document.credentialStatus
-    : [document.credentialStatus];
-
-  return credentialStatuses.some((cs) => isObligationRecordCredentialStatus(cs));
+  return getObligationRecordsCredentialStatus(document) !== undefined;
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/documents/obligation.ts` around lines 26 - 38, Update
isObligationRecord to reuse getObligationRecordsCredentialStatus for
credential-status normalization instead of rebuilding the array locally, then
apply isObligationRecordCredentialStatus to the returned normalized statuses
while preserving the existing signed-document guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Line 35: Update the Table of Contents entry for Gasless Operations to replace
the invalid `#overview-1` fragment with the anchor generated for its Overview
heading, leaving the displayed link text unchanged.
- Line 468: Correct the obsolete section references in README.md: at lines
468-468 and 989-989, change §7c to §8c; at lines 989-989, also change §4 to §5;
and at lines 1585-1585, change “section 7” to “section 8”.

In `@src/__tests__/e2e/obligation-registry-functions/statusLifecycle.e2e.test.ts`:
- Around line 51-63: In the before hook, update the setup order around
hardhat_reset and evm_setAutomine: call hardhat_reset first, then enable
automining with evm_setAutomine so the setting persists for the suite. Leave
signer creation and deployment unchanged.

In `@src/__tests__/obligation-registry-functions/rejectTransfers.test.ts`:
- Around line 55-64: Add an assertion in the
“rejectTransferHolderObligationRegistry with remarks” test verifying that the
encryption function is called with the provided remarks, following the
established pattern in lifecycle.test.ts and mint.test.ts while retaining the
transaction-hash assertion.

In `@src/core/documentBuilder.ts`:
- Around line 109-113: Run Prettier on the changed code: in
src/core/documentBuilder.ts lines 109-113, format the selectedStatusType union
declaration; in
src/verify/fragments/document-status/obligationRecords/obligationRecordVerifier.ts
lines 105-110, format the credentialStatuses.some callback. No behavioral
changes are needed.
- Around line 173-198: Add a symmetric mixing guard to credentialStatus
immediately after its isSigned check, rejecting calls when selectedStatusType is
'obligationRecords' with the same configuration error used by
obligationCredentialStatus. Preserve the existing credentialStatus configuration
flow for all other status types.

In `@src/core/endorsement-chain/fetchEscrowTransfer.ts`:
- Around line 163-170: Invoke each status filter factory before adding it to
allFilters in the includeObligationStatus branch of fetchEscrowTransfer, so
queryFilter receives instantiated event filters rather than the factory
functions themselves. Preserve the existing four status filters and their
ordering.

In `@src/eip7702-functions/deploy/platform-paymaster.ts`:
- Around line 66-78: Validate the resolved platformAddress immediately after its
assignment in the writeContract branch, alongside the existing publicClient
guard. Throw an explicit error when neither options.platformAddress nor
signer.account?.address provides an address, and preserve the existing
transaction flow for valid addresses.

In `@src/eip7702-functions/platform-paymaster-functions/admin.ts`:
- Around line 34-41: Update the v6 branch in the transaction helper containing
isV6EthersProvider to await tx.wait() before returning the transaction hash,
matching the v5 confirmation semantics and deployPlatformPaymaster convention.
Adjust the corresponding v6 expectations in the admin tests so setUserWhitelist
and addRegistry resolve only after confirmation.

In `@src/eip7702-functions/token-registry-functions-gasless/mint.ts`:
- Line 43: Update the encryptedRemarks expression in the mint flow to handle
optional options.id without a non-null assertion, matching the existing
token-registry mint behavior by using an empty-string fallback or explicitly
rejecting remarks when no id is provided.

In `@src/eip7702-functions/token-registry-functions-gasless/transfer.ts`:
- Line 37: Update the encryption calls to use the existing empty-key fallback
when options.id is omitted, while preserving the current '0x' result when
remarks are absent. Apply this in transfer.ts at lines 37, 70, 103, and 140;
rejectTransfers.ts at lines 34, 67, and 100; and returnToken.ts at lines 39, 73,
and 107, so encrypt never receives undefined.

In `@src/obligation-registry-functions/status.ts`:
- Around line 25-28: Update the async status handler to use the supplied
_params.tokenId when resolving the escrow through getEscrowContract, rather than
relying on contractOptions.tokenId. Ensure params.tokenId takes precedence when
both values are present, while preserving the existing read(contract, options)
behavior.

In `@src/utils/documents/index.ts`:
- Around line 35-41: Update the credentialStatuses validation to require at
least one credential status before evaluating every(...). Ensure an empty
document.credentialStatus array returns false, while preserving the existing
status checks for non-empty arrays.

In
`@src/verify/fragments/document-status/obligationRecords/obligationRecordVerifier.ts`:
- Around line 39-70: Update the credentialStatuses mapping in the
verificationResult flow to validate credentialStatus.tokenId before constructing
tokenId. If it is absent or invalid, throw the same UNRECOGNIZED_DOCUMENT
CodedError used by the obligationRegistry and chainId guards; otherwise derive
the hex value without duplicating an existing 0x prefix, then pass it to
isTokenMintedOnObligationRegistry.

In
`@src/verify/fragments/document-status/obligationRecords/obligationRecordVerifier.types.ts`:
- Around line 27-29: Define ObligationRecordsVerificationFragment directly as
ObligationRecordsResultFragment, removing the redundant single-member union
while preserving the existing type alias.

In `@src/verify/fragments/document-status/obligationRecords/utils.ts`:
- Around line 77-81: Update the catch block around ownerOf in the
obligation-record verification flow so only the known nonexistent-token revert
is converted via notMintedReason. Distinguish that expected revert before
calling decodeError; rethrow RPC transport failures, timeouts, rate limits, and
unexpected contract errors instead of returning a non-minted result.

---

Nitpick comments:
In @.github/workflows/linters.yml:
- Line 44: Update the commit-lint job’s dependency installation command to use
the repository-locked dependencies: replace the forced package-specific npm
install with npm ci --ignore-scripts, removing both the package specifier and
--force.

In `@src/__tests__/e2e/fixtures/sample-boe-credential.ts`:
- Around line 14-21: Keep SAMPLE_BOE_SIGNING_KEY limited to test fixtures and
verify it is not referenced by production code. Add the repository’s recognized
inline secret-scanner suppression comment directly beside secretKeyMultibase,
documenting that this is an intentional throwaway test key.

In `@src/__tests__/obligation-registry-functions/deploy.test.ts`:
- Around line 44-77: Add a test for the ethers v5 path in
deployObligationRegistry by making isV6EthersProvider return false and mocking
the deployed contract with address plus deployTransaction.wait(). Assert the
resolved registry and escrow factory addresses and verify deployment arguments,
covering the getDeployedAddress flow while keeping the existing v6 test
unchanged.

In `@src/__tests__/obligation-registry-functions/mint.test.ts`:
- Around line 114-129: Update the “throws when provider is missing” test in the
obligation registry test suite so it does not duplicate the WalletV5 case during
the ethers v6 matrix run. Move the test outside describe.each, or select
WalletV6 when ethersVersion is v6 while preserving the existing Provider is
required assertion.

In `@src/__tests__/obligation-registry-functions/ownerOf.test.ts`:
- Around line 15-43: Extend the ownerOfObligationRegistry test suite to cover
both ethers v5 and v6 provider paths, matching the provider matrix used by
sibling obligation-registry tests. Parameterize or duplicate the existing
owner-address and missing-registry-address cases while preserving their current
assertions and setup behavior.

In `@src/__tests__/verify/obligationRecordVerifier.utils.test.ts`:
- Around line 28-85: The tests for isTokenMintedOnObligationRegistry cover only
the matching chain ID; add cases using a mismatched chainId and omitting chainId
to exercise the chain-mismatch guard. Assert both return minted: false with the
UNRECOGNIZED_DOCUMENT status, preserving the existing matching-chain tests.

In `@src/core/documentBuilder.ts`:
- Around line 379-393: Update withRegistryNetworkError to identify
unsupported-registry failures using a dedicated error type or sentinel property
instead of comparing error.message with unsupportedRegistryError. Preserve
rethrowing the original unsupported-registry error and continue wrapping other
failures with networkError.

In `@src/eip7702-functions/token-registry-functions-gasless/mint.ts`:
- Around line 10-15: Update MintGaslessOptions.paymasterAddress and
tokenRegistryAddress to use the `0x${string}` template-literal type, matching
DeployTokenRegistryGaslessOptions. Remove the corresponding casts at the mint
call sites so malformed address inputs are rejected by the type system.
- Around line 6-8: Define and export a single GaslessSmartAccountClient type in
shared eip7702-functions types, re-export it from the package index, and replace
the local declarations with imports in
src/eip7702-functions/token-registry-functions-gasless/mint.ts lines 6-8 and
src/eip7702-functions/deploy/token-registry.ts lines 4-6. Ensure both modules
use the same shared exported type.

In `@src/obligation-registry-functions/deploy.ts`:
- Around line 37-53: Update getDeployedAddress to prefer a valid contractAddress
from the receipt and use fallbackAddress only when the receipt does not provide
one, preserving the existing error when neither exists. Rename the fallback
parameter if needed to reflect its role, and replace the inline
address-resolution logic in deployObligationEscrowFactory with this helper so
both deployment paths share the same behavior.
- Around line 114-126: Resolve chainId before the conditional escrow-factory
deployment in deployObligationRegistry, and pass that resolved value through the
options supplied to deployObligationEscrowFactory so its existing chain and
fee-option resolution is reused. Then use the same chainId for getTxOptions,
preserving the provided options.escrowFactoryAddress path without unnecessary
provider calls.

In `@src/utils/documents/obligation.ts`:
- Around line 26-38: Update isObligationRecord to reuse
getObligationRecordsCredentialStatus for credential-status normalization instead
of rebuilding the array locally, then apply isObligationRecordCredentialStatus
to the returned normalized statuses while preserving the existing
signed-document guard.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 16b3ab73-dea0-4e63-ace9-d44c9e40f0f9

📥 Commits

Reviewing files that changed from the base of the PR and between 618b397 and 29f6389.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (77)
  • .github/workflows/ci.yml
  • .github/workflows/linters.yml
  • .github/workflows/publish.yml
  • .github/workflows/tests.yml
  • CHANGELOG.md
  • OA-v3-document-sepolia.json
  • README.md
  • package.json
  • release.config.js
  • src/__tests__/core/documentBuilder.test.ts
  • src/__tests__/core/verify.amoy.test.ts
  • src/__tests__/core/verify.test.ts
  • src/__tests__/e2e/fixtures/sample-boe-credential.ts
  • src/__tests__/e2e/obligation-registry-functions/fixtures.ts
  • src/__tests__/e2e/obligation-registry-functions/statusLifecycle.e2e.test.ts
  • src/__tests__/e2e/obligation-registry-functions/transfer.e2e.test.ts
  • src/__tests__/e2e/utils.ts
  • src/__tests__/eip7702-functions/admin.test.ts
  • src/__tests__/eip7702-functions/deploy.test.ts
  • src/__tests__/eip7702-functions/mint.test.ts
  • src/__tests__/eip7702-functions/rejectTransfers.test.ts
  • src/__tests__/eip7702-functions/returnToken.test.ts
  • src/__tests__/eip7702-functions/transfer.test.ts
  • src/__tests__/fixtures/endorsement-chain.ts
  • src/__tests__/obligation-registry-functions/deploy.test.ts
  • src/__tests__/obligation-registry-functions/fixtures.ts
  • src/__tests__/obligation-registry-functions/lifecycle.test.ts
  • src/__tests__/obligation-registry-functions/mint.test.ts
  • src/__tests__/obligation-registry-functions/ownerOf.test.ts
  • src/__tests__/obligation-registry-functions/rejectTransfers.test.ts
  • src/__tests__/obligation-registry-functions/returnToken.test.ts
  • src/__tests__/obligation-registry-functions/status.test.ts
  • src/__tests__/obligation-registry-functions/transfers.test.ts
  • src/__tests__/utils/documents/index.test.ts
  • src/__tests__/verify/obligationRecordVerifier.utils.test.ts
  • src/__tests__/w3c/presentation.test.ts
  • src/core/documentBuilder.ts
  • src/core/endorsement-chain/fetchEscrowTransfer.ts
  • src/core/endorsement-chain/helpers.ts
  • src/core/endorsement-chain/index.ts
  • src/core/endorsement-chain/obligation.ts
  • src/core/endorsement-chain/types.ts
  • src/core/endorsement-chain/useEndorsementChain.ts
  • src/eip7702-functions/deploy/index.ts
  • src/eip7702-functions/deploy/platform-paymaster.ts
  • src/eip7702-functions/deploy/token-registry.ts
  • src/eip7702-functions/index.ts
  • src/eip7702-functions/platform-paymaster-functions/admin.ts
  • src/eip7702-functions/platform-paymaster-functions/index.ts
  • src/eip7702-functions/token-registry-functions-gasless/index.ts
  • src/eip7702-functions/token-registry-functions-gasless/mint.ts
  • src/eip7702-functions/token-registry-functions-gasless/rejectTransfers.ts
  • src/eip7702-functions/token-registry-functions-gasless/returnToken.ts
  • src/eip7702-functions/token-registry-functions-gasless/transfer.ts
  • src/index.ts
  • src/obligation-registry-functions/deploy.ts
  • src/obligation-registry-functions/index.ts
  • src/obligation-registry-functions/lifecycle.ts
  • src/obligation-registry-functions/mint.ts
  • src/obligation-registry-functions/ownerOf.ts
  • src/obligation-registry-functions/rejectTransfers.ts
  • src/obligation-registry-functions/returnToken.ts
  • src/obligation-registry-functions/status.ts
  • src/obligation-registry-functions/transfer.ts
  • src/obligation-registry-functions/types.ts
  • src/obligation-registry-functions/utils.ts
  • src/token-registry-v5/contracts.ts
  • src/utils/documents/index.ts
  • src/utils/documents/obligation.ts
  • src/verify/fragments/document-status/obligationRecords/obligationRecordVerifier.ts
  • src/verify/fragments/document-status/obligationRecords/obligationRecordVerifier.types.ts
  • src/verify/fragments/document-status/obligationRecords/utils.ts
  • src/verify/fragments/document-status/obligationRecords/verifierHelpers.ts
  • src/verify/fragments/document-status/transferableRecords/transferableRecordVerifier.ts
  • src/verify/fragments/document-status/transferableRecords/utils.ts
  • src/verify/fragments/index.ts
  • src/verify/verify.ts

Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread src/__tests__/e2e/obligation-registry-functions/statusLifecycle.e2e.test.ts Outdated
Comment thread src/__tests__/obligation-registry-functions/rejectTransfers.test.ts Outdated
Comment thread src/core/documentBuilder.ts Outdated
Comment thread src/obligation-registry-functions/status.ts Outdated
Comment thread src/utils/documents/index.ts Outdated
Comment thread src/verify/fragments/document-status/obligationRecords/utils.ts Outdated
@rongquan1

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@TrustVC TrustVC deleted a comment from coderabbitai Bot Aug 6, 2026
@TrustVC TrustVC deleted a comment from coderabbitai Bot Aug 6, 2026
@rongquan1
rongquan1 requested a review from RishabhS7 August 7, 2026 02:35
@rongquan1
rongquan1 merged commit b9646bc into main Aug 7, 2026
39 of 45 checks passed
@rongquan1
rongquan1 deleted the fix/mandatory-status-and-expiry-pointers branch August 7, 2026 02:53
nghaninn pushed a commit that referenced this pull request Aug 7, 2026
## [2.15.1](v2.15.0...v2.15.1) (2026-08-07)

### Bug Fixes

* bump w3c-vc to 2.4.2 so revoked and expired credentials cannot be presented ([#159](#159)) ([b9646bc](b9646bc))
@tradetrustimda

Copy link
Copy Markdown

🎉 This PR is included in version 2.15.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

rongquan1 added a commit that referenced this pull request Aug 7, 2026
Sync the 2.15.1 patch from main into the beta line: bump @trustvc/w3c-vc
to 2.4.2 so revoked and expired credentials cannot be presented (#159).

Conflict resolutions:
- package.json: keep beta's version (2.16.0-beta.2, the higher line);
  take main's @trustvc/w3c-vc ^2.4.2; keep beta's @trustvc/eip7702 dep
- package-lock.json: kept beta's cross-platform lockfile, bumped w3c-vc to
  2.4.2 via `npm install --package-lock-only` (all 26 esbuild platforms preserved)
- CHANGELOG.md: kept both histories; inserted the 2.15.1 section before 2.15.0
- src/__tests__/w3c/presentation.test.ts: main's #159 test merged cleanly

Verified: type-check, lint, npm ci clean, w3c-vc 2.4.2 installed, VP tests 32/32
pass (incl. the revoked/expired presentation checks).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nghaninn pushed a commit that referenced this pull request Aug 7, 2026
## [2.16.0-beta.3](v2.16.0-beta.2...v2.16.0-beta.3) (2026-08-07)

### Bug Fixes

* bump w3c-vc to 2.4.2 so revoked and expired credentials cannot be presented ([#159](#159)) ([b9646bc](b9646bc))

### Miscellaneous Chores

* **release:** 2.15.1 [skip ci] ([c03628d](c03628d)), closes [#159](#159)
@tradetrustimda

Copy link
Copy Markdown

🎉 This PR is included in version 2.16.0-beta.3 🎉

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants