Skip to content

feat: Enhance MorphTransaction for reference key#19

Open
chengwenxi wants to merge 6 commits intomainfrom
reference-key
Open

feat: Enhance MorphTransaction for reference key#19
chengwenxi wants to merge 6 commits intomainfrom
reference-key

Conversation

@chengwenxi
Copy link
Contributor

@chengwenxi chengwenxi commented Feb 2, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced versioned Morph Transactions (v0 and v1) with enhanced capabilities
    • Added Transaction Reference support to Morph Transactions
    • Added Memo field support to Morph Transactions
    • Expanded Alternative Fee Token functionality
    • Enhanced L1-to-L2 bridging workflow
  • Documentation

    • Updated documentation describing new Morph EVM+ transaction features and L1-to-L2 integration

@coderabbitai
Copy link

coderabbitai bot commented Feb 2, 2026

📝 Walkthrough

Walkthrough

This change introduces versioning and extended metadata support to Morph transactions and receipts by adding version (u8), reference (Option), and memo (Option) fields with version-aware (V0 and V1) encoding/decoding logic, validation rules, and updated RLP extraction in the runtime integration layer.

Changes

Cohort / File(s) Summary
Documentation
README.md
Updated to reflect unified L1-to-L2 bridging narrative, introduced Morph Transaction type 0x7f with enhanced features (Alternative Fee Tokens, Transaction Reference, Memo Field), and restructured hardfork descriptions.
Receipt Types
crates/primitives/src/receipt/mod.rs, crates/primitives/src/receipt/receipt.rs
Added three new optional fields (version, reference, memo) to MorphTransactionReceipt; introduced multiple constructor variants (with_l1_fee, with_morph_tx, with_morph_tx_full) to support legacy and full configurations; added convenience accessors (has_reference, version_or_zero); updated is_morph_tx logic to check fee_token_id, version, or reference presence; propagated new fields through compact representation conversion paths.
Transaction Types
crates/primitives/src/transaction/morph_transaction.rs, crates/primitives/src/transaction/mod.rs
Introduced versioned TxMorph format with MORPH_TX_VERSION_0, MORPH_TX_VERSION_1, MAX_MEMO_LENGTH constants; added version (u8), fee_token_id (u16), reference, and memo fields; implemented version-specific validation, encoding/decoding (including distinct sig_hash logic for V0 vs V1); extended TxMorphExt trait with accessors for version, reference, memo; re-exported new constants from transaction module.
Runtime Integration
crates/revm/src/tx.rs
Extended MorphTxEnv with version, reference, memo fields; refactored RLP extraction by replacing separate fee_token_id/fee_limit extraction with unified extract_morph_tx_fields_from_rlp; added builder methods (with_version, with_reference, with_memo); extended MorphTxExt trait with uses_token_fee and has_reference methods; updated from_tx_with_rlp_bytes to populate new fields when morph_tx_info is present.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • anylots
  • panos-xyz

Poem

🐰 With version and reference in tow,
Our Morph transactions now versioned flow,
V0 and V1 dance through the chain,
Memos and metadata travel the lane,
A richer Reth emerges from the change! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Enhance MorphTransaction for reference key' is directly related to the main changes in the PR, which add reference, version, and memo fields to MorphTransaction and related receipt structures.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch reference-key

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

@chengwenxi chengwenxi marked this pull request as ready for review February 5, 2026 06:17
@chengwenxi chengwenxi requested review from anylots and panos-xyz and removed request for anylots February 5, 2026 06:18
Copy link

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
crates/primitives/src/receipt/mod.rs (1)

522-553: ⚠️ Potential issue | 🟡 Minor

Guard against out-of-range compact version values.

Casting u64u8 can silently truncate if stored data is corrupted or future versions exceed 255. A small guard avoids wraparound.

🛠️ Suggested guard
-                version: version.map(|v| v as u8),
+                version: version.and_then(|v| {
+                    if v <= u8::MAX as u64 { Some(v as u8) } else { None }
+                }),
crates/primitives/src/transaction/morph_transaction.rs (1)

768-817: ⚠️ Potential issue | 🟡 Minor

Avoid silent truncation when decoding compact version.

Casting u64u8 can wrap on corrupted or unexpected data. Consider a safe fallback.

