Skip to content

feat: token registry functions#96

Merged
rongquan1 merged 15 commits intomainfrom
feat/v1-updates
Jul 30, 2025
Merged

feat: token registry functions#96
rongquan1 merged 15 commits intomainfrom
feat/v1-updates

Conversation

@Moiz47
Copy link
Copy Markdown
Contributor

@Moiz47 Moiz47 commented Jul 30, 2025

Summary

Adding v1 alpha branch changes to main

Summary by CodeRabbit

  • New Features

    • Introduced a comprehensive suite of token registry functions for minting, transferring, returning, and rejecting tokens, with support for multiple contract and provider versions.
    • Added utilities for transaction options, signer management, and contract version detection.
    • Expanded exports to include new token registry functions for easier integration.
  • Bug Fixes

    • Improved import path resolution for test files.
  • Tests

    • Added extensive unit and end-to-end test suites covering all major token registry operations, error handling, and multi-version compatibility.
    • Introduced new fixtures and utilities to support comprehensive test scenarios.
  • Chores

    • Updated configuration files for improved test environment setup, module resolution, and dependency management.
    • Enhanced TypeScript and Vitest configurations for better developer experience and compatibility.

nghaninn and others added 15 commits June 30, 2025 10:16
* fix: add w3c credential status check (#72)

* fix: add w3c credential status check

* fix: update test

* fix: update enum status codes

* fix: remove console

* chore(release): 1.5.4 [skip ci]

## [1.5.4](v1.5.3...v1.5.4) (2025-06-17)

### Bug Fixes

* add w3c credential status check ([#72](#72)) ([0111cb3](0111cb3))

* fix: upgrade package (#73)

* chore(release): 1.5.5 [skip ci]

## [1.5.5](v1.5.4...v1.5.5) (2025-06-18)

### Bug Fixes

* upgrade package ([#73](#73)) ([3c6c9c7](3c6c9c7))

---------

Co-authored-by: RishabhS7 <59636880+RishabhS7@users.noreply.github.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
## [1.6.0-alpha.1](v1.5.3...v1.6.0-alpha.1) (2025-06-30)

### Features

* token registry functions ([#74](#74)) ([5690fcd](5690fcd))

### Miscellaneous Chores

* back merge ([#75](#75)) ([7cc1891](7cc1891)), closes [#72](#72) [#72](#72) [#73](#73) [#73](#73)
* fix: add w3c credential status check (#72)

* fix: add w3c credential status check

* fix: update test

* fix: update enum status codes

* fix: remove console

* chore(release): 1.5.4 [skip ci]

## [1.5.4](v1.5.3...v1.5.4) (2025-06-17)

### Bug Fixes

* add w3c credential status check ([#72](#72)) ([0111cb3](0111cb3))

* fix: upgrade package (#73)

* chore(release): 1.5.5 [skip ci]

## [1.5.5](v1.5.4...v1.5.5) (2025-06-18)

### Bug Fixes

* upgrade package ([#73](#73)) ([3c6c9c7](3c6c9c7))

* feat: add transfer holder function

* feat: add transfer owners beneficiary

* chore: tests cleanup

* chore: tests cleanup

* fix: remove console

* fix: rever useendorement chain

* fix: remove console

* feat: add reject transfer functions

* chore: trigger rebuild after rebase

* chore(release): 1.5.4 [skip ci]

* add w3c credential status check ([#72](#72)) ([0111cb3](0111cb3))

* feat: add transfer holder function

* feat: add transfer owners beneficiary

* chore: tests cleanup

* fix: remove console

* fix: rever useendorement chain

* feat: add reject transfer functions

* chore: trigger rebuild after rebase

* chore: trigger rebuild after rebase

* feat: token registry return functions

* feat: add mint function

* fix: update fixes

* fix: update tests

* revert: revert changes

---------

Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Ng Han Inn <43451336+nghaninn@users.noreply.github.com>
* feat: add ownerOf function

* feat: add test cases

* fix: update test cases for ownerof function

* fix: update imports

* fix: update imports
## [1.6.0-alpha.2](v1.6.0-alpha.1...v1.6.0-alpha.2) (2025-07-15)

### Features

* mint function ([#78](#78)) ([2ea52ce](2ea52ce)), closes [#72](#72) [#72](#72) [#73](#73) [#73](#73) [#72](#72)
* owner of function ([#79](#79)) ([81d0e36](81d0e36))
* feat: add ownerOf function

* feat: add test cases

* fix: update test cases for ownerof function

* chore: add e2e test for transfer functions

* chore: add e2e test for transfer functions

* feat: add ownerOf function

* feat: add test cases

* fix: update test cases for ownerof function

* chore: add e2e test for transfer functions

* chore: add e2e test for transfer functions

* fix: update mock tests

* fix: update mock test fixtures

* fix: update mock tests for mint and return

* fix: update test script

* fix: update imports

* fix: update gitignore

* fix: delete cache

* fix: update imports
* chore: e2e tests for reject functions

* fix: reject function ethers v6 compatible

* fix: update imports

* fix: mock test cases

* fix: import fixed
* chore: e2e tests for reject functions

* fix: reject function ethers v6 compatible

* fix: update imports

* fix: mock test cases

* fix: static call fixes

* chore: add e2e test cases

* fix: update imports

* fix: update imports

* fix: tests

* fix: mock functions

* fix: change name

* fix: update imports

* fix: update src imports
## [1.6.0-alpha.3](v1.6.0-alpha.2...v1.6.0-alpha.3) (2025-07-18)

### Bug Fixes

* e2e return token tests ([#84](#84)) ([703be01](703be01))

### Miscellaneous Chores

* e2e tests reject transfer ([#83](#83)) ([58a8da2](58a8da2))
* e2e transfers tests ([#82](#82)) ([145e763](145e763))
* fix: add w3c credential status check (#72)

* fix: add w3c credential status check

* fix: update test

* fix: update enum status codes

* fix: remove console

* chore(release): 1.5.4 [skip ci]

## [1.5.4](v1.5.3...v1.5.4) (2025-06-17)

### Bug Fixes

* add w3c credential status check ([#72](#72)) ([0111cb3](0111cb3))

* fix: upgrade package (#73)

* chore(release): 1.5.5 [skip ci]

## [1.5.5](v1.5.4...v1.5.5) (2025-06-18)

### Bug Fixes

* upgrade package ([#73](#73)) ([3c6c9c7](3c6c9c7))

* feat: support passing titleEscrowAddress to fetchEndorsementChain (#80)

Co-authored-by: moiz-sgtradex <moiz.shaikh@sgtradextech.com>

* chore(release): 1.6.0 [skip ci]

## [1.6.0](v1.5.5...v1.6.0) (2025-07-14)

### Features

* support passing titleEscrowAddress to fetchEndorsementChain ([#80](#80)) ([aa7b4f0](aa7b4f0))

* feat: add astron v5 (#81)

Co-authored-by: maxufeng <maxufeng@caict.ac.cn>

* chore(release): 1.7.0 [skip ci]

## [1.7.0](v1.6.0...v1.7.0) (2025-07-15)

### Features

* add astron v5 ([#81](#81)) ([0bebeae](0bebeae))

---------

Co-authored-by: RishabhS7 <59636880+RishabhS7@users.noreply.github.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Ng Han Inn <43451336+nghaninn@users.noreply.github.com>
Co-authored-by: moiz-sgtradex <moiz.shaikh@sgtradextech.com>
Co-authored-by: caict-develop-zhangbo <68949988+caict-develop-zhangbo@users.noreply.github.com>
Co-authored-by: maxufeng <maxufeng@caict.ac.cn>
Co-authored-by: moiz-sgtradex <moiz.shaikh@sgtradextech.com>
## [1.6.0-alpha.4](v1.6.0-alpha.3...v1.6.0-alpha.4) (2025-07-23)

### Bug Fixes

* trigger release ([#86](#86)) ([d2fb6fb](d2fb6fb))

### Miscellaneous Chores

* merge main into v1  ([#85](#85)) ([b81b422](b81b422)), closes [#72](#72) [#72](#72) [#73](#73) [#73](#73) [#80](#80) [#80](#80) [#81](#81) [#81](#81)
* fix: add w3c credential status check (#72)

* fix: add w3c credential status check

* fix: update test

* fix: update enum status codes

* fix: remove console

* chore(release): 1.5.4 [skip ci]

## [1.5.4](v1.5.3...v1.5.4) (2025-06-17)

### Bug Fixes

* add w3c credential status check ([#72](#72)) ([0111cb3](0111cb3))

* fix: upgrade package (#73)

* chore(release): 1.5.5 [skip ci]

## [1.5.5](v1.5.4...v1.5.5) (2025-06-18)

### Bug Fixes

* upgrade package ([#73](#73)) ([3c6c9c7](3c6c9c7))

* feat: support passing titleEscrowAddress to fetchEndorsementChain (#80)

Co-authored-by: moiz-sgtradex <moiz.shaikh@sgtradextech.com>

* chore(release): 1.6.0 [skip ci]

## [1.6.0](v1.5.5...v1.6.0) (2025-07-14)

### Features

* support passing titleEscrowAddress to fetchEndorsementChain ([#80](#80)) ([aa7b4f0](aa7b4f0))

* feat: add astron v5 (#81)

Co-authored-by: maxufeng <maxufeng@caict.ac.cn>

* chore(release): 1.7.0 [skip ci]

## [1.7.0](v1.6.0...v1.7.0) (2025-07-15)

### Features

* add astron v5 ([#81](#81)) ([0bebeae](0bebeae))

* fix: update tradetrust-tt/tradetrust package (#87)

* fix: update tradetrust-tt/tradetrust package

* fix: update version

* fix: update imports

* chore(release): 1.7.1 [skip ci]

## [1.7.1](v1.7.0...v1.7.1) (2025-07-25)

### Bug Fixes

* update tradetrust-tt/tradetrust package ([#87](#87)) ([e4f75a4](e4f75a4))

* fix: upgrade packages (#88)

* chore(release): 1.7.2 [skip ci]

## [1.7.2](v1.7.1...v1.7.2) (2025-07-28)

### Bug Fixes

* upgrade packages ([#88](#88)) ([0cc314e](0cc314e))

* fix: error message types (#89)

* chore(release): 1.7.3 [skip ci]

## [1.7.3](v1.7.2...v1.7.3) (2025-07-28)

### Bug Fixes

* error message types ([#89](#89)) ([d83bada](d83bada))

* fix: upgrade packages (#90)

* chore(release): 1.7.4 [skip ci]

## [1.7.4](v1.7.3...v1.7.4) (2025-07-29)

### Bug Fixes

* upgrade packages ([#90](#90)) ([758651d](758651d))

---------

Co-authored-by: RishabhS7 <59636880+RishabhS7@users.noreply.github.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Ng Han Inn <43451336+nghaninn@users.noreply.github.com>
Co-authored-by: moiz-sgtradex <moiz.shaikh@sgtradextech.com>
Co-authored-by: caict-develop-zhangbo <68949988+caict-develop-zhangbo@users.noreply.github.com>
Co-authored-by: maxufeng <maxufeng@caict.ac.cn>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jul 30, 2025

Walkthrough

This update introduces a comprehensive suite of token registry functions for Ethereum smart contract interaction, supporting both ethers.js v5 and v6 and multiple contract versions (v4 and v5). It adds new modules for minting, transferring, rejecting, returning, and querying tokens, with robust TypeScript typings and utilities. Extensive unit and end-to-end tests validate all functionalities, and configuration files are updated to support these enhancements.

Changes

Cohort / File(s) Change Summary
Token Registry Functionality (Core Implementation)
src/token-registry-functions/types.ts, src/token-registry-functions/transfer.ts, src/token-registry-functions/rejectTransfers.ts, src/token-registry-functions/returnToken.ts, src/token-registry-functions/mint.ts, src/token-registry-functions/ownerOf.ts, src/token-registry-functions/utils.ts, src/token-registry-functions/index.ts
Introduces new modules implementing minting, transferring, rejecting, returning, and querying token ownership for TradeTrustToken contracts, with TypeScript typings, utilities, and support for multiple ethers.js and contract versions. Adds an index for unified exports.
Test Fixtures and Utilities
src/__tests__/e2e/fixtures.ts, src/__tests__/e2e/utils.ts, src/__tests__/token-registry-functions/fixtures.ts
Adds fixtures and utility modules for testing, including mock contracts, signers, providers, and factory functions compatible with ethers v5/v6 and contract versions v4/v5.
End-to-End Test Suites
src/__tests__/e2e/token-registry-functions/transfer.e2e.test.ts, src/__tests__/e2e/token-registry-functions/returnToken.e2e.test.ts, src/__tests__/e2e/token-registry-functions/rejectTransfer.e2e.test.ts
Adds comprehensive E2E test suites for transfer, return, and reject transfer token registry functions, covering multiple ethers and contract versions, success and error scenarios.
Unit Test Suites
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
Adds unit tests for all new token registry functions, validating logic, error handling, and version compatibility.
Project and Test Configuration
.gitignore, package.json, tsconfig.json, vitest.config.ts, hardhat.config.ts
Updates configuration to support E2E and unit testing, adds Hardhat setup, path aliases, and ignores cache directories.
Exports and Core Utilities
src/index.ts, src/core/endorsement-chain/useEndorsementChain.ts
Exports new token registry functions from the main index and generalizes/exports interface support check utility.
Test Import Path Fix
src/__tests__/core/verify.test.ts
Updates import path for a test utility to use a relative path.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant App
  participant TokenRegistryFunctions
  participant EthersProvider
  participant SmartContract

  User->>App: Initiate token registry action (e.g., mint, transfer)
  App->>TokenRegistryFunctions: Call function (e.g., mint, transferHolder)
  TokenRegistryFunctions->>EthersProvider: Connect signer/provider
  TokenRegistryFunctions->>SmartContract: Perform static call (pre-check)
  SmartContract-->>TokenRegistryFunctions: Return pre-check result
  TokenRegistryFunctions->>SmartContract: Send transaction (with params)
  SmartContract-->>TokenRegistryFunctions: Emit transaction receipt/event
  TokenRegistryFunctions-->>App: Return transaction result
  App-->>User: Show result/status
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Possibly related PRs

  • TrustVC/trustvc#79: Also adds and exposes token registry functions, including ownerOf, with similar module structure and exports.
  • TrustVC/trustvc#78: Introduces the mint function and tests, which are now subsumed and extended by this PR.
  • TrustVC/trustvc#74: Adds and tests token registry transfer functions with support for ethers v5/v6 and Title Escrow v4/v5, directly overlapping with this PR's transfer functionality.

Poem

A rabbit hopped through code so wide,
Minting tokens with pride,
Transfers, returns, and rejections too,
Across ethers versions old and new.
With tests that leap and configs that grow,
This registry garden’s ready to sow!
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/v1-updates

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Moiz47 Moiz47 changed the title feat:v1 alpha branch updates feat: v1 alpha branch updates Jul 30, 2025
@Moiz47 Moiz47 requested a review from nghaninn July 30, 2025 06:00
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 29

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

51-51: Remove commented code.

Clean up the commented code to improve readability and maintainability.

   const isV5TT = titleEscrowVersion === 'v5';
-  //   let mockContract = isV5TT ? mockV5TradeTrustTokenContract : mockV4TradeTrustTokenContract;
   const mockTxResponse = titleEscrowVersion === 'v5' ? 'v5_mint_tx_hash' : 'v4_mint_tx_hash';
   const mockBeneficiaryAddress = '0xBeneficiaryAddress';
   const mockHolderAddress = '0xHolderAddress';
-  //   const titleEscrowAddress = isV5TT ? '0xv5contract' : '0xv4contract';
   const mockTradeTrustTokenContract = isV5TT

Also applies to: 67-67

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

62-67: Simplify the return logic.

The conditional return logic can be simplified since the contract type is already determined and the ownerOf method signature is the same for both versions.

-  // Send the actual transaction
-
-  if (isV5TT) {
-    return await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).ownerOf(tokenId);
-  } else if (isV4TT) {
-    return await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).ownerOf(tokenId);
-  }
+  // Query the owner of the token
+  return await tradeTrustTokenContract.ownerOf(tokenId);
src/__tests__/token-registry-functions/rejectTransfers.test.ts (1)

56-61: Remove commented code.

Clean up the commented code to improve readability.

     if (ethersVersion === 'v5') {
       wallet = new WalletV5(PRIVATE_KEY, Provider as any) as ethersV5.Wallet;
-      //   wallet = {
-      //     ...wallet,
-      //     address: '0xcurrent_holder',
-      //     getChainId: vi.fn().mockResolvedValue(CHAIN_ID.mainnet as unknown as number),
-      //   } as any;
       vi.spyOn(wallet, 'getChainId').mockResolvedValue(CHAIN_ID.mainnet as unknown as number);
     } else {
       wallet = new WalletV6(PRIVATE_KEY, Provider as any);
       vi.spyOn(Provider, 'getNetwork').mockResolvedValue({
         chainId: CHAIN_ID.mainnet,
       } as unknown as Network);
-      //   vi.spyOn(wallet, 'getAddress').mockResolvedValue('0xcurrent_holder');
     }

Also applies to: 67-67

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

49-49: Remove commented code

-    // let mockContract = isV5TT ? mockV5TradeTrustTokenContract : mockV4TradeTrustTokenContract;

72-75: Remove commented afterEach block

-
-    // afterEach(() => {
-    //   vi.restoreAllMocks();
-    // });
src/token-registry-functions/mint.ts (2)

59-75: Consider improving type safety

The code casts the signer to any on lines 66 and 73, which bypasses TypeScript's type checking.

Consider using a type guard or conditional types to maintain type safety:

// Example approach
type SignerUnion = Signer | SignerV6;
const typedSigner = isV6EthersProvider(signer.provider) 
  ? signer as SignerV6 
  : signer as Signer;

104-120: Consider simplifying the conditional logic

The function has two separate conditional blocks that could be combined since both conditions are mutually exclusive.

-  if (isV5TT) {
-    return await tradeTrustTokenContract.mint(
-      beneficiaryAddress,
-      holderAddress,
-      tokenId,
-      encryptedRemarks,
-      txOptions,
-    );
-  } else if (isV4TT) {
-    return await tradeTrustTokenContract.mint(
-      beneficiaryAddress,
-      holderAddress,
-      tokenId,
-      txOptions,
-    );
-  }
+  const mintArgs = isV5TT 
+    ? [beneficiaryAddress, holderAddress, tokenId, encryptedRemarks, txOptions]
+    : [beneficiaryAddress, holderAddress, tokenId, txOptions];
+  
+  return await tradeTrustTokenContract.mint(...mintArgs);
src/__tests__/token-registry-functions/returnToken.test.ts (1)

219-219: Remove commented debug code

-      // vi.spyOn(coreModule, 'encrypt').mockReturnValue(mockEncryptedRemarks.slice(2));
src/__tests__/token-registry-functions/transfers.test.ts (1)

88-271: Consider refactoring to reduce test duplication

The test suites for transferHolder, transferBeneficiary, transferOwners, and nominate follow nearly identical patterns. Consider extracting common test scenarios into shared test utilities.

Example approach:

const createTransferTestSuite = (
  functionName: string,
  transferFn: Function,
  getParams: (isV5: boolean) => any,
  getTxHash: (isV5: boolean) => string
) => {
  // Common test implementations
};

Would you like me to create a refactored version that reduces duplication while maintaining test coverage?

Also applies to: 273-447, 449-631, 633-803

src/__tests__/e2e/fixtures.ts (3)

23-36: Provider version detection relies on fragile implementation details

The current approach of detecting provider versions by checking internal properties like _getConnection, getNetwork.length, and connection is fragile and may break with ethers.js updates. Consider using a more robust approach such as checking the constructor name or adding explicit version tracking.

-export const getProviderVersion = (provider: any): 'v5' | 'v6' => {
-  // Check for v6-specific properties
-  if (provider._getConnection || provider.getNetwork?.length === 0) {
-    return 'v6';
-  }
-  // Check for v5-specific properties
-  if (provider.getNetwork?.length === 1 || provider.connection) {
-    return 'v5';
-  }
-  return 'v5'; // default fallback
-};
+export const getProviderVersion = (provider: any): 'v5' | 'v6' => {
+  // Check constructor name first
+  const constructorName = provider.constructor.name;
+  if (constructorName.includes('JsonRpcProvider')) {
+    // For v6, check if it's from the ethersV6 module
+    if (provider instanceof JsonRpcProviderV6) {
+      return 'v6';
+    }
+    // Otherwise assume v5
+    return 'v5';
+  }
+  
+  // Fallback to property checking if constructor name doesn't help
+  if (provider._getConnection || (provider.getNetwork && typeof provider.getNetwork === 'function' && provider.getNetwork.length === 0)) {
+    return 'v6';
+  }
+  return 'v5';
+};

37-44: Misleading function name - returns real providers, not mocks

The function name createMockHardhatProvider suggests it creates mock providers, but it actually returns the real Hardhat providers created at the module level. Consider renaming to better reflect its purpose.

-// Mock hardhat ethers provider for testing
-export const createMockHardhatProvider = (version: 'v5' | 'v6' = 'v5') => {
+// Get hardhat ethers provider for testing
+export const getHardhatProvider = (version: 'v5' | 'v6' = 'v5') => {
   if (version === 'v6') {
     return providerV6;
   }
   return providerV5;
 };

104-123: Unnecessary async functions and incomplete funding implementation

  1. The functions are marked as async but don't perform any asynchronous operations.
  2. The commented-out funding code suggests incomplete implementation.
-// Get multiple signers for ethers v5 (similar to hardhat getSigners)
-export const getSignersV5 = async (count: number = 10): Promise<ethersV5.Wallet[]> => {
+// Get multiple signers for ethers v5 (similar to hardhat getSigners)
+export const getSignersV5 = (count: number = 10): ethersV5.Wallet[] => {
   const privateKeys = generateTestV5PrivateKeys(count);
   const wallets = privateKeys.map((key) => new ethersV5.Wallet(key, providerV5));
-
-  // Fund the wallets from Hardhat's pre-funded account
-  // await fundWalletsV5(wallets);
-
   return wallets;
 };

-// Get multiple signers for ethers v6 (similar to hardhat getSigners)
-export const getSignersV6 = async (count: number = 10): Promise<WalletV6[]> => {
+// Get multiple signers for ethers v6 (similar to hardhat getSigners)
+export const getSignersV6 = (count: number = 10): WalletV6[] => {
   const privateKeys = generateTestV6PrivateKeys(count);
   const wallets = privateKeys.map((key) => new WalletV6(key, providerV6));
-
-  // Fund the wallets from Hardhat's pre-funded account
-  // await fundWalletsV6Simple(wallets);
-
   return wallets;
 };

If wallet funding is needed, consider implementing it as a separate utility function that can be called when needed.

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

366-367: Fragile error message assertions

The tests assert exact error messages which makes them fragile to changes in error wording. Consider using partial matches or error codes instead.

-          expect(error.message).to.include('ERC721: owner query for nonexistent token');
+          expect(error.message.toLowerCase()).to.include('nonexistent token');

-          expect(error.message).to.equal('Only Token Registry V5 is supported');
+          expect(error.message).to.match(/only.*v5.*supported/i);

-          expect(error.message).to.equal(
-            'Pre-check (callStatic) for rejectTransferHolder failed',
-          );
+          expect(error.message).to.include('Pre-check');
+          expect(error.message).to.include('rejectTransferHolder');
+          expect(error.message).to.include('failed');

Also applies to: 522-523, 546-547

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

81-81: Remove or implement the commented resetNonceTracker call

This commented code suggests nonce tracking was considered but not implemented. Either implement proper nonce management or remove this comment to avoid confusion.


287-291: Consider conditional test registration instead of runtime skip

While using this.skip() works, consider conditionally registering the test for better test reporting and clarity.

-      it('should mint token with encrypted remarks (V5 only)', async function () {
-        // Skip this test for V4 as it doesn't support encrypted remarks
-        if (titleEscrowVersion === 'v4') {
-          console.log('Skipping encrypted remarks test for V4');
-          this.skip();
-        }
+      // Only register this test for V5
+      if (titleEscrowVersion === 'v5') {
+        it('should mint token with encrypted remarks (V5 only)', async function () {
src/token-registry-functions/returnToken.ts (2)

57-59: Remove commented code

Remove the commented code to maintain code cleanliness.

-  // Connect V5 contract by default
-  // let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow =
-  //   v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer);

86-104: Add explicit initialization to prevent potential undefined contract

While the earlier version check should prevent this, the contract variable could theoretically be undefined.

   const Contract = getEthersContractFromProvider(signer.provider);
-  // Connect V5 contract by default
-  let titleEscrowContract: ContractV5 | ContractV6;
+  let titleEscrowContract: ContractV5 | ContractV6 | undefined;
   if (isV5TT) {
     titleEscrowContract = new Contract(
       titleEscrowAddress,
       v5Contracts.TitleEscrow__factory.abi,
       // eslint-disable-next-line @typescript-eslint/no-explicit-any
       signer as any,
     );
   } else if (isV4TT) {
     titleEscrowContract = new Contract(
       titleEscrowAddress,
       v4Contracts.TitleEscrow__factory.abi,
       // eslint-disable-next-line @typescript-eslint/no-explicit-any
       signer as any,
     );
   }
+  
+  if (!titleEscrowContract) {
+    throw new Error('Failed to instantiate title escrow contract');
+  }
src/token-registry-functions/transfer.ts (2)

502-502: Remove duplicate comment

There's a duplicate "Check callStatic (dry run)" comment.

   // Check callStatic (dry run)
-  // Check callStatic (dry run)
   try {

38-527: Consider refactoring to reduce code duplication

All four transfer functions share nearly identical structure for version detection, contract instantiation, and transaction execution. This violates DRY principles.

Consider creating a common helper function that handles:

  1. Title escrow address resolution
  2. Version detection
  3. Contract instantiation
  4. CallStatic pre-check
  5. Transaction execution

This would reduce the codebase by ~60% and make maintenance easier. Each function would then only need to specify its unique parameters and method name.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8bba950 and 47aebeb.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (27)
  • .gitignore (1 hunks)
  • hardhat.config.ts (1 hunks)
  • package.json (3 hunks)
  • src/__tests__/core/verify.test.ts (1 hunks)
  • src/__tests__/e2e/fixtures.ts (1 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__/e2e/utils.ts (1 hunks)
  • src/__tests__/token-registry-functions/fixtures.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 (1 hunks)
  • src/core/endorsement-chain/useEndorsementChain.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/token-registry-functions/index.ts (1 hunks)
  • src/token-registry-functions/mint.ts (1 hunks)
  • src/token-registry-functions/ownerOf.ts (1 hunks)
  • src/token-registry-functions/rejectTransfers.ts (1 hunks)
  • src/token-registry-functions/returnToken.ts (1 hunks)
  • src/token-registry-functions/transfer.ts (1 hunks)
  • src/token-registry-functions/types.ts (1 hunks)
  • src/token-registry-functions/utils.ts (1 hunks)
  • tsconfig.json (1 hunks)
  • vitest.config.ts (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/core/endorsement-chain/useEndorsementChain.ts (1)
src/utils/ethers/index.ts (1)
  • getEthersContractFromProvider (24-28)
src/__tests__/token-registry-functions/ownerOf.test.ts (2)
src/token-registry-functions/types.ts (1)
  • ProviderInfo (85-89)
src/__tests__/token-registry-functions/fixtures.ts (6)
  • providerV5 (300-300)
  • providerV6 (301-301)
  • PRIVATE_KEY (298-298)
  • MOCK_V5_ADDRESS (6-6)
  • MOCK_V4_ADDRESS (7-7)
  • MOCK_OWNER_ADDRESS (8-8)
🔇 Additional comments (24)
.gitignore (1)

8-8: LGTM! Clean cache directory exclusion.

The addition of cache/ to the gitignore is appropriate for development tooling and testing infrastructure, preventing transient cache files from being committed.

src/__tests__/core/verify.test.ts (1)

11-11: LGTM! Import path updated for consistency.

The change from absolute to relative import path aligns with the new path mapping configuration in tsconfig.json and maintains consistency with other imports in the file.

tsconfig.json (2)

8-8: LGTM! Proper types for testing frameworks.

Adding "vitest/globals" and "mocha" to the types array provides appropriate TypeScript support for the testing frameworks used in the new test suites.


11-13: LGTM! Clean path mapping configuration.

The "src/*": ["./src/*"] path mapping enables cleaner import paths and aligns with the module resolution alias configured in vitest.config.ts.

vitest.config.ts (3)

7-11: LGTM! Consistent module resolution alias.

The alias configuration 'src/': new URL('./src/', import.meta.url).pathname aligns with the path mapping in tsconfig.json and ensures consistent module resolution across the testing environment.


23-23: LGTM! Global test functions enabled.

Setting globals: true enables global test functions (describe, it, expect) which matches the testing style used in the test files.


34-34: LGTM! Proper separation of test types.

Excluding 'src/__tests__/e2e/**' from regular test runs is a good practice, allowing separation of fast unit tests from slower end-to-end tests.

src/index.ts (1)

23-23: Approve wildcard export of token registry functions

The new export * from './token-registry-functions'; in src/index.ts correctly exposes the token registry API at the main entry point. Verification confirms that src/token-registry-functions/index.ts exists and re-exports the expected functions (transfer, rejectTransfers, returnToken, mint, and ownerOf).

• File: src/index.ts
Line: 23 — export * from './token-registry-functions';
• Verified exports in src/token-registry-functions/index.ts

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

1-5: LGTM! Clean barrel export pattern.

The index file properly aggregates all token registry function exports using a standard barrel export pattern. This provides a clean, centralized entry point for consumers of the token registry functions.

hardhat.config.ts (1)

1-34: LGTM! Well-configured Hardhat setup.

The configuration is properly structured with:

  • Appropriate Solidity version (0.8.20) and optimization settings
  • Reasonable network configurations for local development
  • Extended Mocha timeout (60s) suitable for e2e blockchain tests
  • Correct plugin imports for TypeScript and testing support
src/__tests__/token-registry-functions/mint.test.ts (1)

80-93: LGTM! Comprehensive test setup.

The beforeEach setup properly mocks all necessary dependencies and handles both ethers versions correctly. The interface support and encryption mocks are appropriately configured.

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

8-18: LGTM! Excellent documentation.

The JSDoc documentation is comprehensive and clearly explains the function's purpose, parameters, return value, and error conditions.

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

77-203: LGTM! Comprehensive test coverage.

The test suites for all three reject transfer functions (rejectTransferHolder, rejectTransferBeneficiary, rejectTransferOwners) are well-structured with excellent coverage of:

  • Success scenarios with and without remarks
  • Error handling for missing parameters
  • Provider validation
  • Version compatibility checks
  • Static call failure handling

The consistent test patterns across all three functions ensure reliable validation of the reject transfer functionality.

Also applies to: 205-330, 332-458

src/__tests__/token-registry-functions/fixtures.ts (2)

19-28: LGTM!

The core module mocks are appropriately structured for testing purposes.


82-202: Well-structured mock implementation

The V5 mock contracts correctly implement the ethers v6 pattern where methods have both direct call and staticCall variants. This enables comprehensive testing of both transaction execution and static validation.

src/core/endorsement-chain/useEndorsementChain.ts (1)

148-162: Good refactoring to increase reusability

The function has been appropriately generalized by exporting it and using a more generic parameter name. This enables its use across the newly added token registry modules.

Note: The provider as any cast on line 157 bypasses TypeScript's type checking. While this works, consider addressing the underlying type compatibility issue in a future update.

package.json (1)

13-16: Well-structured e2e test orchestration

The e2e test scripts properly coordinate starting a local Hardhat node, waiting for it to be ready, and running tests. The use of concurrently -k ensures clean process termination.

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

76-105: Comprehensive test coverage for success scenarios

The tests properly cover both auto-detection and explicit version specification paths, with appropriate assertions for factory calls and interface checks.

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

23-58: Well-structured function with proper validation

The function has comprehensive documentation, validates inputs appropriately, and efficiently detects contract versions using parallel promises.

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

89-93: Good handling of ethers version compatibility

The test properly mocks both callStatic (ethers v5) and staticCall (ethers v6) patterns, ensuring compatibility across versions.

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

27-35: Well-implemented version compatibility handling

The function properly handles the differences between ethers v5 (returns number) and v6 (returns bigint) for chain IDs, with appropriate error handling.

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

41-51: Excellent use of discriminated union type

The ContractOptions type effectively ensures that either titleEscrowAddress is provided, or both tokenId and tokenRegistryAddress are required. This provides compile-time safety for the API.

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

199-202: Good test isolation practice

Properly restores the original gas station configuration after the test, preventing interference with other tests.


2-2: Add missing beforeAll import

-import { vi, describe, beforeAll, it, expect } from 'vitest';
+import { vi, describe, beforeAll, it, expect } from 'vitest';

Note: beforeAll is already in the import list, so this appears to be correct. Disregard this comment.

Also applies to: 79-79

Comment on lines +45 to +101
// Generate test private keys (similar to Hardhat's approach)
const generateTestV5PrivateKeys = (count: number): string[] => {
const keys: string[] = [];
// Start with some well-known test keys (same as Hardhat)
const baseKeys = [
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
'0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d',
'0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a',
'0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6',
'0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a',
'0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba',
'0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e',
'0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356',
'0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97',
'0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6',
];

for (let i = 0; i < count; i++) {
if (i < baseKeys.length) {
keys.push(baseKeys[i]);
} else {
// Generate additional keys if needed
const randomKey = ethersV5.Wallet.createRandom().privateKey;
keys.push(randomKey);
}
}

return keys;
};
const generateTestV6PrivateKeys = (count: number): string[] => {
const keys: string[] = [];
// Start with some well-known test keys (same as Hardhat)
const baseKeys = [
'0xf214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897',
'0x701b615bbdfb9de65240bc28bd21bbc0d996645a3dd57e7b12bc2bdf6f192c82',
'0xa267530f49f8280200edf313ee7af6b827f2a8bce2897751d06a843f644967b1',
'0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd',
'0xc526ee95bf44d8fc405a158bb884d9d1238d99f0612e9f33d006bb0789009aaa',
'0x8166f546bab6da521a8369cab06c5d2b9e46670292d85c875ee9ec20e84ffb61',
'0xea6c44ac03bff858b476bba40716402b03e41b8e97e276d1baec7c37d42484a0',
'0x689af8efa8c651a91ad287602527f3af2fe9f6501a7ac4b061667b5a93e037fd',
'0xde9be858da4a475276426320d5e9262ecfc3ba460bfac56360bfa6c4c28b4ee0',
'0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e',
];

for (let i = 0; i < count; i++) {
if (i < baseKeys.length) {
keys.push(baseKeys[i]);
} else {
// Generate additional keys if needed
const randomKey = WalletV6.createRandom().privateKey;
keys.push(randomKey);
}
}

return keys;
};
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

Security consideration and code duplication in test key generation

  1. While these are well-known test keys, consider adding a clear warning comment that these keys should never be used outside of testing.
  2. The two functions generateTestV5PrivateKeys and generateTestV6PrivateKeys have identical logic but different hardcoded keys. This duplication could be reduced.
+// WARNING: These are well-known test private keys. NEVER use these keys in production or with real funds!
+const TEST_KEYS_V5 = [
+  '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
+  '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d',
+  // ... rest of keys
+];
+
+const TEST_KEYS_V6 = [
+  '0xf214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897',
+  '0x701b615bbdfb9de65240bc28bd21bbc0d996645a3dd57e7b12bc2bdf6f192c82',
+  // ... rest of keys
+];
+
+const generateTestPrivateKeys = (count: number, baseKeys: string[], walletCreator: { createRandom: () => { privateKey: string } }): string[] => {
+  const keys: string[] = [];
+  for (let i = 0; i < count; i++) {
+    if (i < baseKeys.length) {
+      keys.push(baseKeys[i]);
+    } else {
+      keys.push(walletCreator.createRandom().privateKey);
+    }
+  }
+  return keys;
+};
+
-const generateTestV5PrivateKeys = (count: number): string[] => {
-  const keys: string[] = [];
-  // Start with some well-known test keys (same as Hardhat)
-  const baseKeys = [
-    '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
-    // ... all keys
-  ];
-
-  for (let i = 0; i < count; i++) {
-    if (i < baseKeys.length) {
-      keys.push(baseKeys[i]);
-    } else {
-      // Generate additional keys if needed
-      const randomKey = ethersV5.Wallet.createRandom().privateKey;
-      keys.push(randomKey);
-    }
-  }
-
-  return keys;
-};
+const generateTestV5PrivateKeys = (count: number): string[] => 
+  generateTestPrivateKeys(count, TEST_KEYS_V5, ethersV5.Wallet);
+
-const generateTestV6PrivateKeys = (count: number): string[] => {
-  // ... duplicate code
-};
+const generateTestV6PrivateKeys = (count: number): string[] => 
+  generateTestPrivateKeys(count, TEST_KEYS_V6, WalletV6);
📝 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
// Generate test private keys (similar to Hardhat's approach)
const generateTestV5PrivateKeys = (count: number): string[] => {
const keys: string[] = [];
// Start with some well-known test keys (same as Hardhat)
const baseKeys = [
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
'0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d',
'0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a',
'0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6',
'0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a',
'0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba',
'0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e',
'0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356',
'0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97',
'0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6',
];
for (let i = 0; i < count; i++) {
if (i < baseKeys.length) {
keys.push(baseKeys[i]);
} else {
// Generate additional keys if needed
const randomKey = ethersV5.Wallet.createRandom().privateKey;
keys.push(randomKey);
}
}
return keys;
};
const generateTestV6PrivateKeys = (count: number): string[] => {
const keys: string[] = [];
// Start with some well-known test keys (same as Hardhat)
const baseKeys = [
'0xf214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897',
'0x701b615bbdfb9de65240bc28bd21bbc0d996645a3dd57e7b12bc2bdf6f192c82',
'0xa267530f49f8280200edf313ee7af6b827f2a8bce2897751d06a843f644967b1',
'0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd',
'0xc526ee95bf44d8fc405a158bb884d9d1238d99f0612e9f33d006bb0789009aaa',
'0x8166f546bab6da521a8369cab06c5d2b9e46670292d85c875ee9ec20e84ffb61',
'0xea6c44ac03bff858b476bba40716402b03e41b8e97e276d1baec7c37d42484a0',
'0x689af8efa8c651a91ad287602527f3af2fe9f6501a7ac4b061667b5a93e037fd',
'0xde9be858da4a475276426320d5e9262ecfc3ba460bfac56360bfa6c4c28b4ee0',
'0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e',
];
for (let i = 0; i < count; i++) {
if (i < baseKeys.length) {
keys.push(baseKeys[i]);
} else {
// Generate additional keys if needed
const randomKey = WalletV6.createRandom().privateKey;
keys.push(randomKey);
}
}
return keys;
};
// WARNING: These are well-known test private keys. NEVER use these keys in production or with real funds!
const TEST_KEYS_V5 = [
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
'0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d',
'0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a',
'0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6',
'0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a',
'0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba',
'0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e',
'0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356',
'0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97',
'0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6',
];
const TEST_KEYS_V6 = [
'0xf214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897',
'0x701b615bbdfb9de65240bc28bd21bbc0d996645a3dd57e7b12bc2bdf6f192c82',
'0xa267530f49f8280200edf313ee7af6b827f2a8bce2897751d06a843f644967b1',
'0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd',
'0xc526ee95bf44d8fc405a158bb884d9d1238d99f0612e9f33d006bb0789009aaa',
'0x8166f546bab6da521a8369cab06c5d2b9e46670292d85c875ee9ec20e84ffb61',
'0xea6c44ac03bff858b476bba40716402b03e41b8e97e276d1baec7c37d42484a0',
'0x689af8efa8c651a91ad287602527f3af2fe9f6501a7ac4b061667b5a93e037fd',
'0xde9be858da4a475276426320d5e9262ecfc3ba460bfac56360bfa6c4c28b4ee0',
'0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e',
];
const generateTestPrivateKeys = (
count: number,
baseKeys: string[],
walletCreator: { createRandom: () => { privateKey: string } }
): string[] => {
const keys: string[] = [];
for (let i = 0; i < count; i++) {
if (i < baseKeys.length) {
keys.push(baseKeys[i]);
} else {
keys.push(walletCreator.createRandom().privateKey);
}
}
return keys;
};
const generateTestV5PrivateKeys = (count: number): string[] =>
generateTestPrivateKeys(count, TEST_KEYS_V5, ethersV5.Wallet);
const generateTestV6PrivateKeys = (count: number): string[] =>
generateTestPrivateKeys(count, TEST_KEYS_V6, WalletV6);
🤖 Prompt for AI Agents
In src/__tests__/e2e/fixtures.ts between lines 45 and 101, add a clear warning
comment above both generateTestV5PrivateKeys and generateTestV6PrivateKeys
functions stating that these keys are for testing only and must never be used in
production or real environments. To reduce duplication, refactor by extracting
the common logic into a single reusable function that accepts the baseKeys array
as a parameter and returns the combined keys, then use this function in both
generateTestV5PrivateKeys and generateTestV6PrivateKeys with their respective
baseKeys.

Comment on lines +54 to +55
providers.forEach(({ ethersVersion, titleEscrowVersion }) => {
describe(`Reject Transfer Functions E2E Tests -with ethers ${ethersVersion} and token registry ${titleEscrowVersion}`, async function () {
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

Remove async from describe callback

The describe function callback should not be marked as async. This is not necessary and may cause unexpected behavior in the test runner.

-providers.forEach(({ ethersVersion, titleEscrowVersion }) => {
-  describe(`Reject Transfer Functions E2E Tests -with ethers ${ethersVersion} and token registry ${titleEscrowVersion}`, async function () {
+providers.forEach(({ ethersVersion, titleEscrowVersion }) => {
+  describe(`Reject Transfer Functions E2E Tests -with ethers ${ethersVersion} and token registry ${titleEscrowVersion}`, function () {
📝 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
providers.forEach(({ ethersVersion, titleEscrowVersion }) => {
describe(`Reject Transfer Functions E2E Tests -with ethers ${ethersVersion} and token registry ${titleEscrowVersion}`, async function () {
providers.forEach(({ ethersVersion, titleEscrowVersion }) => {
describe(`Reject Transfer Functions E2E Tests -with ethers ${ethersVersion} and token registry ${titleEscrowVersion}`, function () {
🤖 Prompt for AI Agents
In src/__tests__/e2e/token-registry-functions/rejectTransfer.e2e.test.ts at
lines 54-55, remove the async keyword from the describe callback function. The
describe function should not be async because it does not support asynchronous
callbacks and marking it async can cause unexpected behavior in the test runner.

Comment on lines +70 to +184
before(async function () {
await network.provider.send('evm_setAutomine', [true]); // Ensure auto-mining
await network.provider.send('hardhat_reset'); // Reset network between tests
// Reset nonce tracker for clean state (especially important for v6)

// Get signers using our custom utility (returns ethers.Wallet[])
// For v6, use unique private keys based on provider index to avoid nonce conflicts
const signers = ethersVersion === 'v5' ? await getSignersV5(11) : await getSignersV6(11); // Larger offset for v6
// const signers = await hardhatEthers.getSigners();
[deployer, owner, newOwner, holder, beneficiary, newHolder, newBeneficiary] = signers;

// Deploy TitleEscrowFactory first
console.log('Deploying TitleEscrowFactory...');
await new Promise((resolve) => setTimeout(resolve, 1000));

const titleEscrowFactory = getVersionedContractFactory(
'TitleEscrowFactory',
ethersVersion,
titleEscrowVersion,
deployer,
);

TitleEscrowFactoryContract = await titleEscrowFactory.deploy();
if (ethersVersion === 'v6') {
await TitleEscrowFactoryContract.waitForDeployment();
} else {
await TitleEscrowFactoryContract.deployTransaction.wait();
}

titleEscrowFactoryAddress =
ethersVersion === 'v5'
? (TitleEscrowFactoryContract as ethers.Contract).address
: (TitleEscrowFactoryContract as ethersV6.Contract).target;

// Deploy TradeTrustToken with proper constructor arguments
console.log('Deploying TradeTrustToken...');
await new Promise((resolve) => setTimeout(resolve, 1000));
const tradeTrustTokenFactory = getVersionedContractFactory(
'TradeTrustToken',
ethersVersion,
titleEscrowVersion,
deployer,
);

// add a time delay here

if (ethersVersion === 'v6') {
const nonce = await providerV6.getTransactionCount(deployer.address, 'pending');
TradeTrustTokenContract = await tradeTrustTokenFactory.deploy(
'Test TradeTrust Token',
'TTT',
titleEscrowFactoryAddress,
{
nonce: nonce,
},
);
} else {
TradeTrustTokenContract = await tradeTrustTokenFactory.deploy(
'Test TradeTrust Token',
'TTT',
titleEscrowFactoryAddress,
);
// await TradeTrustTokenContract.wait();
}

tradeTrustTokenAddress =
ethersVersion === 'v5'
? (TradeTrustTokenContract as ethers.Contract).address
: await (TradeTrustTokenContract as ethersV6.Contract).getAddress();
console.log('TradeTrustToken deployed to:', tradeTrustTokenAddress);

console.log('All mock contracts deployed and initialized for E2E testing');
console.log('Minting token...');
await new Promise((resolve) => setTimeout(resolve, 1000));

const contractOptions: MintTokenOptions = {
tokenRegistryAddress: tradeTrustTokenAddress,
};

const params: MintTokenParams = {
beneficiaryAddress: beneficiary.address, //keeping both initial holder and beneficiary same
holderAddress: holder.address,
tokenId: '0',
remarks: 'Initial mint for testing',
};

const options: TransactionOptions = {
titleEscrowVersion,
chainId: CHAIN_ID.local,
id: 'test-encryption-key',
};

const tx0 = await mint(contractOptions, deployer as unknown as Signer, params, options);
await tx0.wait();
await new Promise((resolve) => setTimeout(resolve, 1000));

titleEscrow = createContract(
await TradeTrustTokenContract.ownerOf('0'),
'TitleEscrow',
ethersVersion,
titleEscrowVersion,
deployer,
);

addresses = {
tokenAddress: tradeTrustTokenAddress,
titleEscrow: titleEscrow.address || titleEscrow.target,
holder: holder.address,
beneficiary: beneficiary.address,
newHolder: newHolder.address,
newBeneficiary: newBeneficiary.address,
owner: owner.address,
newOwner: newOwner.address,
};
});
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

⚠️ Potential issue

Multiple issues in test setup

  1. Using await on getSignersV5/getSignersV6 which should not be async based on the fixtures file
  2. Magic timeout values without explanation
  3. Manual nonce management could lead to race conditions
  4. Commented-out code suggests uncertainty
-      const signers = ethersVersion === 'v5' ? await getSignersV5(11) : await getSignersV6(11);
+      const signers = ethersVersion === 'v5' ? getSignersV5(11) : getSignersV6(11);

+      const DEPLOYMENT_DELAY = 1000; // ms delay between deployments to avoid nonce issues
       console.log('Deploying TitleEscrowFactory...');
-      await new Promise((resolve) => setTimeout(resolve, 1000));
+      await new Promise((resolve) => setTimeout(resolve, DEPLOYMENT_DELAY));

-      // add a time delay here
-
       if (ethersVersion === 'v6') {
+        // Get nonce just before deployment to avoid stale nonce
         const nonce = await providerV6.getTransactionCount(deployer.address, 'pending');

-        // await TradeTrustTokenContract.wait();
       }

Consider using a more robust approach for handling deployment delays and nonce management, such as a deployment helper function that handles these concerns centrally.

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

🤖 Prompt for AI Agents
In src/__tests__/e2e/token-registry-functions/rejectTransfer.e2e.test.ts between
lines 70 and 184, fix the test setup by removing the unnecessary await on
getSignersV5/getSignersV6 calls since they are synchronous, replace magic
timeout values with explicit waits for transaction confirmations or events to
ensure deployments complete, eliminate manual nonce management by relying on the
provider or a centralized deployment helper to handle nonce and transaction
ordering, and remove commented-out code to clarify intent and reduce confusion.

Comment on lines +396 to +524
});

it('should throw error if titleEscrow contract is not version v5', async () => {
const titleEscrowFactoryV4 = getVersionedContractFactory(
'TitleEscrowFactory',
ethersVersion,
'v4',
deployer,
);

const TitleEscrowFactoryContractV4 = await titleEscrowFactoryV4.deploy();
if (ethersVersion === 'v6') {
await TitleEscrowFactoryContractV4.waitForDeployment();
}

const titleEscrowFactoryAddressV4 =
ethersVersion === 'v5'
? (TitleEscrowFactoryContractV4 as ethers.Contract).address
: (TitleEscrowFactoryContractV4 as ethersV6.Contract).target;

// Deploy TradeTrustToken with proper constructor arguments
await new Promise((resolve) => setTimeout(resolve, 1000));
const tradeTrustTokenFactoryV4 = getVersionedContractFactory(
'TradeTrustToken',
ethersVersion,
'v4',
deployer,
);

// add a time delay here
let TradeTrustTokenContractV4: any;
if (ethersVersion === 'v6') {
const nonce = await providerV6.getTransactionCount(deployer.address, 'pending');
TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy(
'Test TradeTrust Token',
'TTT',
titleEscrowFactoryAddressV4,
{
nonce: nonce,
},
);
} else {
TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy(
'Test TradeTrust Token',
'TTT',
titleEscrowFactoryAddressV4,
);
// await TradeTrustTokenContract.wait();
}

const tradeTrustTokenAddressV4 =
ethersVersion === 'v5'
? (TradeTrustTokenContractV4 as ethers.Contract).address
: await (TradeTrustTokenContractV4 as ethersV6.Contract).getAddress();
await new Promise((resolve) => setTimeout(resolve, 1000));

const contractOptions: MintTokenOptions = {
tokenRegistryAddress: tradeTrustTokenAddressV4,
};

const params: MintTokenParams = {
beneficiaryAddress: holder.address, //keeping both initial holder and beneficiary same
holderAddress: holder.address,
tokenId: '0',
remarks: 'Initial mint for testing',
};

const options: TransactionOptions = {
titleEscrowVersion: 'v4',
chainId: CHAIN_ID.local,
id: 'test-encryption-key',
};

const txV4 = await mint(contractOptions, deployer as unknown as Signer, params, options);
await txV4.wait();
await new Promise((resolve) => setTimeout(resolve, 1000));
const titleEscrowv4 = createContract(
await TradeTrustTokenContractV4.ownerOf('0'),
'TitleEscrow',
ethersVersion,
'v4',
deployer,
);
const contractOptionsV4 = {
titleEscrowAddress: (titleEscrowv4.address || titleEscrowv4.target) as string,
};

const paramsV4 = {
newBeneficiaryAddress: addresses.newBeneficiary,
newHolderAddress: addresses.newHolder,
remarks: 'Transfer both roles',
};

const optionsV4 = {
chainId: CHAIN_ID.local,
titleEscrowVersion: 'v4' as const,
id: 'test-encryption-id',
};

// Execute transfer using current holder (newHolder)
const tx = await transferOwners(contractOptionsV4, holder as any, paramsV4, optionsV4);
await tx.wait();
await new Promise((resolve) => setTimeout(resolve, 1000));
const contractOptionsV4Reject = {
titleEscrowAddress: titleEscrowv4.address || titleEscrowv4.target,
};

const paramsV4Reject = {
remarks: 'Reject transfer holder to new address',
};

const optionsV4Reject = {
chainId: CHAIN_ID.local,
titleEscrowVersion: 'v4' as const,
id: 'test-encryption-id',
};

// Execute transfer using type assertion to bypass type issues
try {
await rejectTransferHolder(
contractOptionsV4Reject,
newHolder,
paramsV4Reject,
optionsV4Reject,
);
} catch (error: any) {
expect(error.message).to.equal('Only Token Registry V5 is supported');
}
});
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

Extract duplicate v4 contract deployment logic

This test and similar ones in the file contain duplicate code for deploying v4 contracts. Consider extracting this into a helper function to improve maintainability.

// Add this helper function at the module level
async function deployV4Contracts(ethersVersion: string, deployer: any) {
  const titleEscrowFactoryV4 = getVersionedContractFactory(
    'TitleEscrowFactory',
    ethersVersion,
    'v4',
    deployer,
  );

  const TitleEscrowFactoryContractV4 = await titleEscrowFactoryV4.deploy();
  if (ethersVersion === 'v6') {
    await TitleEscrowFactoryContractV4.waitForDeployment();
  }

  const titleEscrowFactoryAddressV4 =
    ethersVersion === 'v5'
      ? (TitleEscrowFactoryContractV4 as ethers.Contract).address
      : (TitleEscrowFactoryContractV4 as ethersV6.Contract).target;

  // ... rest of the deployment logic
  
  return { titleEscrowv4, tradeTrustTokenAddressV4 };
}

// Then use it in tests:
const { titleEscrowv4 } = await deployV4Contracts(ethersVersion, deployer);
🤖 Prompt for AI Agents
In src/__tests__/e2e/token-registry-functions/rejectTransfer.e2e.test.ts from
lines 396 to 524, the test contains duplicated code for deploying v4 contracts
including TitleEscrowFactory and TradeTrustToken. To fix this, extract the
repeated deployment logic into a reusable helper function at the module level
that accepts ethersVersion and deployer as parameters, performs the deployment
steps, and returns the deployed contract instances or addresses. Then replace
the duplicated code in the test with calls to this helper function to improve
maintainability and reduce redundancy.

}
});

it('should throw error when callStatic rejectTransferHolder fails', async () => {
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

Inconsistent test descriptions

The test description mentions "rejectTransferHolder" but the actual test is for "rejectTransferBeneficiary" and "rejectTransferOwners" respectively.

-        it('should throw error when callStatic rejectTransferHolder fails', async () => {
+        it('should throw error when callStatic rejectTransferBeneficiary fails', async () => {

-        it('should throw error when callStatic rejectTransferHolder fails', async () => {
+        it('should throw error when callStatic rejectTransferOwners fails', async () => {

Also applies to: 1459-1459

🤖 Prompt for AI Agents
In src/__tests__/e2e/token-registry-functions/rejectTransfer.e2e.test.ts at
lines 984 and 1459, the test descriptions incorrectly mention
"rejectTransferHolder" while the tests are actually for
"rejectTransferBeneficiary" and "rejectTransferOwners". Update the test
descriptions to accurately reflect the function being tested by replacing
"rejectTransferHolder" with the correct function names
"rejectTransferBeneficiary" and "rejectTransferOwners" respectively.

);
}

if (!titleEscrowAddress) throw new Error('Token registry address is required');
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

Fix incorrect error messages

The error messages incorrectly state "Token registry address is required" when they should say "Title escrow address is required".

-  if (!titleEscrowAddress) throw new Error('Token registry address is required');
+  if (!titleEscrowAddress) throw new Error('Title escrow address is required');

Also applies to: 211-211

🤖 Prompt for AI Agents
In src/token-registry-functions/rejectTransfers.ts at lines 128 and 211, the
error messages incorrectly state "Token registry address is required" when they
should say "Title escrow address is required". Update the error messages in both
lines to correctly reflect that the title escrow address is required.

Comment on lines +291 to +314
// Check callStatic (dry run)
try {
const isV6 = isV6EthersProvider(signer.provider);
const args = isV5TT ? [encryptedRemarks] : [];

if (isV6) {
await (tradeTrustTokenContract as ContractV6).burn.staticCall(...args);
} else {
await (tradeTrustTokenContract as ContractV5).callStatic.burn(...args);
}
} catch (e) {
console.error('callStatic failed:', e);
throw new Error('Pre-check (callStatic) for acceptReturned failed');
}

const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas);

// Send the actual transaction

if (isV5TT) {
return await tradeTrustTokenContract.burn(tokenId, encryptedRemarks, txOptions);
} else if (isV4TT) {
return await tradeTrustTokenContract.burn(tokenId, txOptions);
}
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

Fix incorrect burn function arguments

The burn function is being called with incorrect arguments. The tokenId parameter is missing in the staticCall but included in the actual transaction with wrong positioning.

   // Check callStatic (dry run)
   try {
     const isV6 = isV6EthersProvider(signer.provider);
-    const args = isV5TT ? [encryptedRemarks] : [];
+    const args = isV5TT ? [tokenId, encryptedRemarks] : [tokenId];

     if (isV6) {
       await (tradeTrustTokenContract as ContractV6).burn.staticCall(...args);
     } else {
       await (tradeTrustTokenContract as ContractV5).callStatic.burn(...args);
     }
   } catch (e) {
     console.error('callStatic failed:', e);
     throw new Error('Pre-check (callStatic) for acceptReturned failed');
   }

   const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas);

   // Send the actual transaction

   if (isV5TT) {
     return await tradeTrustTokenContract.burn(tokenId, encryptedRemarks, txOptions);
   } else if (isV4TT) {
     return await tradeTrustTokenContract.burn(tokenId, txOptions);
   }
📝 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
// Check callStatic (dry run)
try {
const isV6 = isV6EthersProvider(signer.provider);
const args = isV5TT ? [encryptedRemarks] : [];
if (isV6) {
await (tradeTrustTokenContract as ContractV6).burn.staticCall(...args);
} else {
await (tradeTrustTokenContract as ContractV5).callStatic.burn(...args);
}
} catch (e) {
console.error('callStatic failed:', e);
throw new Error('Pre-check (callStatic) for acceptReturned failed');
}
const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas);
// Send the actual transaction
if (isV5TT) {
return await tradeTrustTokenContract.burn(tokenId, encryptedRemarks, txOptions);
} else if (isV4TT) {
return await tradeTrustTokenContract.burn(tokenId, txOptions);
}
// Check callStatic (dry run)
try {
const isV6 = isV6EthersProvider(signer.provider);
const args = isV5TT ? [tokenId, encryptedRemarks] : [tokenId];
if (isV6) {
await (tradeTrustTokenContract as ContractV6).burn.staticCall(...args);
} else {
await (tradeTrustTokenContract as ContractV5).callStatic.burn(...args);
}
} catch (e) {
console.error('callStatic failed:', e);
throw new Error('Pre-check (callStatic) for acceptReturned failed');
}
const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas);
// Send the actual transaction
if (isV5TT) {
return await tradeTrustTokenContract.burn(tokenId, encryptedRemarks, txOptions);
} else if (isV4TT) {
return await tradeTrustTokenContract.burn(tokenId, txOptions);
}
🤖 Prompt for AI Agents
In src/token-registry-functions/returnToken.ts around lines 291 to 314, the burn
function calls have inconsistent and incorrect arguments: the staticCall is
missing the tokenId parameter, and the actual transaction call has tokenId and
encryptedRemarks in the wrong order. Fix this by ensuring both staticCall and
actual burn calls include tokenId as the first argument, followed by
encryptedRemarks if required, matching the function signature and keeping
argument order consistent.

);
}

if (!titleEscrowAddress) throw new Error('Token registry address is required');
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

Fix incorrect error messages for title escrow address checks

Multiple instances where the error message incorrectly states "Token registry address is required" when checking for title escrow address.

-  if (!titleEscrowAddress) throw new Error('Token registry address is required');
+  if (!titleEscrowAddress) throw new Error('Title escrow address is required');

Also applies to: 186-186, 311-311, 450-450

🤖 Prompt for AI Agents
In src/token-registry-functions/transfer.ts at lines 63, 186, 311, and 450, the
error messages incorrectly state "Token registry address is required" when they
should refer to the title escrow address. Update the error messages in these
lines to correctly say "Title escrow address is required" to accurately reflect
the validation being performed.

Comment on lines +110 to +120
// check for current holder and signer
// const currentHolder = await titleEscrowContract.holder();

// if (currentHolder.toLowerCase() === holderAddress.toLowerCase()) {
// throw new Error('Cannot transfer to current holder');
// }
// const signerAddress = await getSignerAddressSafe(signer);
// if (currentHolder.toLowerCase() !== signerAddress.toLowerCase()) {
// throw new Error('Only the current holder can transfer');
// }

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

Remove or implement commented validation logic

Multiple blocks of validation code are commented out. These checks appear to verify:

  • Current holder/beneficiary vs new addresses
  • Signer authorization

Either implement these validations properly or remove the commented code. Leaving them suggests incomplete implementation.

Would you like me to help implement proper validation logic for these transfer functions?

Also applies to: 231-240, 355-371, 491-500

🤖 Prompt for AI Agents
In src/token-registry-functions/transfer.ts around lines 110 to 120, the
commented-out validation code that checks if the current holder matches the new
holder and verifies the signer authorization should be either fully implemented
or removed to avoid incomplete logic. To fix this, uncomment the code and ensure
it correctly fetches the current holder from the contract, compares it
case-insensitively with the holderAddress and signerAddress, and throws
appropriate errors if validations fail. Apply the same approach to the similar
commented code blocks at lines 231-240, 355-371, and 491-500.

Comment on lines +14 to +15
if (!maxFeePerGas || !maxPriorityFeePerGas) {
chainId = chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID);
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

Avoid parameter reassignment and unsafe type assertion

Reassigning parameters and using as unknown as type assertions can lead to issues.

 // If gas values are missing, query gas station if available
 if (!maxFeePerGas || !maxPriorityFeePerGas) {
-  chainId = chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID);
+  const effectiveChainId = chainId ?? (await getChainIdSafe(signer));
+  if (!Object.values(CHAIN_ID).includes(effectiveChainId as any)) {
+    throw new Error(`Unsupported chain ID: ${effectiveChainId}`);
+  }
+  const typedChainId = effectiveChainId as CHAIN_ID;
-  const gasStation = SUPPORTED_CHAINS[chainId]?.gasStation;
+  const gasStation = SUPPORTED_CHAINS[typedChainId]?.gasStation;
🤖 Prompt for AI Agents
In src/token-registry-functions/utils.ts around lines 14 to 15, avoid
reassigning the parameter chainId and using the unsafe type assertion 'as
unknown as CHAIN_ID'. Instead, declare a new local variable to hold the chainId
value and use a safer type assertion or proper type guard when assigning the
result of getChainIdSafe(signer). This prevents side effects from parameter
mutation and improves type safety.

@Moiz47 Moiz47 requested a review from rongquan1 July 30, 2025 06:36
@Moiz47 Moiz47 changed the title feat: v1 alpha branch updates feat: token registry functions Jul 30, 2025
@rongquan1 rongquan1 merged commit 6c379e9 into main Jul 30, 2025
35 of 36 checks passed
@rongquan1 rongquan1 deleted the feat/v1-updates branch July 30, 2025 06:58
nghaninn pushed a commit that referenced this pull request Jul 30, 2025
## [1.8.0](v1.7.4...v1.8.0) (2025-07-30)

### Features

* token registry functions ([#96](#96)) ([6c379e9](6c379e9))
@nghaninn
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.8.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

rongquan1 added a commit that referenced this pull request Aug 15, 2025
* fix: add w3c credential status check (#72)

* fix: add w3c credential status check

* fix: update test

* fix: update enum status codes

* fix: remove console

* chore(release): 1.5.4 [skip ci]

## [1.5.4](v1.5.3...v1.5.4) (2025-06-17)

### Bug Fixes

* add w3c credential status check ([#72](#72)) ([0111cb3](0111cb3))

* fix: upgrade package (#73)

* chore(release): 1.5.5 [skip ci]

## [1.5.5](v1.5.4...v1.5.5) (2025-06-18)

### Bug Fixes

* upgrade package ([#73](#73)) ([3c6c9c7](3c6c9c7))

* feat: support passing titleEscrowAddress to fetchEndorsementChain (#80)

Co-authored-by: moiz-sgtradex <moiz.shaikh@sgtradextech.com>

* chore(release): 1.6.0 [skip ci]

## [1.6.0](v1.5.5...v1.6.0) (2025-07-14)

### Features

* support passing titleEscrowAddress to fetchEndorsementChain ([#80](#80)) ([aa7b4f0](aa7b4f0))

* feat: add astron v5 (#81)

Co-authored-by: maxufeng <maxufeng@caict.ac.cn>

* chore(release): 1.7.0 [skip ci]

## [1.7.0](v1.6.0...v1.7.0) (2025-07-15)

### Features

* add astron v5 ([#81](#81)) ([0bebeae](0bebeae))

* fix: update tradetrust-tt/tradetrust package (#87)

* fix: update tradetrust-tt/tradetrust package

* fix: update version

* fix: update imports

* chore(release): 1.7.1 [skip ci]

## [1.7.1](v1.7.0...v1.7.1) (2025-07-25)

### Bug Fixes

* update tradetrust-tt/tradetrust package ([#87](#87)) ([e4f75a4](e4f75a4))

* fix: upgrade packages (#88)

* chore(release): 1.7.2 [skip ci]

## [1.7.2](v1.7.1...v1.7.2) (2025-07-28)

### Bug Fixes

* upgrade packages ([#88](#88)) ([0cc314e](0cc314e))

* fix: error message types (#89)

* chore(release): 1.7.3 [skip ci]

## [1.7.3](v1.7.2...v1.7.3) (2025-07-28)

### Bug Fixes

* error message types ([#89](#89)) ([d83bada](d83bada))

* fix: upgrade packages (#90)

* chore(release): 1.7.4 [skip ci]

## [1.7.4](v1.7.3...v1.7.4) (2025-07-29)

### Bug Fixes

* upgrade packages ([#90](#90)) ([758651d](758651d))

* feat: token registry functions (#96)

* chore(release): 1.8.0 [skip ci]

## [1.8.0](v1.7.4...v1.8.0) (2025-07-30)

### Features

* token registry functions ([#96](#96)) ([6c379e9](6c379e9))

* fix: accept return function (#97)

* chore(release): 1.8.1 [skip ci]

## [1.8.1](v1.8.0...v1.8.1) (2025-08-07)

### Bug Fixes

* accept return function ([#97](#97)) ([6398017](6398017))

* fix: update edsa w3c verifier

* fix: update vefiable doc v2.0

* feat: token registry functions (#74)

* chore(release): 1.6.0-alpha.1 [skip ci]

## [1.6.0-alpha.1](v1.5.3...v1.6.0-alpha.1) (2025-06-30)

### Features

* token registry functions ([#74](#74)) ([5690fcd](5690fcd))

### Miscellaneous Chores

* back merge ([#75](#75)) ([7cc1891](7cc1891)), closes [#72](#72) [#72](#72) [#73](#73) [#73](#73)

* feat: mint function (#78)

* fix: add w3c credential status check (#72)

* fix: add w3c credential status check

* fix: update test

* fix: update enum status codes

* fix: remove console

* chore(release): 1.5.4 [skip ci]

## [1.5.4](v1.5.3...v1.5.4) (2025-06-17)

### Bug Fixes

* add w3c credential status check ([#72](#72)) ([0111cb3](0111cb3))

* fix: upgrade package (#73)

* chore(release): 1.5.5 [skip ci]

## [1.5.5](v1.5.4...v1.5.5) (2025-06-18)

### Bug Fixes

* upgrade package ([#73](#73)) ([3c6c9c7](3c6c9c7))

* feat: add transfer holder function

* feat: add transfer owners beneficiary

* chore: tests cleanup

* chore: tests cleanup

* fix: remove console

* fix: rever useendorement chain

* fix: remove console

* feat: add reject transfer functions

* chore: trigger rebuild after rebase

* chore(release): 1.5.4 [skip ci]

* add w3c credential status check ([#72](#72)) ([0111cb3](0111cb3))

* feat: add transfer holder function

* feat: add transfer owners beneficiary

* chore: tests cleanup

* fix: remove console

* fix: rever useendorement chain

* feat: add reject transfer functions

* chore: trigger rebuild after rebase

* chore: trigger rebuild after rebase

* feat: token registry return functions

* feat: add mint function

* fix: update fixes

* fix: update tests

* revert: revert changes

---------

Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Ng Han Inn <43451336+nghaninn@users.noreply.github.com>

* feat: owner of function (#79)

* feat: add ownerOf function

* feat: add test cases

* fix: update test cases for ownerof function

* fix: update imports

* fix: update imports

* chore(release): 1.6.0-alpha.2 [skip ci]

## [1.6.0-alpha.2](v1.6.0-alpha.1...v1.6.0-alpha.2) (2025-07-15)

### Features

* mint function ([#78](#78)) ([2ea52ce](2ea52ce)), closes [#72](#72) [#72](#72) [#73](#73) [#73](#73) [#72](#72)
* owner of function ([#79](#79)) ([81d0e36](81d0e36))

* chore: e2e transfers tests (#82)

* feat: add ownerOf function

* feat: add test cases

* fix: update test cases for ownerof function

* chore: add e2e test for transfer functions

* chore: add e2e test for transfer functions

* feat: add ownerOf function

* feat: add test cases

* fix: update test cases for ownerof function

* chore: add e2e test for transfer functions

* chore: add e2e test for transfer functions

* fix: update mock tests

* fix: update mock test fixtures

* fix: update mock tests for mint and return

* fix: update test script

* fix: update imports

* fix: update gitignore

* fix: delete cache

* fix: update imports

* chore: e2e tests reject transfer (#83)

* chore: e2e tests for reject functions

* fix: reject function ethers v6 compatible

* fix: update imports

* fix: mock test cases

* fix: import fixed

* fix: e2e return token tests (#84)

* chore: e2e tests for reject functions

* fix: reject function ethers v6 compatible

* fix: update imports

* fix: mock test cases

* fix: static call fixes

* chore: add e2e test cases

* fix: update imports

* fix: update imports

* fix: tests

* fix: mock functions

* fix: change name

* fix: update imports

* fix: update src imports

* chore(release): 1.6.0-alpha.3 [skip ci]

## [1.6.0-alpha.3](v1.6.0-alpha.2...v1.6.0-alpha.3) (2025-07-18)

### Bug Fixes

* e2e return token tests ([#84](#84)) ([703be01](703be01))

### Miscellaneous Chores

* e2e tests reject transfer ([#83](#83)) ([58a8da2](58a8da2))
* e2e transfers tests ([#82](#82)) ([145e763](145e763))

* chore: merge main into v1  (#85)

* fix: add w3c credential status check (#72)

* fix: add w3c credential status check

* fix: update test

* fix: update enum status codes

* fix: remove console

* chore(release): 1.5.4 [skip ci]

## [1.5.4](v1.5.3...v1.5.4) (2025-06-17)

### Bug Fixes

* add w3c credential status check ([#72](#72)) ([0111cb3](0111cb3))

* fix: upgrade package (#73)

* chore(release): 1.5.5 [skip ci]

## [1.5.5](v1.5.4...v1.5.5) (2025-06-18)

### Bug Fixes

* upgrade package ([#73](#73)) ([3c6c9c7](3c6c9c7))

* feat: support passing titleEscrowAddress to fetchEndorsementChain (#80)

Co-authored-by: moiz-sgtradex <moiz.shaikh@sgtradextech.com>

* chore(release): 1.6.0 [skip ci]

## [1.6.0](v1.5.5...v1.6.0) (2025-07-14)

### Features

* support passing titleEscrowAddress to fetchEndorsementChain ([#80](#80)) ([aa7b4f0](aa7b4f0))

* feat: add astron v5 (#81)

Co-authored-by: maxufeng <maxufeng@caict.ac.cn>

* chore(release): 1.7.0 [skip ci]

## [1.7.0](v1.6.0...v1.7.0) (2025-07-15)

### Features

* add astron v5 ([#81](#81)) ([0bebeae](0bebeae))

---------

Co-authored-by: RishabhS7 <59636880+RishabhS7@users.noreply.github.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Ng Han Inn <43451336+nghaninn@users.noreply.github.com>
Co-authored-by: moiz-sgtradex <moiz.shaikh@sgtradextech.com>
Co-authored-by: caict-develop-zhangbo <68949988+caict-develop-zhangbo@users.noreply.github.com>
Co-authored-by: maxufeng <maxufeng@caict.ac.cn>

* fix: trigger release (#86)

Co-authored-by: moiz-sgtradex <moiz.shaikh@sgtradextech.com>

* chore(release): 1.6.0-alpha.4 [skip ci]

## [1.6.0-alpha.4](v1.6.0-alpha.3...v1.6.0-alpha.4) (2025-07-23)

### Bug Fixes

* trigger release ([#86](#86)) ([d2fb6fb](d2fb6fb))

### Miscellaneous Chores

* merge main into v1  ([#85](#85)) ([b81b422](b81b422)), closes [#72](#72) [#72](#72) [#73](#73) [#73](#73) [#80](#80) [#80](#80) [#81](#81) [#81](#81)

* chore: rebase v1 with main (#95)

* fix: add w3c credential status check (#72)

* fix: add w3c credential status check

* fix: update test

* fix: update enum status codes

* fix: remove console

* chore(release): 1.5.4 [skip ci]

* add w3c credential status check ([#72](#72)) ([0111cb3](0111cb3))

* fix: upgrade package (#73)

* chore(release): 1.5.5 [skip ci]

* upgrade package ([#73](#73)) ([3c6c9c7](3c6c9c7))

* feat: support passing titleEscrowAddress to fetchEndorsementChain (#80)

Co-authored-by: moiz-sgtradex <moiz.shaikh@sgtradextech.com>

* chore(release): 1.6.0 [skip ci]

* support passing titleEscrowAddress to fetchEndorsementChain ([#80](#80)) ([aa7b4f0](aa7b4f0))

* feat: add astron v5 (#81)

Co-authored-by: maxufeng <maxufeng@caict.ac.cn>

* chore(release): 1.7.0 [skip ci]

* add astron v5 ([#81](#81)) ([0bebeae](0bebeae))

* fix: update tradetrust-tt/tradetrust package (#87)

* fix: update tradetrust-tt/tradetrust package

* fix: update version

* fix: update imports

* chore(release): 1.7.1 [skip ci]

* update tradetrust-tt/tradetrust package ([#87](#87)) ([e4f75a4](e4f75a4))

* fix: upgrade packages (#88)

* chore(release): 1.7.2 [skip ci]

* upgrade packages ([#88](#88)) ([0cc314e](0cc314e))

* fix: error message types (#89)

* chore(release): 1.7.3 [skip ci]

* error message types ([#89](#89)) ([d83bada](d83bada))

* fix: upgrade packages (#90)

* chore(release): 1.7.4 [skip ci]

* upgrade packages ([#90](#90)) ([758651d](758651d))

---------

Co-authored-by: RishabhS7 <59636880+RishabhS7@users.noreply.github.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Ng Han Inn <43451336+nghaninn@users.noreply.github.com>
Co-authored-by: moiz-sgtradex <moiz.shaikh@sgtradextech.com>
Co-authored-by: caict-develop-zhangbo <68949988+caict-develop-zhangbo@users.noreply.github.com>
Co-authored-by: maxufeng <maxufeng@caict.ac.cn>

* fix: add w3c credential status check (#72)

* fix: add w3c credential status check

* fix: update test

* fix: update enum status codes

* fix: remove console

* chore(release): 1.5.4 [skip ci]

* add w3c credential status check ([#72](#72)) ([0111cb3](0111cb3))

* fix: upgrade package (#73)

* chore(release): 1.5.5 [skip ci]

* upgrade package ([#73](#73)) ([3c6c9c7](3c6c9c7))

* fix: update edsa w3c verifier

* fix: resolve conflicts

* fix: rebase

* fix: resolve conflicts

* fix: update package lock

* fix: resolve conflicts

* fix: verify test

* fix: cryptosuit types

---------

Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Ng Han Inn <43451336+nghaninn@users.noreply.github.com>
Co-authored-by: Moiz Shaikh <58319530+Moiz47@users.noreply.github.com>
Co-authored-by: moiz-sgtradex <moiz.shaikh@sgtradextech.com>
Co-authored-by: caict-develop-zhangbo <68949988+caict-develop-zhangbo@users.noreply.github.com>
Co-authored-by: maxufeng <maxufeng@caict.ac.cn>
Co-authored-by: rongquan1 <rongquan.low@gmail.com>
nghaninn pushed a commit that referenced this pull request Aug 19, 2025
## [1.6.0-alpha.5](v1.6.0-alpha.4...v1.6.0-alpha.5) (2025-08-19)

### Bug Fixes

* add w3c version detection function ([#103](#103)) ([3270cc6](3270cc6))

### Miscellaneous Chores

* ecdsa w3c verify ([#100](#100)) ([484e1ff](484e1ff)), closes [#72](#72) [#72](#72) [#73](#73) [#73](#73) [#80](#80) [#80](#80) [#81](#81) [#81](#81) [#87](#87) [#87](#87) [#88](#88) [#88](#88) [#89](#89) [#89](#89) [#90](#90) [#90](#90) [#96](#96) [#96](#96) [#97](#97) [#97](#97) [#74](#74) [#74](#74) [#72](#72) [#72](#72) [#73](#73) [#73](#73) [#78](#78) [#72](#72) [#72](#72) [#73](#73) [#73](#73) [#72](#72)
* rebase v1 with main ([#95](#95)) ([b54b146](b54b146)), closes [#72](#72) [#72](#72) [#73](#73) [#73](#73) [#80](#80) [#80](#80) [#81](#81) [#81](#81) [#87](#87) [#87](#87) [#88](#88) [#88](#88) [#89](#89) [#89](#89) [#90](#90) [#90](#90)
@nghaninn
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.6.0-alpha.5 🎉

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.

6 participants