Skip to content

feat: merge tt utils#123

Merged
rongquan1 merged 8 commits into
mainfrom
feat/merge-tt-utils
Nov 27, 2025
Merged

feat: merge tt utils#123
rongquan1 merged 8 commits into
mainfrom
feat/merge-tt-utils

Conversation

@RishabhS7

@RishabhS7 RishabhS7 commented Nov 27, 2025

Copy link
Copy Markdown
Contributor

Summary

Merge TT-utils in trustvc

Summary by CodeRabbit

  • New Features

    • Google Analytics helpers (page views/events) added to utils.
    • Centralized verification messages, richer verification fragment handling, and extensive verifier-response fixtures.
    • Gas price utilities with remote fetch, parsing, BigNumber scaling, and fee calculation.
    • Expanded network/chain metadata with inline chain icons and a public SUPPORTED_CHAINS map.
  • Tests

    • Added comprehensive tests for analytics, gas station, supported chains, fragment handling, and verifier fixtures.
  • Chores

    • Dependency and build config updates (fetch/types for analytics).

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Nov 27, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Consolidates external utility re-exports into local implementations, adds analytics and gas-station utilities with tests, expands supportedChains and chain metadata, centralizes verification error messages and fragment handling, adds extensive verifier-response fixtures, and updates TypeScript types for gtag.

Changes

Cohort / File(s) Change Summary
Import migrations
src/__tests__/e2e/token-registry-functions/rejectTransfer.e2e.test.ts, src/__tests__/e2e/token-registry-functions/returnToken.e2e.test.ts, src/__tests__/e2e/token-registry-functions/transfer.e2e.test.ts, src/__tests__/token-registry-functions/mint.test.ts, src/__tests__/token-registry-functions/ownerOf.test.ts, src/__tests__/token-registry-functions/rejectTransfers.test.ts, src/__tests__/token-registry-functions/returnToken.test.ts, src/__tests__/token-registry-functions/transfers.test.ts, src/__tests__/utils/fragment/errorMessageHandling.test.ts, src/token-registry-functions/types.ts, src/token-registry-functions/utils.ts
Repointed imports of CHAIN_ID, SUPPORTED_CHAINS, and constants from external @tradetrust-tt/tradetrust-utils to local src/utils/supportedChains; removed some dynamic imports. No runtime logic changes.
Verifier fixtures
src/__tests__/fixtures/verifier-response.ts
Added extensive verification-fragment fixtures covering hash, issuance, identity, revocation, server/client errors, and mixed scenarios for tests.
Analytics module & tests
src/utils/analytics/analytics.ts, src/utils/analytics/index.ts, src/utils/analytics/analytics.test.ts
New analytics helpers and barrel export: validateGtag, validatePageViewEvent, validateGaEvent, gaPageView, gaEvent; tests for validation, logging, and gtag invocation.
Verification error messages
src/utils/errorMessages/VerificationErrorMessages.ts, src/utils/errorMessages/index.ts
Introduced local TYPES and MESSAGES constants for verification outcomes; errorMessages now derived from local module.
Fragment utils & tests
src/utils/fragment/index.ts, src/utils/fragment/fragments.test.ts
Added interpretFragments, OAErrorMessageHandling, reworked fragment error aggregation (DID/Ethereum nuances), preserved/updated public exports; tests added.
Gas-station implementation & tests
src/utils/gasStation/index.ts, src/utils/gasStation/index.test.ts
New local gasStation implementation and types: gasStation, GasStationFeeData, scaleBigNumber, calculateMaxFee, internal safeParseUnits; tests for fetch behavior, BigNumber parsing, zero/invalid values, and error paths.
Supported chains & tests
src/utils/supportedChains/index.ts, src/utils/supportedChains/supportedChains.test.ts
Replaced re-export with full local implementation: CHAIN_ID enum, chainInfo type, comprehensive SUPPORTED_CHAINS mapping (rpc, explorers, gasStation, nativeCurrency, icons); tests validate entries.
Network types & icons
src/utils/network/index.ts, src/utils/static/icons.ts
Added networks constant and exported types (networkName, networkType, networkCurrency); added five icon data-URL exports.
Utils barrel, TS config & deps
src/utils/index.ts, package.json, tsconfig.json, tsconfig.build.json
Re-exported analytics from src/utils/index.ts; package.json added node-fetch, @types/node-fetch, @types/gtag.js, jsdom; tsconfig and tsconfig.build added "gtag.js" to global types.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Analytics as Analytics Module
    participant Gtag as window.gtag
    participant Console as Console

    App->>Analytics: gaPageView(event, gaId)
    Analytics->>Analytics: validateGtag()
    alt gtag present
        Analytics->>Analytics: validatePageViewEvent(event)
        alt valid
            Analytics->>Gtag: gtag('event','page_view', {..., send_to: gaId})
        else invalid
            Analytics->>Console: console.error("invalid page view")
        end
    else gtag missing
        Analytics->>Console: console.warn("gtag not initialised")
    end
Loading
sequenceDiagram
    participant Test as Test Suite
    participant Factory as gasStation(url)
    participant Fetch as fetch
    participant Parser as safeParseUnits
    participant Caller as Caller

    Test->>Factory: create with URL
    Factory-->>Test: fetcherFn
    Test->>fetcherFn: invoke
    fetcherFn->>Fetch: fetch(url)
    alt success
        Fetch-->>fetcherFn: JSON
        fetcherFn->>Parser: parse fee strings
        Parser-->>fetcherFn: BigNumber values
        fetcherFn-->>Caller: {maxPriorityFeePerGas, maxFeePerGas}
    else error
        fetcherFn-->>Caller: throw "Failed to fetch gas station"
    end
Loading
sequenceDiagram
    participant Fragments as VerificationFragments
    participant Handler as errorMessageHandling()
    participant Logic as interpretFragments / OAErrorMessageHandling
    participant Out as ErrorCodes[]

    Fragments->>Handler: fragments[]
    Handler->>Logic: interpretFragments(fragments)
    Logic->>Logic: check integrity (HASH), issuance (ISSUED/REVOKED), identity (DNS/DID)
    alt all valid
        Logic-->>Out: [ISSUED]
    else revoked
        Logic-->>Out: [REVOKED,...]
    else mixed issues
        Logic-->>Out: aggregated error codes
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing extra attention:
    • src/utils/gasStation/index.ts — BigNumber parsing, unit/precision, error handling.
    • src/utils/supportedChains/index.ts — chain metadata, env keys, gasStation wiring.
    • src/utils/fragment/index.ts — new interpretation logic, DID/Ethereum revocation nuances.
    • src/utils/errorMessages/VerificationErrorMessages.ts — coverage and message mappings.

Possibly related PRs

Suggested labels

released on @v1``, released

Suggested reviewers

  • rongquan1
  • nghaninn

Poem

🐰 I hopped through chains and messages bright,
I stitched up utils by soft moonlight.
Analytics hums and gas fees flow,
Fragments sorted in row and row.
Tests cheer softly — a joyful hop hello!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description only provides a minimal 'Summary' section stating 'Merge TT-utils in trustvc' but is missing the required 'Changes' and 'Issues' sections from the template. The description lacks detail about what was actually changed and which issues are addressed. Expand the description to include: 1) detailed 'Changes' section listing the key modifications (e.g., moving dependencies, updating imports, adding new utilities), and 2) 'Issues' section referencing related issues or stories.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: merge tt utils' is concise and clearly indicates the main change: merging TT-utils into the repository. It accurately reflects the primary objective of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/merge-tt-utils

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9f0c6dc and af8a9d5.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • package.json (3 hunks)
  • src/utils/errorMessages/types.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/utils/errorMessages/types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json

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.

