Skip to content

feat: implement Bill of Exchange functionality in TitleEscrow#66

Open
manishdex25 wants to merge 7 commits into
beta-boefrom
feature/eboe-bill-of-exchange
Open

feat: implement Bill of Exchange functionality in TitleEscrow#66
manishdex25 wants to merge 7 commits into
beta-boefrom
feature/eboe-bill-of-exchange

Conversation

@manishdex25

@manishdex25 manishdex25 commented Jul 9, 2026

Copy link
Copy Markdown
  • Added status management for TitleEscrow with enum for Issued, Accepted, Rejected, and Discharged.
  • Implemented functions to accept, reject, and discharge bills of exchange, updating the status accordingly.
  • Introduced relevant events for state changes and added error handling for invalid status transitions.
  • Updated Hardhat configuration to optimize contract size for TitleEscrowSignable.

Summary

What is the background of this pull request?

Changes

  • What are the changes made in this pull request?
  • Change this and that, etc...

Issues

What are the related issues or stories?

Releases

Channels: latest
ETA: Any target release date

Summary by CodeRabbit

  • New Features

    • Added bill-of-exchange lifecycle tracking with a public status accessor.
    • Added accept, reject, and discharge actions with role-based permissions, state transitions, and corresponding events (including remark support).
  • Bug Fixes

    • Enforced valid status transitions and clarified checks around holder/beneficiary relationships and terminal states.
    • Improved remark validation behavior across action flows, including pause/inactive and token-holding requirements.
  • Tests

    • Added comprehensive E2E and regression coverage for bill-of-exchange behavior, events, remarks, pause/burn/restore flows, and signable escrow interactions.

- Added status management for TitleEscrow with enum for Issued, Accepted, Rejected, and Discharged.
- Implemented functions to accept, reject, and discharge bills of exchange, updating the status accordingly.
- Introduced relevant events for state changes and added error handling for invalid status transitions.
- Updated Hardhat configuration to optimize contract size for TitleEscrowSignable.
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e04a3b7b-bfa5-468f-bb0d-2db4b16716a4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

This PR adds a Bill of Exchange (eBOE) status lifecycle to TitleEscrow contracts: a new Status enum (Issued, Accepted, Rejected, Discharged), a public status field, three role-gated transition functions with events, a corresponding custom error, a compiler override for TitleEscrowSignable, and an extensive new test suite.

Changes

Bill of Exchange status lifecycle

Layer / File(s) Summary
Status contract and transition functions
contracts/TitleEscrow.sol, contracts/interfaces/ITitleEscrow.sol, contracts/interfaces/TitleEscrowErrors.sol
Adds Status enum, public status field, internal _transitionBillOfExchangeStatus helper, and external acceptBillOfExchange/rejectBillOfExchange/dischargeBillOfExchange functions with matching events and an InvalidBillOfExchangeStatus error.
Compiler override
hardhat.config.ts
Adds a Solidity compiler override for TitleEscrowSignable.sol pinning version 0.8.22, optimizer runs to 1, and output limited to storageLayout.
Core transition tests
test/BillOfExchange.test.ts
Sets up fixtures/helpers and tests mint defaults, access control, valid/invalid transitions, and event emission for accept/reject/discharge.
Modifier and role interaction tests
test/BillOfExchange.test.ts
Tests pause/inactive/remark validation modifiers and owner/holder role dynamics against status guards, including financing-driven discharge.
Circulation and regression tests
test/BillOfExchange.test.ts
Confirms endorsement/transfer operations preserve BOE status and that existing ETR functions have no status side effects.
Return/burn/restore and end-to-end tests
test/BillOfExchange.test.ts
Covers returnToIssuer/burn/restore interactions with status and validates happy-path, financing, and re-mint end-to-end flows.
TitleEscrowSignable inheritance tests
test/BillOfExchange.test.ts
Verifies BOE functionality is inherited by TitleEscrowSignable and composes correctly with signature-based transfers.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Holder
  participant Beneficiary
  participant TitleEscrow
  participant TitleEscrowErrors

  Holder->>TitleEscrow: acceptBillOfExchange(remark)
  TitleEscrow->>TitleEscrow: check status == Issued, beneficiary != holder
  alt invalid status
    TitleEscrow->>TitleEscrowErrors: revert InvalidBillOfExchangeStatus
  else valid
    TitleEscrow->>TitleEscrow: status = Accepted, remark updated
    TitleEscrow-->>Holder: emit BillOfExchangeAccepted
  end

  Beneficiary->>TitleEscrow: dischargeBillOfExchange(remark)
  TitleEscrow->>TitleEscrow: check status == Accepted
  alt invalid status
    TitleEscrow->>TitleEscrowErrors: revert InvalidBillOfExchangeStatus
  else valid
    TitleEscrow->>TitleEscrow: status = Discharged, remark updated
    TitleEscrow-->>Beneficiary: emit BillOfExchangeDischarged
  end
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The template sections are present, but Summary, Issues, and Releases are left as placeholders instead of filled out content. Add a real background Summary, the related issue/story links, and release details for Channels and ETA.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly matches the main change: adding Bill of Exchange functionality to TitleEscrow.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/eboe-bill-of-exchange

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
contracts/TitleEscrow.sol (2)