🛠️ Suggested guard
-                version: version as u8,
+                version: u8::try_from(version).unwrap_or(MORPH_TX_VERSION_0),
🤖 Fix all issues with AI agents
In `@crates/primitives/src/receipt/receipt.rs`:
- Around line 177-185: The is_morph_tx predicate currently checks fee_token_id,
version, and reference but misses memo, so receipts with only memo set are not
treated as Morph; update the pub const fn is_morph_tx(&self) -> bool in
receipt.rs to also include self.memo.is_some() in the boolean expression
(alongside self.fee_token_id.is_some(), self.version.is_some(), and
self.reference.is_some()) so memo presence is considered when detecting a
TxMorph.

In `@crates/primitives/src/transaction/morph_transaction.rs`:
- Around line 202-205: The is_v1 method currently uses a ">=" comparison which
treats newer versions as V1; change its logic in the is_v1 function to check
equality against MORPH_TX_VERSION_1 (use "==" with MORPH_TX_VERSION_1) so only
the exact supported version is considered V1, ensuring encoding/decoding
behavior matches.
- Around line 172-193: The validate_version method currently allows Version 0
MorphTx with reference or memo set even though V0 encoding drops those fields;
update MorphTx::validate_version to also reject requests where self.version ==
MORPH_TX_VERSION_0 and (self.reference is non-empty OR self.memo is non-empty)
by returning an Err with a clear message (e.g., "version 0 MorphTx must not
include reference or memo") so in-memory state cannot silently lose data when
roundtripping; keep existing FeeTokenID check and existing handling for
MORPH_TX_VERSION_1 and other versions.

Comment on lines 177 to 185
/// Returns true if this receipt is for a TxMorph.
pub const fn is_morph_tx(&self) -> bool {
self.fee_token_id.is_some()
self.fee_token_id.is_some() || self.version.is_some() || self.reference.is_some()
}

/// Returns true if this receipt has a reference.
pub const fn has_reference(&self) -> bool {
self.reference.is_some()
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Include memo in is_morph_tx detection.

A receipt with only memo set would be treated as non-Morph. Including it keeps the predicate robust to future construction paths.

🛠️ Suggested update
-        self.fee_token_id.is_some() || self.version.is_some() || self.reference.is_some()
+        self.fee_token_id.is_some()
+            || self.version.is_some()
+            || self.reference.is_some()
+            || self.memo.is_some()
📝 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
/// Returns true if this receipt is for a TxMorph.
pub const fn is_morph_tx(&self) -> bool {
self.fee_token_id.is_some()
self.fee_token_id.is_some() || self.version.is_some() || self.reference.is_some()
}
/// Returns true if this receipt has a reference.
pub const fn has_reference(&self) -> bool {
self.reference.is_some()
}
/// Returns true if this receipt is for a TxMorph.
pub const fn is_morph_tx(&self) -> bool {
self.fee_token_id.is_some()
|| self.version.is_some()
|| self.reference.is_some()
|| self.memo.is_some()
}
/// Returns true if this receipt has a reference.
pub const fn has_reference(&self) -> bool {
self.reference.is_some()
}
🤖 Prompt for AI Agents
In `@crates/primitives/src/receipt/receipt.rs` around lines 177 - 185, The
is_morph_tx predicate currently checks fee_token_id, version, and reference but
misses memo, so receipts with only memo set are not treated as Morph; update the
pub const fn is_morph_tx(&self) -> bool in receipt.rs to also include
self.memo.is_some() in the boolean expression (alongside
self.fee_token_id.is_some(), self.version.is_some(), and
self.reference.is_some()) so memo presence is considered when detecting a
TxMorph.

Comment on lines +172 to +193
/// Validates the MorphTx version and its associated field requirements.
///
/// Rules:
/// - Version 0 (legacy format): FeeTokenID must be > 0
/// - Version 1 (with Reference/Memo): FeeTokenID, FeeLimit, Reference, Memo are all optional
/// - Other versions: not supported
pub fn validate_version(&self) -> Result<(), &'static str> {
match self.version {
MORPH_TX_VERSION_0 => {
// Version 0 requires FeeTokenID > 0 (legacy format used for alt-fee transactions)
if self.fee_token_id == 0 {
return Err("version 0 MorphTx requires FeeTokenID > 0");
}
}
MORPH_TX_VERSION_1 => {
// Version 1: FeeTokenID, FeeLimit, Reference, Memo are all optional
// No additional validation needed
}
_ => {
return Err("unsupported MorphTx version");
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Reject reference/memo on V0 to avoid silent data loss.

V0 encoding ignores reference/memo; allowing them produces an in-memory state that won’t roundtrip over the wire.

🛠️ Suggested validation
             MORPH_TX_VERSION_0 => {
                 // Version 0 requires FeeTokenID > 0 (legacy format used for alt-fee transactions)
                 if self.fee_token_id == 0 {
                     return Err("version 0 MorphTx requires FeeTokenID > 0");
                 }
+                if self.reference.is_some() || self.memo.is_some() {
+                    return Err("version 0 MorphTx must not include reference or memo");
+                }
             }
📝 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
/// Validates the MorphTx version and its associated field requirements.
///
/// Rules:
/// - Version 0 (legacy format): FeeTokenID must be > 0
/// - Version 1 (with Reference/Memo): FeeTokenID, FeeLimit, Reference, Memo are all optional
/// - Other versions: not supported
pub fn validate_version(&self) -> Result<(), &'static str> {
match self.version {
MORPH_TX_VERSION_0 => {
// Version 0 requires FeeTokenID > 0 (legacy format used for alt-fee transactions)
if self.fee_token_id == 0 {
return Err("version 0 MorphTx requires FeeTokenID > 0");
}
}
MORPH_TX_VERSION_1 => {
// Version 1: FeeTokenID, FeeLimit, Reference, Memo are all optional
// No additional validation needed
}
_ => {
return Err("unsupported MorphTx version");
}
}
/// Validates the MorphTx version and its associated field requirements.
///
/// Rules:
/// - Version 0 (legacy format): FeeTokenID must be > 0
/// - Version 1 (with Reference/Memo): FeeTokenID, FeeLimit, Reference, Memo are all optional
/// - Other versions: not supported
pub fn validate_version(&self) -> Result<(), &'static str> {
match self.version {
MORPH_TX_VERSION_0 => {
// Version 0 requires FeeTokenID > 0 (legacy format used for alt-fee transactions)
if self.fee_token_id == 0 {
return Err("version 0 MorphTx requires FeeTokenID > 0");
}
if self.reference.is_some() || self.memo.is_some() {
return Err("version 0 MorphTx must not include reference or memo");
}
}
MORPH_TX_VERSION_1 => {
// Version 1: FeeTokenID, FeeLimit, Reference, Memo are all optional
// No additional validation needed
}
_ => {
return Err("unsupported MorphTx version");
}
}
🤖 Prompt for AI Agents
In `@crates/primitives/src/transaction/morph_transaction.rs` around lines 172 -
193, The validate_version method currently allows Version 0 MorphTx with
reference or memo set even though V0 encoding drops those fields; update
MorphTx::validate_version to also reject requests where self.version ==
MORPH_TX_VERSION_0 and (self.reference is non-empty OR self.memo is non-empty)
by returning an Err with a clear message (e.g., "version 0 MorphTx must not
include reference or memo") so in-memory state cannot silently lose data when
roundtripping; keep existing FeeTokenID check and existing handling for
MORPH_TX_VERSION_1 and other versions.

Comment on lines +202 to +205
/// Returns true if this is a version 1 MorphTx (with Reference/Memo).
pub const fn is_v1(&self) -> bool {
self.version >= MORPH_TX_VERSION_1
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

is_v1 should match the supported version exactly.

>= will treat version 2+ as V1 for encoding, but decoding rejects them. Tighten to == until more versions are supported.

🛠️ Suggested fix
-    pub const fn is_v1(&self) -> bool {
-        self.version >= MORPH_TX_VERSION_1
-    }
+    pub const fn is_v1(&self) -> bool {
+        self.version == MORPH_TX_VERSION_1
+    }
📝 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
/// Returns true if this is a version 1 MorphTx (with Reference/Memo).
pub const fn is_v1(&self) -> bool {
self.version >= MORPH_TX_VERSION_1
}
/// Returns true if this is a version 1 MorphTx (with Reference/Memo).
pub const fn is_v1(&self) -> bool {
self.version == MORPH_TX_VERSION_1
}
🤖 Prompt for AI Agents
In `@crates/primitives/src/transaction/morph_transaction.rs` around lines 202 -
205, The is_v1 method currently uses a ">=" comparison which treats newer
versions as V1; change its logic in the is_v1 function to check equality against
MORPH_TX_VERSION_1 (use "==" with MORPH_TX_VERSION_1) so only the exact
supported version is considered V1, ensuring encoding/decoding behavior matches.

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.

1 participant