Skip to content

Polymer hypercore EXSC-169 [PolymerCCTPFacet v3.0.0, ITokenMessenger v1.1.0]#1652

Open
0xDEnYO wants to merge 16 commits into
mainfrom
polymer-hypercore-ex-286
Open

Polymer hypercore EXSC-169 [PolymerCCTPFacet v3.0.0, ITokenMessenger v1.1.0]#1652
0xDEnYO wants to merge 16 commits into
mainfrom
polymer-hypercore-ex-286

Conversation

@0xDEnYO
Copy link
Copy Markdown
Contributor

@0xDEnYO 0xDEnYO commented Mar 16, 2026

Which Jira task belongs to this PR?

Why did I implement it this way?

Checklist before requesting a review

Checklist for reviewer (DO NOT DEPLOY and contracts BEFORE CHECKING THIS!!!)

  • I have checked that any arbitrary calls to external contracts are validated and or restricted
  • I have checked that any privileged calls (i.e. storage modifications) are validated and or restricted
  • I have ensured that any new contracts have had AT A MINIMUM 1 preliminary audit conducted on by <company/auditor>

@lifi-action-bot lifi-action-bot marked this pull request as draft March 16, 2026 00:47
@0xDEnYO 0xDEnYO marked this pull request as ready for review March 16, 2026 00:47
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Updates the PolymerCCTPFacet to support hook data and destination caller parameters in bridge operations, adding conditional burn logic based on hook data presence, extending domain mappings for HyperCore, and updating related deployment metadata and tests. Bumps PolymerCCTPFacet version to 3.0.0 and improves deployment script robustness.

Changes

Cohort / File(s) Summary
Deployment Metadata
deployments/arbitrum.diamond.staging.json, deployments/base.staging.json
Updated AccessManagerFacet version to 1.0.0 on Arbitrum; updated PolymerCCTPFacet address on Base from 0x12B47a94... to 0xF158ac09....
Polymer CCTP Core Implementation
src/Facets/PolymerCCTPFacet.sol, src/Interfaces/ITokenMessenger.sol
Added destinationCaller and hookData fields to PolymerCCTPData struct; introduced conditional burn logic selecting between depositForBurnWithHook (when hookData present) and depositForBurn; extended chainId-to-domainId mapping to include HyperCore domain 19; new depositForBurnWithHook interface function added to ITokenMessenger; version bumped to 3.0.0.
Tests & Deployment Script
test/solidity/Facets/PolymerCCTPFacet.t.sol, script/deploy/deploySingleContract.sh
Updated test setup to initialize new destinationCaller and hookData fields; added two new test cases validating hook data behavior for EVM and non-EVM receivers; expanded chainId-to-domainId mapping test table to 19 entries; improved constructor argument extraction in deploy script with broadcast artifact fallback logic.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • #1630: Modifies PolymerCCTPFacet struct and bridge logic to add destination-related fields and enhance domain mapping behavior.
  • #1731: Updates PolymerCCTPFacet.sol version bumping and extends chainIdToDomainId mappings with HyperCore support.
  • #1581: Modifies PolymerCCTP facet contract and deployment manifest entries in staging configurations.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is largely incomplete; it lacks the Jira task link, implementation rationale, and most reviewer checklist items are unchecked without confirmation of critical security and audit requirements. Add the Jira task link in the first section, provide rationale for implementation choices, and verify or address all unchecked checklist items, especially security validation and audit confirmation before review.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly references the main changes: Polymer hypercore work with specific version updates (PolymerCCTPFacet v3.0.0, ITokenMessenger v1.1.0), and identifies the Jira task (EXSC-169).
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch polymer-hypercore-ex-286

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@lifi-action-bot lifi-action-bot changed the title Polymer hypercore ex-286 Polymer hypercore ex-286 [PolymerCCTPFacet v3.0.0, ITokenMessenger v1.1.0] Mar 16, 2026
@0xDEnYO 0xDEnYO enabled auto-merge (squash) March 16, 2026 00:47
Comment thread src/Facets/PolymerCCTPFacet.sol Dismissed
@0xDEnYO 0xDEnYO changed the title Polymer hypercore ex-286 [PolymerCCTPFacet v3.0.0, ITokenMessenger v1.1.0] Polymer hypercore ex-169 [PolymerCCTPFacet v3.0.0, ITokenMessenger v1.1.0] Mar 16, 2026
@0xDEnYO 0xDEnYO changed the title Polymer hypercore ex-169 [PolymerCCTPFacet v3.0.0, ITokenMessenger v1.1.0] Polymer hypercore EXSC-169 [PolymerCCTPFacet v3.0.0, ITokenMessenger v1.1.0] Mar 16, 2026
@lifi-action-bot
Copy link
Copy Markdown
Collaborator