380-428: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix NatSpec doc: dischargeBillOfExchange is caller-restricted to beneficiary, not "Owner".

Line 420 says "Owner discharges the instrument" but the function uses onlyBeneficiary. This is misleading — in this contract, "owner" is ambiguous and could be confused with holder. Update to "Beneficiary" for precision.

📝 Proposed doc fix
-  /// `@notice` Owner discharges the instrument, moving status from Accepted to Discharged.
+  /// `@notice` Beneficiary discharges the instrument, moving status from Accepted to Discharged.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contracts/TitleEscrow.sol` around lines 380 - 428, Update the NatSpec for
dischargeBillOfExchange so it matches the actual access control: the function is
gated by onlyBeneficiary, not an owner role. In TitleEscrow’s
dischargeBillOfExchange docstring, replace “Owner discharges the instrument”
with wording that clearly says the Beneficiary discharges it, keeping the rest
of the status-transition description unchanged.

387-392: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider using bytes memory for the internal helper's remark parameter.

_transitionBillOfExchangeStatus declares _remark as bytes calldata. This works for the three current external callers that pass their calldata parameter directly, but an internal function with calldata cannot accept memory bytes from future internal callers. Since the function only stores the remark (no abi.decode or slicing that benefits from calldata), using bytes memory would be more flexible with negligible gas difference for an internal helper.