@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: 3

🧹 Nitpick comments (21)
src/utils/static/icons.ts (1)

1-8: Consider using proper MIME types for image data URLs.

iconEthereum and iconPolygon use data:image/octet-stream;base64 while iconStability and iconAstron use data:image/png;base64. Using the correct MIME type improves browser compatibility and ensures proper rendering.

Based on the base64 headers:

  • iconEthereum appears to be WebP format (UklGR = RIFF header)
  • iconPolygon also appears to be WebP format
 export const iconEthereum =
-  'data:image/octet-stream;base64,UklGRhgNAABXRUJQ...
+  'data:image/webp;base64,UklGRhgNAABXRUJQ...

 export const iconPolygon =
-  'data:image/octet-stream;base64,UklGRuIDAABXRUJQ...
+  'data:image/webp;base64,UklGRuIDAABXRUJQ...
src/utils/fragment/index.ts (3)

18-22: Rename interface to follow PascalCase convention.

The interface name interpretFragmentsReturnTypes should follow TypeScript naming conventions using PascalCase.

-interface interpretFragmentsReturnTypes {
+interface InterpretFragmentsReturnTypes {
   hashValid: boolean;
   issuedValid: boolean;
   identityValid: boolean;
 }

Also update the return type on line 47:

 export const interpretFragments = (
   fragments: VerificationFragment[],
-): interpretFragmentsReturnTypes => {
+): InterpretFragmentsReturnTypes => {

54-90: Consider adding explicit type annotation for the errors array.

The errors array is implicitly typed. Adding an explicit type annotation improves readability and catches potential type errors early.

 export const OAErrorMessageHandling = (fragments: VerificationFragment[]): string[] => {
   const { hashValid, issuedValid, identityValid } = interpretFragments(fragments);
-  const errors = [];
+  const errors: string[] = [];

114-141: Consider adding explicit type annotation for consistency.

Similar to OAErrorMessageHandling, the errors array should have an explicit type annotation for consistency.

 const errorMessageHandling = (fragments: VerificationFragment[]): string[] => {
   const { hashValid, issuedValid, identityValid } = interpretFragments(fragments);
-  const errors = [];
+  const errors: string[] = [];
src/utils/gasStation/index.ts (3)

1-2: Remove commented-out code.

These commented import lines should be removed as they serve no purpose and add noise. Per static analysis.

-// export { gasStation, calculateMaxFee, scaleBigNumber } from '@tradetrust-tt/tradetrust-utils';
-// export type { GasStationFunction, GasStationFeeData } from '@tradetrust-tt/tradetrust-utils';
 import { BigNumber, ethers } from 'ethers';

71-72: Simplify undefined checks (optional).

Per static analysis, prefer direct comparison with undefined instead of typeof. This applies to lines 71, 86, and 89.

-  if (wei === null || typeof wei === 'undefined') {
+  if (wei === null || wei === undefined) {
     throw new Error('Wei not specified');
   }

31-33: Consider preserving the original error context.

The catch block discards the original error, making debugging harder. Consider including the original error message or at least logging it.

-    } catch {
-      throw new Error('Failed to fetch gas station');
+    } catch (error) {
+      throw new Error(`Failed to fetch gas station: ${error instanceof Error ? error.message : String(error)}`);
     }
src/utils/gasStation/index.test.ts (1)

1-87: Good test coverage for gasStation, but missing tests for other exports.

The tests adequately cover the gasStation function. However, scaleBigNumber and calculateMaxFee are also exported but have no test coverage in this file. Consider adding tests for these functions, especially edge cases like:

  • scaleBigNumber with null/undefined input
  • calculateMaxFee with scale = 1 (fast path) and scale != 1
  • Values near precision boundaries
src/token-registry-functions/utils.ts (1)

3-4: Remove commented-out import.

The commented import on line 3 should be removed. Per static analysis.

-// import { CHAIN_ID, SUPPORTED_CHAINS } from '@tradetrust-tt/tradetrust-utils';
 import { CHAIN_ID, SUPPORTED_CHAINS } from '../utils';
src/__tests__/token-registry-functions/returnToken.test.ts (1)

7-7: Consider standardizing CHAIN_ID import paths across test files.

This file imports CHAIN_ID from ../../utils/supportedChains, while other test files (e.g., mint.test.ts) import from ../../utils/index.js. Both paths may work if properly re-exported, but using a consistent import path through the barrel export (../../utils/index.js or ../../utils) improves maintainability.

src/__tests__/token-registry-functions/rejectTransfers.test.ts (1)

6-6: Consider standardizing CHAIN_ID import paths across test files.

This file imports CHAIN_ID from ../../utils/supportedChains, while other test files import from ../../utils/index.js. Using a consistent import path through the barrel export improves maintainability.

src/__tests__/token-registry-functions/transfers.test.ts (1)

7-7: Local SUPPORTED_CHAINS usage looks good; consider cleaning up commented dynamic imports

Switching to the local CHAIN_ID/SUPPORTED_CHAINS import is consistent with the new utils module, and the pattern of overriding SUPPORTED_CHAINS[mockChainId].gasStation then restoring it is correct for these tests.

You can safely remove the now-redundant commented dynamic-import blocks for SUPPORTED_CHAINS (Lines 172–174, 361–363, 543, 719) to reduce noise and avoid future confusion.

Also applies to: 169-203, 350-392, 542-574, 708-748

src/utils/fragment/fragments.test.ts (1)

1-158: Comprehensive coverage for fragment interpretation and error aggregation

The test scenarios for interpretFragments and errorMessageHandling are well structured and cover the main combinations of hash/issued/identity validity plus the various error codes (HASH, IDENTITY, ISSUED, REVOKED, ADDRESS_INVALID, CONTRACT_NOT_FOUND, SERVER_ERROR, ETHERS_UNHANDLED_ERROR).

If you want to reduce duplication later, you could import the centralised error constants (e.g., via errorMessages) instead of hardcoding the string literals, but the current tests are already clear and effective.

src/utils/errorMessages/index.ts (1)

1-8: Tighten up local CONSTANTS wiring and remove dead commented import

The move to a local VerificationErrorMessages source looks fine, and assigning the module namespace to errorMessages: ErrorMessages will work as long as that module exposes the expected TYPES/MESSAGES shape.

Two small cleanups:

  1. Remove the commented external import to satisfy the Sonar warning and avoid confusion.
  2. (Optional) Make the mapping explicit, which also better documents the contract:
-import * as CONSTANTS from './VerificationErrorMessages';
+import { TYPES, MESSAGES } from './VerificationErrorMessages';
 ...
-// Re-export with proper typing
-export const errorMessages: ErrorMessages = CONSTANTS;
+// Re-export with proper typing
+export const errorMessages: ErrorMessages = { TYPES, MESSAGES };
src/utils/network/index.ts (1)

1-21: Local network types look good; drop obsolete commented re-export

Defining networks as a readonly tuple and deriving networkName plus the explicit networkType/networkCurrency unions is a clean replacement for the previous external re-export.

You can safely delete the commented export * from '@tradetrust-tt/tradetrust-utils/constants/network'; line now that the local definitions are in place, which will also address the Sonar warning.

src/utils/analytics/analytics.ts (1)

1-54: Consider making validators gate event dispatch, not just log

The core GA helpers are structurally sound:

  • validateGtag safely checks for gtag and avoids runtime errors.
  • gaPageView / gaEvent correctly construct page_view and generic event payloads.

Right now, validatePageViewEvent and validateGaEvent only log errors but don’t prevent sending malformed events (e.g., missing category/action or wrong value type) — gaPageView/gaEvent proceed regardless.

If you want validation to be effective rather than advisory, consider having validators return a boolean (or throw) and short‑circuit on failure, e.g.:

export const validateGaEvent = (gaEvent: GaEventProps): boolean => {
  let valid = true;
  if (!gaEvent.category) { console.error('Category is required'); valid = false; }
  if (!gaEvent.action) { console.error('Action is required'); valid = false; }
  if (gaEvent.label != null && typeof gaEvent.label !== 'string') { console.error('Label must be a string'); valid = false; }
  if (gaEvent.value != null && typeof gaEvent.value !== 'number') { console.error('Value must be a number'); valid = false; }
  return valid;
};

export const gaEvent = (gaEvent: GaEventProps): void => {
  if (!validateGtag()) return;
  if (!validateGaEvent(gaEvent)) return;
  ...
};

This keeps the API the same but avoids emitting obviously invalid analytics data.

src/utils/analytics/analytics.test.ts (2)

1-29: Simplify console spying and align “gtag not present” test with its setup

A couple of small testing improvements:

  • You don’t need to vi.spyOn(console, 'error'/'warn') both at the top level and again in beforeEach. Initialising the spies in beforeEach (and using those references in expectations) is enough and avoids any risk of double‑spying confusion.
  • In the gaEvent suite, the test "does not fail if gtag is not present" currently runs with gtag initialised in the suite beforeEach. Either rename this test to reflect that it’s a generic smoke test, or clear globalThis.gtag/window.gtag inside that test before calling gaEvent so it truly covers the “not present” scenario.

These are test-only changes but will make intent clearer and more robust.

Also applies to: 31-37


48-59: Use globalThis instead of window for gtag in tests to satisfy Sonar and be environment-agnostic

Sonar’s suggestions to prefer globalThis over window here are reasonable and easy to adopt, and they’ll also make the tests less dependent on a DOM-like environment.

You can simplify the setup/teardown by only touching globalThis.gtag and asserting on it, e.g.:

beforeEach(() => {
-  // Ensure both global gtag (used by code) and window.gtag (used by assertions) are set
-  (globalThis as any).gtag = vi.fn();
-  window.gtag = (globalThis as any).gtag;
+  (globalThis as any).gtag = vi.fn();
});

afterEach(() => {
-  window.gtag = undefined as any;
-  (globalThis as any).gtag = undefined;
+  (globalThis as any).gtag = undefined;
});
...
- expect(window.gtag).toHaveBeenCalledTimes(1);
- expect(window.gtag).toHaveBeenCalledWith('event', 'TEST_ACTION', { ... });
+ expect((globalThis as any).gtag).toHaveBeenCalledTimes(1);
+ expect((globalThis as any).gtag).toHaveBeenCalledWith('event', 'TEST_ACTION', { ... });

This will also remove the “unnecessary assertion” warning on the as any cast.

Also applies to: 60-80, 129-139, 141-163

src/utils/supportedChains/index.ts (2)

1-1: Remove commented-out code.

Dead code clutters the codebase. If this export is no longer needed, delete the line entirely rather than leaving it commented.

-// export * from '@tradetrust-tt/tradetrust-utils/constants/supportedChains';

60-60: Consider validating environment variables at startup.

Environment variables like INFURA_API_KEY, OKLINK_API_KEY, and STABILITY_*_API_KEY are interpolated directly into URLs. If any are undefined, you'll get malformed URLs like https://mainnet.infura.io/v3/undefined. Consider adding validation or fallback handling for required env vars.

Also applies to: 70-70, 87-87, 103-103, 148-148, 164-164

src/utils/errorMessages/VerificationErrorMessages.ts (1)

1-18: Consider using as const for stricter type inference.

Adding as const to the TYPES object enables TypeScript to infer literal types for the values, which can improve type safety when used as discriminants.

 export const TYPES = {
   REVOKED: 'REVOKED',
   SUSPENDED: 'SUSPENDED',
   ISSUED: 'ISSUED',
   HASH: 'HASH',
   IDENTITY: 'IDENTITY',
   INVALID: 'INVALID',
   ADDRESS_INVALID: 'ADDRESS_INVALID',
   NETWORK_INVALID: 'NETWORK_INVALID',
   NETWORK_MISMATCH_MAINNET: 'NETWORK_MISMATCH_MAINNET',
   NETWORK_MISMATCH_TESTNET: 'NETWORK_MISMATCH_TESTNET',
   CONTRACT_NOT_FOUND: 'CONTRACT_NOT_FOUND',
   INVALID_ARGUMENT: 'INVALID_ARGUMENT',
   SERVER_ERROR: 'SERVER_ERROR',
   ETHERS_UNHANDLED_ERROR: 'ETHERS_UNHANDLED_ERROR',
   CLIENT_NETWORK_ERROR: 'CLIENT_NETWORK_ERROR',
   VERIFICATION_ERROR: 'VERIFICATION_ERROR',
-};
+} as const;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3b5742 and 2c05346.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (29)
  • package.json (2 hunks)
  • src/__tests__/e2e/token-registry-functions/rejectTransfer.e2e.test.ts (1 hunks)
  • src/__tests__/e2e/token-registry-functions/returnToken.e2e.test.ts (1 hunks)
  • src/__tests__/e2e/token-registry-functions/transfer.e2e.test.ts (1 hunks)
  • src/__tests__/fixtures/verifier-response.ts (1 hunks)
  • src/__tests__/token-registry-functions/mint.test.ts (1 hunks)
  • src/__tests__/token-registry-functions/ownerOf.test.ts (1 hunks)
  • src/__tests__/token-registry-functions/rejectTransfers.test.ts (1 hunks)
  • src/__tests__/token-registry-functions/returnToken.test.ts (1 hunks)
  • src/__tests__/token-registry-functions/transfers.test.ts (5 hunks)
  • src/__tests__/utils/fragment/errorMessageHandling.test.ts (1 hunks)
  • src/token-registry-functions/types.ts (1 hunks)
  • src/token-registry-functions/utils.ts (1 hunks)
  • src/utils/analytics/analytics.test.ts (1 hunks)
  • src/utils/analytics/analytics.ts (1 hunks)
  • src/utils/analytics/index.ts (1 hunks)
  • src/utils/errorMessages/VerificationErrorMessages.ts (1 hunks)
  • src/utils/errorMessages/index.ts (1 hunks)
  • src/utils/fragment/fragments.test.ts (1 hunks)
  • src/utils/fragment/index.ts (2 hunks)
  • src/utils/gasStation/index.test.ts (1 hunks)
  • src/utils/gasStation/index.ts (1 hunks)
  • src/utils/index.ts (1 hunks)
  • src/utils/network/index.ts (1 hunks)
  • src/utils/static/icons.ts (1 hunks)
  • src/utils/supportedChains/index.ts (1 hunks)
  • src/utils/supportedChains/supportedChains.test.ts (1 hunks)
  • tsconfig.build.json (1 hunks)
  • tsconfig.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/utils/supportedChains/supportedChains.test.ts (1)
src/utils/supportedChains/index.ts (1)
  • SUPPORTED_CHAINS (41-204)
src/utils/gasStation/index.test.ts (1)
src/utils/gasStation/index.ts (1)
  • gasStation (21-34)
src/utils/fragment/index.ts (2)
src/verify/verify.ts (3)
  • VerificationFragment (99-99)
  • utils (86-86)
  • isValid (78-78)
src/utils/errorMessages/VerificationErrorMessages.ts (1)
  • TYPES (1-18)
src/utils/analytics/analytics.test.ts (1)
src/utils/analytics/analytics.ts (5)
  • validateGtag (14-18)
  • validatePageViewEvent (20-24)
  • gaPageView (26-34)
  • validateGaEvent (36-42)
  • gaEvent (44-54)
🪛 GitHub Check: SonarCloud Code Analysis
src/utils/network/index.ts

[warning] 1-1: Remove this commented out code.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqonzAF9f2sW9oAf&open=AZrDJqonzAF9f2sW9oAf&pullRequest=123

src/utils/fragment/index.ts

[warning] 18-18: Rename interface "interpretFragmentsReturnTypes" to match the regular expression ^[A-Z][a-zA-Z0-9]*$.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnwzAF9f2sW9oAd&open=AZrDJqnwzAF9f2sW9oAd&pullRequest=123


[warning] 1-5: Remove this commented out code.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnwzAF9f2sW9oAc&open=AZrDJqnwzAF9f2sW9oAc&pullRequest=123

src/utils/supportedChains/index.ts

[warning] 1-1: Remove this commented out code.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqoFzAF9f2sW9oAe&open=AZrDJqoFzAF9f2sW9oAe&pullRequest=123

src/utils/analytics/analytics.test.ts

[warning] 149-149: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAb&open=AZrDJqnZzAF9f2sW9oAb&pullRequest=123


[warning] 148-148: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAa&open=AZrDJqnZzAF9f2sW9oAa&pullRequest=123


[warning] 52-52: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAT&open=AZrDJqnZzAF9f2sW9oAT&pullRequest=123


[warning] 137-137: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAZ&open=AZrDJqnZzAF9f2sW9oAZ&pullRequest=123


[warning] 56-56: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAU&open=AZrDJqnZzAF9f2sW9oAU&pullRequest=123


[warning] 67-67: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAV&open=AZrDJqnZzAF9f2sW9oAV&pullRequest=123


[warning] 68-68: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAW&open=AZrDJqnZzAF9f2sW9oAW&pullRequest=123


[warning] 133-133: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAX&open=AZrDJqnZzAF9f2sW9oAX&pullRequest=123


[warning] 133-133: This assertion is unnecessary since it does not change the type of the expression.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAY&open=AZrDJqnZzAF9f2sW9oAY&pullRequest=123

src/token-registry-functions/utils.ts

[warning] 3-3: Remove this commented out code.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqkWzAF9f2sW9oAL&open=AZrDJqkWzAF9f2sW9oAL&pullRequest=123

src/utils/gasStation/index.ts

[warning] 71-71: Compare with undefined directly instead of using typeof.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnLzAF9f2sW9oAQ&open=AZrDJqnLzAF9f2sW9oAQ&pullRequest=123


[warning] 86-86: Compare with undefined directly instead of using typeof.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnLzAF9f2sW9oAR&open=AZrDJqnLzAF9f2sW9oAR&pullRequest=123


[warning] 38-38: Use the "RegExp.exec()" method instead.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnLzAF9f2sW9oAO&open=AZrDJqnLzAF9f2sW9oAO&pullRequest=123


[warning] 59-59: Use the "RegExp.exec()" method instead.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnLzAF9f2sW9oAP&open=AZrDJqnLzAF9f2sW9oAP&pullRequest=123


[warning] 89-89: Compare with undefined directly instead of using typeof.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnLzAF9f2sW9oAS&open=AZrDJqnLzAF9f2sW9oAS&pullRequest=123


[warning] 1-2: Remove this commented out code.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnLzAF9f2sW9oAN&open=AZrDJqnLzAF9f2sW9oAN&pullRequest=123

src/utils/errorMessages/index.ts

[warning] 1-1: Remove this commented out code.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqm3zAF9f2sW9oAM&open=AZrDJqm3zAF9f2sW9oAM&pullRequest=123

🔇 Additional comments (21)
package.json (1)

133-133: Appropriate choice of node-fetch v2.x for dual module support.

Using node-fetch v2.x is correct since v3.x is ESM-only and would break the CommonJS build output. The type definitions at line 152 align properly.

tsconfig.json (1)

8-8: LGTM!

Adding gtag.js to the types array properly enables ambient type definitions for the new analytics utilities.

tsconfig.build.json (1)

7-7: LGTM!

Build configuration properly includes gtag types, consistent with the base tsconfig.json.

src/utils/fragment/index.ts (3)

31-38: LGTM!

The helper correctly extracts the DID-signed document status fragment and checks for the DOCUMENT_REVOKED status code. The documentation clearly explains why this project-level check is necessary.


45-52: LGTM!

The function properly aggregates fragment results using the isValid helper from @tradetrust-tt/tt-verify with the correct verification types.


143-143: LGTM!

The export statement correctly exposes errorMessageHandling, w3cCredentialStatusRevoked, and w3cCredentialStatusSuspended as the public API surface.

src/__tests__/e2e/token-registry-functions/transfer.e2e.test.ts (1)

4-4: LGTM!

Import path correctly updated to use local utilities, consistent with the PR objective to consolidate TT-utils.

src/__tests__/e2e/token-registry-functions/rejectTransfer.e2e.test.ts (1)

6-6: LGTM!

Import path correctly updated to use local utilities, consistent with other test files in this PR.

src/utils/analytics/index.ts (1)

1-1: LGTM!

Standard barrel export pattern for the analytics module.

src/utils/index.ts (1)

9-9: LGTM!

The analytics module is properly added to the public API through the barrel export, consistent with the existing export pattern.

src/__tests__/token-registry-functions/ownerOf.test.ts (1)

6-6: LGTM!

Correctly imports CHAIN_ID through the barrel export at ../../utils/index.js, which is the preferred pattern for accessing utilities.

src/__tests__/e2e/token-registry-functions/returnToken.e2e.test.ts (1)

3-3: LGTM!

Correctly imports CHAIN_ID through the barrel export with the appropriate relative path for the e2e test directory structure.

src/__tests__/token-registry-functions/mint.test.ts (1)

19-19: CHAIN_ID is correctly exported from the local utils module.

The import path change from the external package to '../../utils/index.js' is valid. The local utils module properly re-exports CHAIN_ID from the supportedChains submodule via its index file, maintaining the same interface.

src/token-registry-functions/types.ts (1)

1-1: No type compatibility issues found with CHAIN_ID import.

The import path is correctly configured and properly resolves through the utils barrel export. CHAIN_ID is defined as a string enum in src/utils/supportedChains/index.ts and is re-exported via src/utils/index.ts, making it available at the ../utils import location. The TransactionOptions interface correctly uses the optional chainId?: CHAIN_ID property, maintaining type safety for the public API.

src/__tests__/utils/fragment/errorMessageHandling.test.ts (1)

2-3: Wiring to local errorMessages/fragment utilities looks correct

Importing errorMessages as CONSTANTS and errorMessageHandling from the local utils path preserves the previous behavior while decoupling from the external package. The tests remain clear and correctly assert against CONSTANTS.TYPES.

src/utils/supportedChains/supportedChains.test.ts (1)

1-108: Chain metadata tests align with SUPPORTED_CHAINS configuration

These tests correctly mirror the SUPPORTED_CHAINS entries (id, name, type, currency, explorer URL, and Amoy RPC prefix). The import path to ../supportedChains will resolve to the index module as intended.

src/utils/supportedChains/index.ts (2)

7-19: LGTM!

The CHAIN_ID enum provides a clean, type-safe way to reference chain identifiers across the codebase.


21-37: LGTM!

The chainInfo type is well-structured with appropriate optional fields for chain-specific features like gasStation and nativeCurrency.

src/utils/errorMessages/VerificationErrorMessages.ts (1)

20-112: LGTM!

The MESSAGES mapping provides comprehensive, user-friendly error messages for all verification scenarios. The structure is consistent and the messages are clear and actionable.

src/__tests__/fixtures/verifier-response.ts (2)

1-105: LGTM!

Comprehensive test fixtures covering various document verification scenarios. The data structures accurately represent OpenAttestation verification fragments.


276-289: Good use of composition for derived fixtures.

Reusing whenDocumentValidAndIssuedByDns and filtering by type to create the tampered hash scenario reduces duplication and ensures consistency across related test cases.

Comment thread src/utils/fragment/index.ts Outdated
Comment on lines +58 to +63
// Too many decimals and some non-zero ending, take the ceiling
if (comps[1].length > 9 && !comps[1].substring(9).match(/^0+$/)) {
comps[1] = BigNumber.from(comps[1].substring(0, 9)).add(BigNumber.from(1)).toString();
}

return ethers.utils.parseUnits(`${comps[0]}.${comps[1]}`, decimals);

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.

⚠️ Potential issue | 🟠 Major

Hardcoded 9 should use decimals parameter, and ceiling logic may overflow.

Two issues in this block:

  1. Line 59 uses hardcoded 9 instead of the decimals parameter
  2. Line 60: Adding 1 to the fractional part can cause overflow (e.g., "999999999" + 1 = "1000000000"), which would then cause parseUnits to fail or produce incorrect results
-  if (comps[1].length > 9 && !comps[1].substring(9).match(/^0+$/)) {
-    comps[1] = BigNumber.from(comps[1].substring(0, 9)).add(BigNumber.from(1)).toString();
+  if (comps[1].length > decimals && !comps[1].substring(decimals).match(/^0+$/)) {
+    const fractional = BigNumber.from(comps[1].substring(0, decimals)).add(BigNumber.from(1));
+    const fractionalStr = fractional.toString();
+    // Handle carry-over to whole part
+    if (fractionalStr.length > decimals) {
+      comps[0] = BigNumber.from(comps[0]).add(1).toString();
+      comps[1] = '0'.repeat(decimals);
+    } else {
+      comps[1] = fractionalStr.padStart(decimals, '0');
+    }
+  } else {
+    comps[1] = comps[1].substring(0, decimals);
   }
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[warning] 59-59: Use the "RegExp.exec()" method instead.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnLzAF9f2sW9oAP&open=AZrDJqnLzAF9f2sW9oAP&pullRequest=123

🤖 Prompt for AI Agents
In src/utils/gasStation/index.ts around lines 58 to 63, the code currently uses
a hardcoded "9" for fractional trimming and naively adds 1 to the fractional
substring which can overflow; change the hardcoded 9 to the function's decimals
parameter, and when rounding up handle carry: compute the fractional substring
of length decimals, if the truncated tail contains any non-zero digit then add
one to the fractional part using BigNumber; if that addition increases the
fractional string length (e.g., "999" + 1 -> "1000") roll the carry into the
integer part (increment comps[0]) and set the fractional string to zeros of
length decimals; finally left-pad or right-pad the fractional string to exactly
decimals before calling ethers.utils.parseUnits so parseUnits receives a valid
fixed-length fraction.

currency: 'MATIC',
iconImage: iconPolygon,
explorerUrl: 'https://www.oklink.com/amoy',
explorerApiUrl: `https://www.oklink.com/${process.env.OKLINK_API_KEY}`,

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

OKLink API authentication format documentation


<web_search_result>
OKLink private REST requests — required headers and signing

  • Required headers:

    • OK-ACCESS-KEY: your APIKey. [1]
    • OK-ACCESS-SIGN: Base64-encoded HMAC-SHA256 signature. [1]
    • OK-ACCESS-TIMESTAMP: UTC timestamp in ISO 8601 with milliseconds (e.g. 2022-10-07T07:03:54.726Z). [1]
    • OK-ACCESS-PASSPHRASE: passphrase chosen when creating the APIKey. [1]
  • Signature generation:

    1. Build the prehash string: timestamp + HTTP_METHOD(UPPERCASE) + requestPath + body (body omitted for GET). Query parameters for GET count as part of requestPath. [1]
    2. Compute HMAC-SHA256 of the prehash string using your SecretKey. [1]
    3. Base64-encode the HMAC result and put it in OK-ACCESS-SIGN. [1]
  • Request notes:

    • Request body must be application/json. [1]
    • requestPath is the API path (e.g. /api/v5/asset/balances). [1]

Source: OKLink API docs. [1] https://www.oklink.com/docs/trust_en/
</web_search_result>


OKLink explorer API public endpoint authentication


<web_search_result>
Short answer — it depends:

  • Public/read-only explorer endpoints (e.g., basic chain/query endpoints) are typically unauthenticated and can be called without an API key. See example explorer endpoints in the docs. [1]

  • Actions that change state or access protected data (broadcasting txs, contract verification, rate‑limited/paid endpoints) require API credentials and signed headers (OK-ACCESS-KEY / OK-ACCESS-SIGN / passphrase style auth). See the API key / signing instructions. [2][3]

  • Note: OKLink announced suspension of the Explorer API service effective May 20, 2025; if you plan integration verify current service status with OKLink before building. [4]

Sources:
[1] OKLink explorer API examples/docs. [2] OKLink API authentication / APIKey & signing headers. [3] OKLink explorer endpoint example (v5). [4] OKLink announcement: suspension of Explorer API (May 20, 2025).
</web_search_result>


Script executed:

rg -n "explorerApiUrl" --type ts --type js -B 3 -A 3

Repository: TrustVC/trustvc


<shell_result>
Repository: TrustVC/trustvc
Exit code: 0

stdout:

src/utils/supportedChains/index.ts-26-  currency: networkCurrency;
src/utils/supportedChains/index.ts-27-  iconImage: string;
src/utils/supportedChains/index.ts-28-  explorerUrl: string;
src/utils/supportedChains/index.ts:29:  explorerApiUrl?: string;
src/utils/supportedChains/index.ts-30-  rpcUrl?: string;
src/utils/supportedChains/index.ts-31-  gasStation?: () => Promise<GasStationFeeData | undefined>;
src/utils/supportedChains/index.ts-32-  nativeCurrency?: {
--
src/utils/supportedChains/index.ts-83-    currency: 'MATIC',
src/utils/supportedChains/index.ts-84-    iconImage: iconPolygon,
src/utils/supportedChains/index.ts-85-    explorerUrl: 'https://www.oklink.com/amoy',
src/utils/supportedChains/index.ts:86:    explorerApiUrl: `https://www.oklink.com/${process.env.OKLINK_API_KEY}`,
src/utils/supportedChains/index.ts-87-    rpcUrl: `https://polygon-amoy.infura.io/v3/${process.env.INFURA_API_KEY}`,
src/utils/supportedChains/index.ts-88-    gasStation: gasStation('https://gasstation-testnet.polygon.technology/amoy'),
src/utils/supportedChains/index.ts-89-    nativeCurrency: {

</shell_result>


Script executed:

rg -n "explorerApiUrl" --type ts --type js

Repository: TrustVC/trustvc


<shell_result>
Repository: TrustVC/trustvc
Exit code: 0

stdout:

src/utils/supportedChains/index.ts:29:  explorerApiUrl?: string;
src/utils/supportedChains/index.ts:86:    explorerApiUrl: `https://www.oklink.com/${process.env.OKLINK_API_KEY}`,

</shell_result>


Remove the API key from the URL path and use proper OKLink authentication headers instead.

OKLink API authentication requires headers (OK-ACCESS-KEY, OK-ACCESS-SIGN, OK-ACCESS-TIMESTAMP, OK-ACCESS-PASSPHRASE) for protected endpoints, not API keys embedded in the URL path. Public/read-only explorer endpoints are typically unauthenticated and require no API key at all. The current format exposes the key in logs, URLs, and referrer headers, which is a security anti-pattern.

Additionally, OKLink has announced suspension of the Explorer API effective May 20, 2025—verify current service status before relying on this integration.

🤖 Prompt for AI Agents
In src/utils/supportedChains/index.ts around line 86, the explorerApiUrl is
embedding the OKLink API key into the URL path which leaks secrets and is wrong
for OKLink (their protected endpoints require authentication via headers, or
public explorer endpoints require no key). Remove the API key from the URL and
set explorerApiUrl to the base public endpoint only; implement/expect OKLink
auth to be provided via request headers (OK-ACCESS-KEY, OK-ACCESS-SIGN,
OK-ACCESS-TIMESTAMP, OK-ACCESS-PASSPHRASE) when calling protected endpoints, and
ensure the key is read from env and used only in header construction (not
concatenated into URLs), also add a note or conditional to verify the Explorer
API availability given the May 20, 2025 suspension notice.

@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: 4

🧹 Nitpick comments (1)
src/utils/analytics/analytics.test.ts (1)

133-133: Remove redundant type assertion.

The type assertion as any after (globalThis as any).gtag is redundant since the expression is already typed as any.

Apply this diff:

-    window.gtag = (globalThis as any).gtag as any;
+    window.gtag = (globalThis as any).gtag;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb10fc6 and d398af7.

📒 Files selected for processing (1)
  • src/utils/analytics/analytics.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/utils/analytics/analytics.test.ts (1)
src/utils/analytics/analytics.ts (5)
  • validateGtag (14-18)
  • validatePageViewEvent (20-24)
  • gaPageView (26-34)
  • validateGaEvent (36-42)
  • gaEvent (44-54)
🪛 GitHub Check: SonarCloud Code Analysis
src/utils/analytics/analytics.test.ts

[warning] 133-133: This assertion is unnecessary since it does not change the type of the expression.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAY&open=AZrDJqnZzAF9f2sW9oAY&pullRequest=123


[warning] 56-56: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAU&open=AZrDJqnZzAF9f2sW9oAU&pullRequest=123


[warning] 148-148: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAa&open=AZrDJqnZzAF9f2sW9oAa&pullRequest=123


[warning] 133-133: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAX&open=AZrDJqnZzAF9f2sW9oAX&pullRequest=123


[warning] 67-67: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAV&open=AZrDJqnZzAF9f2sW9oAV&pullRequest=123


[warning] 68-68: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAW&open=AZrDJqnZzAF9f2sW9oAW&pullRequest=123


[warning] 149-149: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAb&open=AZrDJqnZzAF9f2sW9oAb&pullRequest=123


[warning] 52-52: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAT&open=AZrDJqnZzAF9f2sW9oAT&pullRequest=123


[warning] 137-137: Prefer globalThis over window.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnZzAF9f2sW9oAZ&open=AZrDJqnZzAF9f2sW9oAZ&pullRequest=123

🔇 Additional comments (3)
src/utils/analytics/analytics.test.ts (3)

1-19: LGTM!

The test setup is well-structured with appropriate vitest configuration, console spies, and mock data.


21-29: LGTM!

The beforeEach and afterEach hooks properly manage mock state between tests.


31-37: LGTM!

The test correctly verifies that a warning is logged when gtag is not initialized.

});
});

describe('validateGaPageView', () => {

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.

⚠️ Potential issue | 🟡 Minor

Fix the describe block name.

The describe block name "validateGaPageView" doesn't match the function name "validatePageViewEvent".

Apply this diff:

-describe('validateGaPageView', () => {
+describe('validatePageViewEvent', () => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
describe('validateGaPageView', () => {
describe('validatePageViewEvent', () => {
🤖 Prompt for AI Agents
In src/utils/analytics/analytics.test.ts around line 39, the describe block is
named "validateGaPageView" but the test targets the function
validatePageViewEvent; update the describe block name to "validatePageViewEvent"
so it matches the function under test, keeping surrounding test code intact.

Comment on lines +73 to +79
it('errors if there is a validation error', () => {
const mockGaEventError = { action: 123 };
// @ts-expect-error the mock does not match the signature
gaPageView(mockGaEventError);
expect(consoleError).toHaveBeenCalledTimes(1);
expect(consoleError).toHaveBeenCalledWith('Action must be a string');
});

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.

⚠️ Potential issue | 🔴 Critical

Missing required parameter in function call.

The gaPageView function requires two parameters (gaEvent and gaId), but line 76 only provides one. This means the test doesn't properly exercise the validation error path.

Apply this diff:

     const mockGaEventError = { action: 123 };
     // @ts-expect-error the mock does not match the signature
-    gaPageView(mockGaEventError);
+    gaPageView(mockGaEventError, GA_MEASUREMENT_ID);
     expect(consoleError).toHaveBeenCalledTimes(1);
     expect(consoleError).toHaveBeenCalledWith('Action must be a string');
🤖 Prompt for AI Agents
In src/utils/analytics/analytics.test.ts around lines 73 to 79, the test calls
gaPageView with only the gaEvent argument which omits the required gaId and
prevents the test from hitting the intended validation path; update the function
call to include a valid dummy GA id (e.g. 'GA-TEST') as the second argument so
the validation runs against the malformed gaEvent.action and the existing
assertions remain valid.

Comment on lines +108 to +126
it('passes for minimum values', () => {
validateGaEvent({
category: 'foobar',
action: 'foobar_start',
label: undefined,
value: undefined,
});
expect(true).toBe(true);
});

it('passes for all values', () => {
validateGaEvent({
category: 'foobar',
action: 'foobar_start',
label: 'Start Foobar',
value: 2,
});
expect(true).toBe(true);
});

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.

⚠️ Potential issue | 🟡 Minor

Replace meaningless assertions.

Lines 115 and 125 use expect(true).toBe(true), which doesn't verify anything meaningful. Consider asserting that consoleError was NOT called instead.

Apply this diff:

   it('passes for minimum values', () => {
     validateGaEvent({
       category: 'foobar',
       action: 'foobar_start',
       label: undefined,
       value: undefined,
     });
-    expect(true).toBe(true);
+    expect(consoleError).not.toHaveBeenCalled();
   });

   it('passes for all values', () => {
     validateGaEvent({
       category: 'foobar',
       action: 'foobar_start',
       label: 'Start Foobar',
       value: 2,
     });
-    expect(true).toBe(true);
+    expect(consoleError).not.toHaveBeenCalled();
   });

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/utils/analytics/analytics.test.ts around lines 108 to 126, the tests use
meaningless assertions expect(true).toBe(true); replace them with assertions
that console error was not invoked: set up a spy (or mock) for console.error (or
the existing consoleError mock if present) before calling validateGaEvent, call
validateGaEvent with the same payloads, then assert that the spy was not called
(e.g., expect(consoleError).not.toHaveBeenCalled()), and finally restore/clear
the spy to avoid test pollution.

Comment on lines +141 to +144
it('does not fail if gtag is not present', () => {
gaEvent(mockGaEvent as any);
expect(true).toBe(true);
});

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.

⚠️ Potential issue | 🔴 Critical

Test doesn't verify the intended condition.

This test claims to verify behavior "if gtag is not present", but the beforeEach hook on lines 130-133 always sets up gtag. The test doesn't actually exercise the code path when gtag is absent.

Apply this diff to properly test the absence of gtag:

   it('does not fail if gtag is not present', () => {
+    // Remove gtag to test the not-present case
+    window.gtag = undefined as any;
+    (globalThis as any).gtag = undefined;
     gaEvent(mockGaEvent as any);
     expect(true).toBe(true);
   });

Alternatively, consider moving this test outside the describe block so it doesn't run the beforeEach hook that sets up gtag.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('does not fail if gtag is not present', () => {
gaEvent(mockGaEvent as any);
expect(true).toBe(true);
});
it('does not fail if gtag is not present', () => {
// Remove gtag to test the not-present case
window.gtag = undefined as any;
(globalThis as any).gtag = undefined;
gaEvent(mockGaEvent as any);
expect(true).toBe(true);
});
🤖 Prompt for AI Agents
In src/utils/analytics/analytics.test.ts around lines 141 to 144, the test "does
not fail if gtag is not present" is invalid because the describe-level
beforeEach always sets window.gtag; update the test to remove or stub out gtag
before invoking gaEvent (e.g., delete (window as any).gtag or set it to
undefined) or move this test outside the describe that installs gtag so it
actually exercises the absent-gtag path, then assert that gaEvent does not throw
and that no global gtag calls were attempted (e.g., wrap gaEvent call in
expect(() => gaEvent(...)).not.toThrow() and verify any spy on global gtag is
not called).

@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: 1

♻️ Duplicate comments (2)
src/utils/gasStation/index.ts (1)

34-62: Hardcoded 9 should use decimals parameter, and ceiling logic may overflow.

This is the same issue flagged in the previous review. Two problems persist:

  1. Line 57: Uses hardcoded 9 instead of the decimals parameter
  2. Lines 58-59: Adding 1 to the fractional part can overflow (e.g., "999999999" + 1 = "1000000000"), producing an invalid string for parseUnits

Additionally, after line 59, if the fractional part is shorter than decimals, it needs proper padding or truncation before calling parseUnits.

Apply this diff to fix:

-  // Pad the fraction to 9 decimal places
+  // Pad the fraction to the specified decimal places
   while (comps[1].length < decimals) {
     comps[1] += '0';
   }
 
   // Too many decimals and some non-zero ending, take the ceiling
-  if (comps[1].length > 9 && !comps[1].substring(9).match(/^0+$/)) {
-    comps[1] = BigNumber.from(comps[1].substring(0, 9)).add(BigNumber.from(1)).toString();
+  if (comps[1].length > decimals && !comps[1].substring(decimals).match(/^0+$/)) {
+    const fractional = BigNumber.from(comps[1].substring(0, decimals)).add(BigNumber.from(1));
+    const fractionalStr = fractional.toString();
+    // Handle carry-over to whole part
+    if (fractionalStr.length > decimals) {
+      comps[0] = BigNumber.from(comps[0]).add(1).toString();
+      comps[1] = '0'.repeat(decimals);
+    } else {
+      comps[1] = fractionalStr.padStart(decimals, '0');
+    }
+  } else {
+    comps[1] = comps[1].substring(0, decimals);
   }
src/utils/supportedChains/index.ts (1)

85-86: Remove the API key from the URL path and use proper OKLink authentication headers instead.

This is the same security issue flagged in the previous review. OKLink API authentication requires headers (OK-ACCESS-KEY, OK-ACCESS-SIGN, OK-ACCESS-TIMESTAMP, OK-ACCESS-PASSPHRASE) for protected endpoints, not API keys embedded in the URL path. Public/read-only explorer endpoints typically require no authentication at all.

Embedding the key in the URL:

  • Exposes secrets in logs, URLs, and referrer headers
  • Uses the wrong authentication method for OKLink
  • May not work at all given OKLink announced suspension of Explorer API effective May 20, 2025

Apply this diff:

     explorerUrl: 'https://www.oklink.com/amoy',
-    explorerApiUrl: `https://www.oklink.com/${process.env.OKLINK_API_KEY}`,
+    explorerApiUrl: 'https://www.oklink.com/amoy',

Implement OKLink authentication via request headers (when calling protected endpoints) rather than URL construction. Also verify the Explorer API availability given the suspension notice.

🧹 Nitpick comments (7)
src/utils/fragment/index.ts (3)

13-17: Rename interface to PascalCase.

Per TypeScript conventions, interface names should use PascalCase.

-interface interpretFragmentsReturnTypes {
+interface InterpretFragmentsReturnTypes {
   hashValid: boolean;
   issuedValid: boolean;
   identityValid: boolean;
 }

Also update the return type annotation on line 42:

): InterpretFragmentsReturnTypes => {

49-52: Add explicit type annotation to errors array.

Without a type annotation, TypeScript may infer never[] in strict mode, which would cause type errors on push calls.

 export const OAErrorMessageHandling = (fragments: VerificationFragment[]): string[] => {
   const { hashValid, issuedValid, identityValid } = interpretFragments(fragments);
-  const errors = [];
+  const errors: string[] = [];

109-111: Add explicit type annotation to errors array.

Same issue as in OAErrorMessageHandling - the array needs an explicit type annotation.

 const errorMessageHandling = (fragments: VerificationFragment[]): string[] => {
   const { hashValid, issuedValid, identityValid } = interpretFragments(fragments);
-  const errors = [];
+  const errors: string[] = [];
src/utils/gasStation/index.ts (3)

19-32: Consider returning undefined on error for consistency with the return type.

The function's return type is Promise<GasStationFeeData | undefined>, but the catch block throws an error rather than returning undefined. This creates inconsistent behavior—callers expecting undefined on failure will instead receive an unhandled promise rejection.

Apply this diff to return undefined consistently:

     } catch {
-      throw new Error('Failed to fetch gas station');
+      return undefined;
     }

Alternatively, if throwing is intentional, update the return type to remove | undefined.


64-77: Consider direct undefined comparison for consistency.

The function correctly handles null/undefined inputs. Static analysis suggests comparing with undefined directly rather than using typeof, which is a common modern TypeScript pattern.

Apply this diff if you prefer the modern style:

-  if (wei === null || typeof wei === 'undefined') {
+  if (wei === null || wei === undefined) {
     throw new Error('Wei not specified');
   }

79-96: Consider direct undefined comparison for consistency.

The function logic is correct, including the fast-path optimization when scale === 1. Static analysis suggests comparing with undefined directly rather than using typeof, which aligns with modern TypeScript conventions.

Apply this diff if you prefer the modern style:

-  if (maxFee === null || typeof maxFee === 'undefined') {
+  if (maxFee === null || maxFee === undefined) {
     throw new Error('Max Fee not specified');
   }
-  if (priorityFee === null || typeof priorityFee === 'undefined') {
+  if (priorityFee === null || priorityFee === undefined) {
     throw new Error('Priority Fee not specified');
   }
src/utils/supportedChains/index.ts (1)

59-203: Consider validating environment variables to prevent runtime errors.

Multiple chain configurations use environment variables in template strings (e.g., INFURA_API_KEY, STABILITY_API_KEY, OKLINK_API_KEY) without validation. If any of these variables are undefined, the resulting URLs will contain the string "undefined", causing runtime failures when the RPC or API endpoints are accessed.

Consider adding validation either:

  1. At module initialization (throw early if required vars are missing)
  2. At runtime (return undefined or throw descriptive errors when constructing URLs)

Example validation at module level:

const requiredEnvVars = ['INFURA_API_KEY', 'STABILITY_API_KEY', 'STABILITY_TESTNET_API_KEY'];
for (const varName of requiredEnvVars) {
  if (!process.env[varName]) {
    console.warn(`Environment variable ${varName} is not set. Some chain configurations may fail.`);
  }
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d398af7 and 129ae68.

📒 Files selected for processing (6)
  • src/token-registry-functions/utils.ts (1 hunks)
  • src/utils/errorMessages/index.ts (1 hunks)
  • src/utils/fragment/index.ts (2 hunks)
  • src/utils/gasStation/index.ts (1 hunks)
  • src/utils/network/index.ts (1 hunks)
  • src/utils/supportedChains/index.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/token-registry-functions/utils.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/utils/errorMessages/index.ts
🧰 Additional context used
🧬 Code graph analysis (2)
src/utils/supportedChains/index.ts (3)
src/utils/network/index.ts (3)
  • networkName (16-16)
  • networkType (18-18)
  • networkCurrency (20-20)
src/utils/gasStation/index.ts (2)
  • GasStationFeeData (7-10)
  • gasStation (19-32)
src/utils/static/icons.ts (5)
  • iconEthereum (1-2)
  • iconPolygon (4-5)
  • iconXDC (7-8)
  • iconStability (10-11)
  • iconAstron (13-14)
src/utils/fragment/index.ts (1)
src/utils/errorMessages/VerificationErrorMessages.ts (1)
  • TYPES (1-18)
🪛 GitHub Check: SonarCloud Code Analysis
src/utils/fragment/index.ts

[warning] 13-13: Rename interface "interpretFragmentsReturnTypes" to match the regular expression ^[A-Z][a-zA-Z0-9]*$.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnwzAF9f2sW9oAd&open=AZrDJqnwzAF9f2sW9oAd&pullRequest=123

src/utils/gasStation/index.ts

[warning] 84-84: Compare with undefined directly instead of using typeof.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnLzAF9f2sW9oAR&open=AZrDJqnLzAF9f2sW9oAR&pullRequest=123


[warning] 69-69: Compare with undefined directly instead of using typeof.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnLzAF9f2sW9oAQ&open=AZrDJqnLzAF9f2sW9oAQ&pullRequest=123


[warning] 57-57: Use the "RegExp.exec()" method instead.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnLzAF9f2sW9oAP&open=AZrDJqnLzAF9f2sW9oAP&pullRequest=123


[warning] 36-36: Use the "RegExp.exec()" method instead.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnLzAF9f2sW9oAO&open=AZrDJqnLzAF9f2sW9oAO&pullRequest=123


[warning] 87-87: Compare with undefined directly instead of using typeof.

See more on https://sonarcloud.io/project/issues?id=TrustVC_trustvc&issues=AZrDJqnLzAF9f2sW9oAS&open=AZrDJqnLzAF9f2sW9oAS&pullRequest=123

🔇 Additional comments (7)
src/utils/fragment/index.ts (5)

1-11: Imports are clean and well-organized.

The previously commented-out import block has been removed as suggested in prior review. All imports are now in use.


19-33: Well-documented internal helper.

Good JSDoc explaining why this project-level helper exists rather than relying on the upstream library. The implementation correctly checks the DID-signed fragment for revocation status.


35-47: Clean aggregation helper.

The function correctly delegates to isValid for each verification category and returns a well-structured result object.


87-107: W3C status helper functions are correctly implemented.

The functions properly handle the various credential status codes including the combined REVOKED_AND_SUSPENDED state.


138-138: Export statement aligns with public API.

The named exports correctly expose the intended public interface while keeping internal helpers private.

src/utils/network/index.ts (1)

1-20: LGTM! Clean type definitions.

The network constants and type aliases are well-structured. Using as const for the networks array provides type safety, and the derived type aliases are appropriate.

src/utils/supportedChains/index.ts (1)

6-38: LGTM! Well-structured type definitions.

The CHAIN_ID enum and chainInfo type are clearly defined with appropriate field types. The optional fields (explorerApiUrl?, rpcUrl?, gasStation?, nativeCurrency?) provide flexibility for different chain configurations.

@@ -1 +1,203 @@
export * from '@tradetrust-tt/tradetrust-utils/constants/supportedChains';
import 'dotenv/config';

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.

🛠️ Refactor suggestion | 🟠 Major

Move dotenv/config import to the application entry point.

Importing dotenv/config in a utility module creates side effects and can lead to initialization-order issues. The conventional practice is to import it once at the application's entry point (e.g., index.ts or server.ts) before any other modules are loaded.

Remove the import from this file:

-import 'dotenv/config';

And ensure dotenv/config is imported at the top of your application's entry file.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import 'dotenv/config';
🤖 Prompt for AI Agents
In src/utils/supportedChains/index.ts lines 1-1 the file currently imports
'dotenv/config' causing side effects and potential initialization-order issues;
remove that import from this module and instead add a single import
'dotenv/config' at the very top of your application's entry point (e.g.,
src/index.ts or src/server.ts) before any other imports so environment variables
are loaded once at startup.

@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: 0

🧹 Nitpick comments (1)
src/__tests__/token-registry-functions/mint.test.ts (1)

18-19: Local utils imports look good; optional consistency tweak

Switching getEthersContractFromProvider to ../../utils/ethers and CHAIN_ID to the local ../../utils keeps these tests aligned with the new TT-utils consolidation and should be behaviorally equivalent. If CHAIN_ID is ultimately sourced from supportedChains, you could optionally import it from ../../utils/supportedChains (like in transfers.test.ts) to make the source of chain metadata consistent across tests, but this is purely a style/nitpick point.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 129ae68 and 9f0c6dc.

📒 Files selected for processing (3)
  • src/__tests__/token-registry-functions/mint.test.ts (1 hunks)
  • src/__tests__/token-registry-functions/ownerOf.test.ts (1 hunks)
  • src/__tests__/token-registry-functions/transfers.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/tests/token-registry-functions/ownerOf.test.ts
🔇 Additional comments (1)
src/__tests__/token-registry-functions/transfers.test.ts (1)

7-7: Migration to local supportedChains is consistent and safe

Importing CHAIN_ID and SUPPORTED_CHAINS from ../../utils/supportedChains keeps these transfer tests tied to the same chain metadata used in the app, and the gas-station tests still correctly override and restore SUPPORTED_CHAINS[mockChainId].gasStation, so behavior should remain unchanged.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
7.8% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@rongquan1 rongquan1 merged commit 5b997fc into main Nov 27, 2025
27 of 29 checks passed
@rongquan1 rongquan1 deleted the feat/merge-tt-utils branch November 27, 2025 07:43
nghaninn pushed a commit that referenced this pull request Nov 27, 2025
## [2.5.0](v2.4.2...v2.5.0) (2025-11-27)

### Features

* merge tt utils ([#123](#123)) ([5b997fc](5b997fc))
@tradetrustimda

Copy link
Copy Markdown

🎉 This PR is included in version 2.5.0 🎉

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