lifi-action-bot commented Mar 16, 2026

Test Coverage Report

Line Coverage: 88.10% (3216 / 3650 lines)
Function Coverage: 90.53% ( 488 / 539 functions)
Branch Coverage: 71.24% ( 597 / 838 branches)
Test coverage (88.10%) is above min threshold (83%). Check passed.

@0xDEnYO
Copy link
Copy Markdown
Contributor Author

0xDEnYO commented Mar 16, 2026

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 16, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

mirooon
mirooon previously approved these changes Mar 16, 2026
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.

🧹 Nitpick comments (1)
src/Facets/PolymerCCTPFacet.sol (1)

246-267: Consider extracting duplicated hook-routing logic.

The hook-routing conditional (if hookData.length > 0) is duplicated between the EVM (lines 210-231) and non-EVM (lines 246-267) branches. While the current implementation is clear and correct, extracting this into an internal helper could reduce code duplication.

That said, the duplication is minor and the explicit branching improves readability for auditors reviewing the two distinct paths.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Facets/PolymerCCTPFacet.sol` around lines 246 - 267, The hook-routing
conditional (checking _polymerData.hookData.length and calling
TOKEN_MESSENGER.depositForBurnWithHook vs TOKEN_MESSENGER.depositForBurn) is
duplicated in both the EVM and non‑EVM branches; extract that logic into a
single internal helper (e.g., _depositWithOptionalHook or similar) that accepts
the common parameters (bridgeAmount, domainId, mintRecipient, token constant
like USDC, destinationCaller/UNRESTRICTED_DESTINATION_CALLER, maxCCTPFee,
minFinalityThreshold, hookData) and invoke that helper from both places (replace
the two inline if/else blocks with calls to your new internal function) so the
hook routing is centralized while preserving existing behavior and parameter
choices.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/Facets/PolymerCCTPFacet.sol`:
- Around line 246-267: The hook-routing conditional (checking
_polymerData.hookData.length and calling TOKEN_MESSENGER.depositForBurnWithHook
vs TOKEN_MESSENGER.depositForBurn) is duplicated in both the EVM and non‑EVM
branches; extract that logic into a single internal helper (e.g.,
_depositWithOptionalHook or similar) that accepts the common parameters
(bridgeAmount, domainId, mintRecipient, token constant like USDC,
destinationCaller/UNRESTRICTED_DESTINATION_CALLER, maxCCTPFee,
minFinalityThreshold, hookData) and invoke that helper from both places (replace
the two inline if/else blocks with calls to your new internal function) so the
hook routing is centralized while preserving existing behavior and parameter
choices.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dcc088f6-4002-48e6-ba33-298dc9e2e52e

📥 Commits

Reviewing files that changed from the base of the PR and between 31ecb70 and 8bbbc2d.

📒 Files selected for processing (6)
  • .cursor/rules/100-solidity-basics.mdc
  • deployments/arbitrum.diamond.staging.json
  • deployments/arbitrum.staging.json
  • src/Facets/PolymerCCTPFacet.sol
  • src/Interfaces/ITokenMessenger.sol
  • test/solidity/Facets/PolymerCCTPFacet.t.sol

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: 2

🧹 Nitpick comments (1)
deployments/base.diamond.staging.json (1)

72-75: PolymerCCTPFacet Version field is empty but PR title indicates v3.0.0.

The PR title explicitly references "PolymerCCTPFacet v3.0.0", yet the Version field here is an empty string. Consider populating the version for consistency with the PR scope and to support downstream scripts that may rely on version information for tracking or duplicate detection.

Suggested fix
      "0xF158ac0983D6D4eF8Ef65De7B39585B8381Fe570": {
        "Name": "PolymerCCTPFacet",
-        "Version": ""
+        "Version": "3.0.0"
      },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deployments/base.diamond.staging.json` around lines 72 - 75, The JSON entry
for the contract at address "0xF158ac0983D6D4eF8Ef65De7B39585B8381Fe570" lists
"Name": "PolymerCCTPFacet" but has an empty "Version" field; update that
"Version" value to "v3.0.0" (matching the PR title) so downstream tooling and
duplicate-detection scripts can rely on consistent version metadata for the
PolymerCCTPFacet entry.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@script/deploy/deploySingleContract.sh`:
- Around line 381-385: The trailing "0x" cleanup currently only runs when
CONSTRUCTOR_ARGS is >322 chars; remove that hardcoded size gate and run the
cleanup whenever CONSTRUCTOR_ARGS ends with "0x" by changing the outer condition
to only check the suffix (i.e., the "${CONSTRUCTOR_ARGS: -2}" == "0x" check) and
leave the inner alignment check on WITHOUT_TRAILING (the
($((${`#WITHOUT_TRAILING`} % 64)) -eq 2) logic) intact so shorter blobs ending
with "0x" are also fixed; refer to the CONSTRUCTOR_ARGS variable,
WITHOUT_TRAILING local, and the existing alignment check when updating the if
statement.
- Around line 367-378: The current logic sets CONSTRUCTOR_ARGS from the
broadcast JSON using jq with a default of "0x", which prevents the subsequent
fallback parser from running when the field is missing; update the assignment
and check so that CONSTRUCTOR_ARGS is unset/null when the broadcast file lacks
.returns.constructorArgs.value (for example remove the jq default // "0x" or
explicitly convert "null"/"0x" to empty), and adjust the conditional that
triggers the stdout/raw parser to run when CONSTRUCTOR_ARGS is empty or
"null"/"0x"; reference the BROADCAST_JSON lookup and the CONSTRUCTOR_ARGS /
JSON_DATA variables in the block so the fallback parser (the sed/grep/jq
sequence that populates JSON_DATA and then CONSTRUCTOR_ARGS) executes when the
broadcast value is absent.

---

Nitpick comments:
In `@deployments/base.diamond.staging.json`:
- Around line 72-75: The JSON entry for the contract at address
"0xF158ac0983D6D4eF8Ef65De7B39585B8381Fe570" lists "Name": "PolymerCCTPFacet"
but has an empty "Version" field; update that "Version" value to "v3.0.0"
(matching the PR title) so downstream tooling and duplicate-detection scripts
can rely on consistent version metadata for the PolymerCCTPFacet entry.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f61ab3af-8382-440c-8b79-ea2dd255d09b

📥 Commits

Reviewing files that changed from the base of the PR and between 8bbbc2d and 764f941.

📒 Files selected for processing (3)
  • deployments/base.diamond.staging.json
  • deployments/base.staging.json
  • script/deploy/deploySingleContract.sh
✅ Files skipped from review due to trivial changes (1)
  • deployments/base.staging.json

Comment thread script/deploy/deploySingleContract.sh
Comment thread script/deploy/deploySingleContract.sh Outdated
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.

Caution

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

⚠️ Outside diff range comments (1)
script/deploy/deploySingleContract.sh (1)

365-389: ⚠️ Potential issue | 🟠 Major

The new constructor-args extraction is overwritten before it is used.

This block computes and sanitizes CONSTRUCTOR_ARGS, but Line 387 immediately reassigns it from JSON_DATA. When the broadcast artifact path succeeds, JSON_DATA was never populated, so non-empty constructor args can collapse back to 0x. Even in the fallback path, the newline / trailing-0x cleanup here never survives into verification or logging.

🛠️ Proposed fix
   if [[ -z "${CONSTRUCTOR_ARGS:-}" || "$CONSTRUCTOR_ARGS" == "null" ]]; then
     local JSON_DATA
     JSON_DATA=$(echo "$RAW_RETURN_DATA" | sed -n '/{"logs":/,/}$/p' | tr -d '\n' | sed 's/} *$/}/')
     if [[ -z "$JSON_DATA" || "$JSON_DATA" == "" ]]; then
       JSON_DATA=$(echo "$RAW_RETURN_DATA" | grep -o '{"logs":.*}' | tail -1)
     fi
-    CONSTRUCTOR_ARGS=$(echo "$JSON_DATA" | jq -r '.returns.constructorArgs.value // "0x"' 2>/dev/null)
+    CONSTRUCTOR_ARGS=$(echo "$JSON_DATA" | jq -r '.returns.constructorArgs.value // .returns[1].value // "0x"' 2>/dev/null)
   fi
   # Sanitize: forge stdout can embed newline + "0x" in the value, which breaks Etherscan verification
   CONSTRUCTOR_ARGS=$(printf '%s' "${CONSTRUCTOR_ARGS:-0x}" | tr -d '\n\r\t ')
   if [[ ${`#CONSTRUCTOR_ARGS`} -gt 322 && "${CONSTRUCTOR_ARGS: -2}" == "0x" ]]; then
     local WITHOUT_TRAILING="${CONSTRUCTOR_ARGS%0x}"
     if [[ $((${`#WITHOUT_TRAILING`} % 64)) -eq 2 ]]; then
       CONSTRUCTOR_ARGS="$WITHOUT_TRAILING"
     fi
   fi
-
-  CONSTRUCTOR_ARGS=$(echo "$JSON_DATA" | jq -r '.returns.constructorArgs.value // .returns[1].value // "0x"' 2>/dev/null | head -1 | tr -d '\n')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@script/deploy/deploySingleContract.sh` around lines 365 - 389, The computed
and sanitized CONSTRUCTOR_ARGS get clobbered by the later unconditional
reassignment from JSON_DATA; remove or make that reassignment conditional so the
earlier extraction/sanitization (the block that reads BROADCAST_JSON,
RAW_RETURN_DATA, JSON_DATA and the sanitization/trailing-"0x" fix) survives;
specifically, modify or remove the line that does CONSTRUCTOR_ARGS=$(echo
"$JSON_DATA" | jq -r '.returns.constructorArgs.value // .returns[1].value //
"0x"' 2>/dev/null | head -1 | tr -d '\n') so that it only sets CONSTRUCTOR_ARGS
when CONSTRUCTOR_ARGS is empty or unset, leaving the existing sanitized
CONSTRUCTOR_ARGS intact for later validation and logging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@script/deploy/deploySingleContract.sh`:
- Around line 365-389: The computed and sanitized CONSTRUCTOR_ARGS get clobbered
by the later unconditional reassignment from JSON_DATA; remove or make that
reassignment conditional so the earlier extraction/sanitization (the block that
reads BROADCAST_JSON, RAW_RETURN_DATA, JSON_DATA and the
sanitization/trailing-"0x" fix) survives; specifically, modify or remove the
line that does CONSTRUCTOR_ARGS=$(echo "$JSON_DATA" | jq -r
'.returns.constructorArgs.value // .returns[1].value // "0x"' 2>/dev/null | head
-1 | tr -d '\n') so that it only sets CONSTRUCTOR_ARGS when CONSTRUCTOR_ARGS is
empty or unset, leaving the existing sanitized CONSTRUCTOR_ARGS intact for later
validation and logging.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fc93911a-3e06-4345-9030-527075fea66d

📥 Commits

Reviewing files that changed from the base of the PR and between 9b0a969 and 1add319.

📒 Files selected for processing (4)
  • .cursor/rules/100-solidity-basics.mdc
  • deployments/arbitrum.diamond.staging.json
  • deployments/arbitrum.staging.json
  • script/deploy/deploySingleContract.sh
✅ Files skipped from review due to trivial changes (1)
  • deployments/arbitrum.staging.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • deployments/arbitrum.diamond.staging.json
  • .cursor/rules/100-solidity-basics.mdc

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: 2

🧹 Nitpick comments (2)
test/solidity/Facets/PolymerCCTPFacet.t.sol (1)

362-452: Consider adding a negative test for the hook-data path.

Both new tests cover the happy path with non-empty hookData and a non-zero destinationCaller. To strengthen coverage of the new branching introduced in _startBridge, please consider adding:

  1. A test asserting that hookData = "" with a non-zero destinationCaller falls back to depositForBurn (and emits LiFiTransferStarted with the unadjusted flow). This will lock in the fallback semantics in case the condition at lines 210/246 is later changed.
  2. If the source-side validation suggested in the related comment is adopted, a vm.expectRevert(InvalidCallData.selector) test for the hookData != "" && destinationCaller == bytes32(0) case.

Otherwise the new tests look correct — fork-executing against the live TokenMessenger gives reasonable assurance that depositForBurnWithHook is wired up correctly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/solidity/Facets/PolymerCCTPFacet.t.sol` around lines 362 - 452, Add two
negative tests in test/solidity/Facets/PolymerCCTPFacet.t.sol: (1) create a test
(e.g., test_FallbackToDepositForBurnWhenHookEmpty) that sets hookData = "" and a
non-zero destinationCaller, invokes
PolymerCCTPFacet.startBridgeTokensViaPolymerCCTP and asserts the code follows
the depositForBurn path by expecting the LiFiTransferStarted emit with the
unadjusted flow (and any BridgeToNonEVMChainBytes32 emit when appropriate) to
cover the _startBridge fallback to depositForBurn/depositForBurnWithHook; (2)
create a test (e.g., test_RevertWhenHookProvidedButDestinationCallerZero) that
sets hookData != "" and destinationCaller == bytes32(0) and uses
vm.expectRevert(InvalidCallData.selector) before calling
PolymerCCTPFacet.startBridgeTokensViaPolymerCCTP to lock in the source-side
validation behavior. Ensure tests reference depositForBurn,
depositForBurnWithHook, _startBridge, InvalidCallData.selector, and
LiFiTransferStarted so reviewers can locate the covered branches.
src/Facets/PolymerCCTPFacet.sol (1)

210-267: Optional: extract the hook/no-hook branching to remove duplication.

The 22-line block selecting between depositForBurnWithHook and depositForBurn is repeated verbatim in both the EVM and non-EVM paths (only mintRecipient differs). Once mintRecipient and domainId are computed, a single private helper would deduplicate the burn dispatch and reduce the chance of the two branches diverging in future updates.

♻️ Suggested helper extraction
+    function _executeBurn(
+        uint256 _bridgeAmount,
+        uint32 _domainId,
+        bytes32 _mintRecipient,
+        PolymerCCTPData calldata _polymerData
+    ) private {
+        if (_polymerData.hookData.length > 0) {
+            TOKEN_MESSENGER.depositForBurnWithHook(
+                _bridgeAmount,
+                _domainId,
+                _mintRecipient,
+                USDC,
+                _polymerData.destinationCaller,
+                _polymerData.maxCCTPFee,
+                _polymerData.minFinalityThreshold,
+                _polymerData.hookData
+            );
+        } else {
+            TOKEN_MESSENGER.depositForBurn(
+                _bridgeAmount,
+                _domainId,
+                _mintRecipient,
+                USDC,
+                UNRESTRICTED_DESTINATION_CALLER,
+                _polymerData.maxCCTPFee,
+                _polymerData.minFinalityThreshold
+            );
+        }
+    }

Then the two branches in _startBridge collapse to a single call each.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Facets/PolymerCCTPFacet.sol` around lines 210 - 267, Extract the
duplicated branching logic that chooses between
TOKEN_MESSENGER.depositForBurnWithHook and TOKEN_MESSENGER.depositForBurn into a
private helper (e.g., _dispatchCCTPBurn) that accepts domainId, bytes32
mintRecipient, uint256 bridgeAmount, PolymerData _polymerData (or the specific
fields: destinationCaller, maxCCTPFee, minFinalityThreshold, hookData) and calls
depositForBurnWithHook when hookData.length>0 otherwise depositForBurn with
UNRESTRICTED_DESTINATION_CALLER; then replace the two identical blocks in
_startBridge (the EVM path and the non-EVM path that compute mintRecipient) with
a single call to this new helper to remove duplication and keep behavior
identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Facets/PolymerCCTPFacet.sol`:
- Around line 354-356: The inline comment next to the conditional that checks
"chainId == 999 || chainId == LIFI_CHAIN_ID_HYPERCORE" is misleading because it
only mentions HyperEVM; update the trailing comment to indicate both HyperEVM
(999) and HyperCore (LIFI_CHAIN_ID_HYPERCORE) map to domain 19 (e.g., "//
HyperEVM / HyperCore (same domain)"), locating the change at the branch that
uses chainId and the LIFI_CHAIN_ID_HYPERCORE constant which returns 19.
- Around line 210-231: When _polymerData.hookData is non-empty the code passes
_polymerData.destinationCaller into TOKEN_MESSENGER.depositForBurnWithHook
without ensuring it's non-zero, which would allow anyone on the destination to
execute the hook; add a check in the PolymerCCTPFacet flow (the branches that
call depositForBurnWithHook) that reverts if _polymerData.hookData.length > 0
and _polymerData.destinationCaller == bytes32(0) (use a clear revert message),
and apply this validation before calling depositForBurnWithHook so both entry
points startBridgeTokensViaPolymerCCTP and
swapAndStartBridgeTokensViaPolymerCCTP are protected; alternatively (if
intended) update the struct docs for destinationCaller to explicitly allow zero
and describe the security implications.

---

Nitpick comments:
In `@src/Facets/PolymerCCTPFacet.sol`:
- Around line 210-267: Extract the duplicated branching logic that chooses
between TOKEN_MESSENGER.depositForBurnWithHook and
TOKEN_MESSENGER.depositForBurn into a private helper (e.g., _dispatchCCTPBurn)
that accepts domainId, bytes32 mintRecipient, uint256 bridgeAmount, PolymerData
_polymerData (or the specific fields: destinationCaller, maxCCTPFee,
minFinalityThreshold, hookData) and calls depositForBurnWithHook when
hookData.length>0 otherwise depositForBurn with UNRESTRICTED_DESTINATION_CALLER;
then replace the two identical blocks in _startBridge (the EVM path and the
non-EVM path that compute mintRecipient) with a single call to this new helper
to remove duplication and keep behavior identical.

In `@test/solidity/Facets/PolymerCCTPFacet.t.sol`:
- Around line 362-452: Add two negative tests in
test/solidity/Facets/PolymerCCTPFacet.t.sol: (1) create a test (e.g.,
test_FallbackToDepositForBurnWhenHookEmpty) that sets hookData = "" and a
non-zero destinationCaller, invokes
PolymerCCTPFacet.startBridgeTokensViaPolymerCCTP and asserts the code follows
the depositForBurn path by expecting the LiFiTransferStarted emit with the
unadjusted flow (and any BridgeToNonEVMChainBytes32 emit when appropriate) to
cover the _startBridge fallback to depositForBurn/depositForBurnWithHook; (2)
create a test (e.g., test_RevertWhenHookProvidedButDestinationCallerZero) that
sets hookData != "" and destinationCaller == bytes32(0) and uses
vm.expectRevert(InvalidCallData.selector) before calling
PolymerCCTPFacet.startBridgeTokensViaPolymerCCTP to lock in the source-side
validation behavior. Ensure tests reference depositForBurn,
depositForBurnWithHook, _startBridge, InvalidCallData.selector, and
LiFiTransferStarted so reviewers can locate the covered branches.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 636319af-8f62-418c-8633-7d560657d4d7

📥 Commits

Reviewing files that changed from the base of the PR and between 1add319 and 9dd2bb6.

📒 Files selected for processing (4)
  • deployments/arbitrum.diamond.staging.json
  • script/deploy/deploySingleContract.sh
  • src/Facets/PolymerCCTPFacet.sol
  • test/solidity/Facets/PolymerCCTPFacet.t.sol
✅ Files skipped from review due to trivial changes (1)
  • deployments/arbitrum.diamond.staging.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • script/deploy/deploySingleContract.sh

Comment thread src/Facets/PolymerCCTPFacet.sol
Comment thread src/Facets/PolymerCCTPFacet.sol
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
0xDEnYO and others added 3 commits May 15, 2026 18:49
# Conflicts:
#	deployments/arbitrum.diamond.staging.json
- PolymerCCTPFacet: revert with InvalidConfig when hookData is non-empty
  but destinationCaller is bytes32(0); enforces the documented restricted-
  forwarder model on the destination domain. Adds two revert tests.
- PolymerCCTPFacet: update inline comment to reflect that domain 19 covers
  both HyperEVM (chainId 999) and HyperCore (LIFI_CHAIN_ID_HYPERCORE).
- deploySingleContract.sh: switch broadcast-file jq fallback from
  `// "0x"` to `// empty` so the stdout fallback parser runs when the
  broadcast artifact lacks `.returns.constructorArgs.value`. Remove the
  hardcoded 322-char gate on the trailing `0x` cleanup. Drop a redundant
  re-extraction that overwrote the earlier value.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restore the post-sanitize re-extraction step that the previous commit
removed wholesale. The original line was Daniel's fix for newline-
corrupted constructor args coming from forge stdout (commit abba53f,
"remove newline char from constructor args").

The bug it had was running unconditionally, which clobbered a clean
value extracted from the broadcast artifact (Path 1) with an empty
re-read against an unset JSON_DATA. Gate it on JSON_DATA being non-
empty so it only runs in the stdout-fallback path (Path 2), and only
overwrite when the re-extract itself yielded something non-empty.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

4 participants