♻️ Proposed change
-  function _transitionBillOfExchangeStatus(Status requiredStatus, Status newStatus, bytes calldata _remark) internal {
+  function _transitionBillOfExchangeStatus(Status requiredStatus, Status newStatus, bytes memory _remark) internal {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contracts/TitleEscrow.sol` around lines 387 - 392, _update the internal
helper _transitionBillOfExchangeStatus to take remark as bytes memory instead of
bytes calldata. The current calldata parameter only works for the existing
external paths and blocks future internal callers that pass memory bytes; since
the helper only assigns to remark and does no calldata-specific processing,
switch the parameter type and keep the status/beneficiary checks and assignment
logic unchanged._
contracts/interfaces/ITitleEscrow.sol (1)

12-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add status getter and BOE transition functions to the ITitleEscrow interface.

The contract TitleEscrow implements ITitleEscrow, but the new public status field and the three lifecycle functions (acceptBillOfExchange, rejectBillOfExchange, dischargeBillOfExchange) are not declared in the interface. Consumers interacting through ITitleEscrow cannot call these functions or read the status. The tests access status and the BOE functions directly on the contract instance, but any caller using the interface (e.g., via supportsInterface or typed interactions) would be unable to invoke them.

♻️ Proposed interface additions
   function shred(bytes calldata remark) external;
+
+  function status() external view returns (Status);
+
+  function acceptBillOfExchange(bytes calldata remark) external;
+
+  function rejectBillOfExchange(bytes calldata remark) external;
+
+  function dischargeBillOfExchange(bytes calldata remark) external;
 }

Also applies to: 75-77

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

In `@contracts/interfaces/ITitleEscrow.sol` around lines 12 - 20, The ITitleEscrow
interface is missing the public status getter and the BOE lifecycle methods, so
add declarations for status plus acceptBillOfExchange, rejectBillOfExchange, and
dischargeBillOfExchange to match TitleEscrow’s implemented API. Update the
interface alongside the Status enum so typed callers and interface-based
interactions can read the lifecycle state and invoke the transition functions
through ITitleEscrow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/BillOfExchange.test.ts`:
- Line 2: Prettier formatting is failing in BillOfExchange.test.ts, including
the import statement and several expect(...).to.be.revertedWithCustomError(...)
assertions. Reformat the affected test file to match the project’s Prettier
config, preferably by running the suggested prettier write command so the import
and all listed assertion blocks in BillOfExchange.test.ts are normalized
together.
- Line 885: The typed-data signing in BillOfExchange.test uses
signableEscrow.target for TypedDataDomain.verifyingContract, but that value can
be string | Addressable while the domain requires a string. Update the
endorsement signing setup in the relevant test to pass a string address from
signableEscrow, using the contract’s address accessor (or another string value)
before calling users.holder.signTypedData.

---

Nitpick comments:
In `@contracts/interfaces/ITitleEscrow.sol`:
- Around line 12-20: The ITitleEscrow interface is missing the public status
getter and the BOE lifecycle methods, so add declarations for status plus
acceptBillOfExchange, rejectBillOfExchange, and dischargeBillOfExchange to match
TitleEscrow’s implemented API. Update the interface alongside the Status enum so
typed callers and interface-based interactions can read the lifecycle state and
invoke the transition functions through ITitleEscrow.

In `@contracts/TitleEscrow.sol`:
- Around line 380-428: Update the NatSpec for dischargeBillOfExchange so it
matches the actual access control: the function is gated by onlyBeneficiary, not
an owner role. In TitleEscrow’s dischargeBillOfExchange docstring, replace
“Owner discharges the instrument” with wording that clearly says the Beneficiary
discharges it, keeping the rest of the status-transition description unchanged.
- Around line 387-392: _update the internal helper
_transitionBillOfExchangeStatus to take remark as bytes memory instead of bytes
calldata. The current calldata parameter only works for the existing external
paths and blocks future internal callers that pass memory bytes; since the
helper only assigns to remark and does no calldata-specific processing, switch
the parameter type and keep the status/beneficiary checks and assignment logic
unchanged._
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dce6a803-c7ef-43c9-b3e4-b9977b4d9aed

📥 Commits

Reviewing files that changed from the base of the PR and between 857ac29 and d9b62f2.

📒 Files selected for processing (5)
  • contracts/TitleEscrow.sol
  • contracts/interfaces/ITitleEscrow.sol
  • contracts/interfaces/TitleEscrowErrors.sol
  • hardhat.config.ts
  • test/BillOfExchange.test.ts

Comment thread test/BillOfExchange.test.ts Outdated
Comment thread test/BillOfExchange.test.ts
…ency for verifyingContract

- Removed the mintRejected function from the BillOfExchange tests as it was redundant.
- Updated the type assertion for verifyingContract to ensure it is treated as a string.
- Reformatted import statements for better organization.
- Adjusted expect statements for consistency and clarity in error handling.
- Ensured uniformity in the structure of test cases for better maintainability.
@manishdex25 manishdex25 changed the base branch from master to beta July 10, 2026 08:45
@manishdex25 manishdex25 changed the base branch from beta to beta-boe July 10, 2026 08:47
Comment thread contracts/interfaces/ITitleEscrow.sol Outdated
Comment thread contracts/interfaces/TitleEscrowErrors.sol Outdated
- Reformatted import statements for better organization.
- Adjusted expect statements for consistency and clarity in error handling.
- Ensured uniformity in the structure of test cases for better maintainability.
…/token-registry into feature/eboe-bill-of-exchange
- Changed the status variable to override in TitleEscrow.
- Updated accept, reject, and discharge functions to override their virtual implementations.
- Added status function to contract interfaces for better integration.
- Refactored expect statements for consistency and clarity in error handling.
- Enhanced formatting for better organization and maintainability of test cases.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants