Skip to content

Conversation

@mirooon
Copy link
Contributor

@mirooon mirooon commented Oct 10, 2025

Which Jira task belongs to this PR?

LF-14786

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>

…e identifier, enhanced EverclearData struct with additional parameters, and added validation checks for receiver addresses. Introduced new unit tests for error handling on invalid output assets and receiver addresses
…Everclear protocol description, refined the EverclearData struct with detailed parameters, and added error handling for bridging to non-EVM chains. Introduced new unit tests for bridging functionality and validation of receiver addresses.
…meter to EverclearData struct, updated transaction execution to include native fees, and enhanced demo script for bridging functionality. Introduced unit tests to validate behavior with native assets and ensure proper error handling.
…clearFacet tests: Deleted MessageHashUtils.sol, updated EverclearFacetTest to include a local implementation of the toEthSignedMessageHash function, and added a MockEverclearFeeAdapter for testing native fee handling.
…ployed address in JSON logs, added support for Non-EVM chain handling in demo script, and refined ABI decoding logic for better compatibility with both EVM and Non-EVM chains
… from Arbitrum to Solana to enhance logging and traceability.
@lifi-action-bot lifi-action-bot marked this pull request as draft October 10, 2025 10:10
/// @dev Contains the business logic for the bridge via Everclear
/// @param _bridgeData The core information needed for bridging
/// @param _everclearData Data specific to Everclear
function _startBridge(

Check notice

Code scanning / Olympix Integrated Security

Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events

Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events
}

// destination chain is non-EVM
FEE_ADAPTER.newIntent{ value: _everclearData.nativeFee }( // value is ONLY the fee for the intent, FEE_ADAPTER does NOT handle the native token as an asset

Check warning

Code scanning / Olympix Integrated Security

Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call

Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
// destination chain is EVM
// make sure that bridgeData and everclearData receiver addresses match
if (
bytes32(uint256(uint160(_bridgeData.receiver))) !=

Check notice

Code scanning / Olympix Integrated Security

Performing a narrowing downcast may result in silent overflow due to bit truncation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unsafe-downcast

Performing a narrowing downcast may result in silent overflow due to bit truncation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unsafe-downcast
uint32[] memory destinationChainIds = new uint32[](1);
destinationChainIds[0] = uint32(_bridgeData.destinationChainId);

FEE_ADAPTER.newIntent{ value: _everclearData.nativeFee }( // value is ONLY the fee for the intent, FEE_ADAPTER does NOT handle the native token as an asset

Check warning

Code scanning / Olympix Integrated Security

Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call

Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
/// @dev Contains the business logic for the bridge via Everclear
/// @param _bridgeData The core information needed for bridging
/// @param _everclearData Data specific to Everclear
function _startBridge(

Check notice

Code scanning / Olympix Integrated Security

Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events

Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events
}

// destination chain is non-EVM
FEE_ADAPTER_V2.newIntent{ value: _everclearData.nativeFee }( // value is ONLY the fee for the intent, FEE_ADAPTER_V2 does NOT handle the native token as an asset

Check warning

Code scanning / Olympix Integrated Security

Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call

Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
// destination chain is EVM
// make sure that bridgeData and everclearData receiver addresses match
if (
bytes32(uint256(uint160(_bridgeData.receiver))) !=

Check notice

Code scanning / Olympix Integrated Security

Performing a narrowing downcast may result in silent overflow due to bit truncation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unsafe-downcast

Performing a narrowing downcast may result in silent overflow due to bit truncation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unsafe-downcast
uint32[] memory destinationChainIds = new uint32[](1);
destinationChainIds[0] = uint32(_bridgeData.destinationChainId);

FEE_ADAPTER_V2.newIntent{ value: _everclearData.nativeFee }( // value is ONLY the fee for the intent, FEE_ADAPTER_V2 does NOT handle the native token as an asset

Check warning

Code scanning / Olympix Integrated Security

Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call

Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 10, 2025

Walkthrough

Adds Everclear integration: new EverclearFacet and IEverclearFeeAdapter, configuration and deployment entries, deploy/update scripts, demo and helper utilities, extensive Solidity tests, docs, and minor periphery/template import and license adjustments.

Changes

Cohort / File(s) Summary
Core Facet & Interface
src/Facets/EverclearFacet.sol, src/Interfaces/IEverclearFeeAdapter.sol
New EverclearFacet with immutable FEE_ADAPTER, EverclearData struct, UnsupportedEverclearChainId error, entry points startBridgeTokensViaEverclear and swapAndStartBridgeTokensViaEverclear, internal _startBridge; new IEverclearFeeAdapter interface with FeeParams/Intent structs and overloaded newIntent, updateFeeSigner, owner.
Configuration
config/everclear.json
New JSON config mapping feeAdapter addresses for mainnet, base, optimism, and arbitrum.
Deployments / Manifests
deployments/_deployments_log_file.json, deployments/arbitrum.diamond.staging.json, deployments/arbitrum.staging.json
Added EverclearFacet deployment metadata (staging/production entries in log); added multiple facet entries (RelayDepositoryFacet, DexManagerFacet, EverclearFacet v1/v2) in Arbitrum staging diamond, updated Periphery.Permit2Proxy address and minor reordering.
Deployment Scripts
script/deploy/facets/DeployEverclearFacet.s.sol, script/deploy/facets/UpdateEverclearFacet.s.sol
New deploy script DeployEverclearFacet.s.sol that reads config/everclear.json to build constructor args and deploys EverclearFacet; update script UpdateEverclearFacet.s.sol to run update("EverclearFacet").
Tests
test/solidity/Facets/EverclearFacet.t.sol
New comprehensive Solidity test suite (TestEverclearFacet, EverclearFacetTest) covering bridge flows, swap+bridge, native-fee, non-EVM scenarios, revert cases, fuzz tests, and utilities.
Docs & Demo Helpers
docs/EverclearFacet.md, script/demoScripts/utils/demoScriptHelpers.ts, script/demoScripts/demoEverclear.ts
Added EverclearFacet documentation; new helper addressToBytes32LeftPadded(address: string); new demo script orchestrating Everclear bridge flow and decoding fee adapter calldata.
Periphery & Templates
src/Periphery/LiFiDEXAggregator.sol, templates/facet.template.hbs
Split out IERC20Permit import, changed template SPDX to SPDX-LGPL-3.0-only, added imports for LibDiamond, LibAsset, LibSwap, and adjusted title annotation spacing in template.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Files/areas to focus on:
    • src/Facets/EverclearFacet.sol: EVM vs non-EVM branching, native-fee handling, ERC20 approvals, event emissions, and constructor wiring to config.
    • src/Interfaces/IEverclearFeeAdapter.sol: struct layouts and overloaded ABI signatures for correctness.
    • test/solidity/Facets/EverclearFacet.t.sol: test assumptions around signatures/fee decoding and revert coverage.
    • Deployment scripts/manifests: JSON path resolution, constructor arg encoding, and Permit2Proxy address change.

Possibly related PRs

Suggested labels

AuditNotRequired

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete; while it references the Jira ticket and includes a checklist, critical sections are missing: no explanation of implementation rationale, tests are not confirmed as added, new facet checklist is unchecked, documentation updates are unchecked, and security/audit checklists are unchecked. Complete the missing sections: explain implementation rationale, confirm test coverage, verify new-facet checklist completion, document updates made, and confirm preliminary audit status before merge.
Title check ❓ Inconclusive The title 'LF-14786 Everclear' is vague and does not clearly convey the main change; it only references a ticket ID and product name without describing what was implemented. Revise the title to clearly describe the main implementation, e.g., 'Add EverclearFacet for cross-chain bridging' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch lf-14786-everclear

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3e3a7c0 and cf23cc0.

📒 Files selected for processing (4)
  • deployments/_deployments_log_file.json (1 hunks)
  • deployments/arbitrum.diamond.staging.json (2 hunks)
  • deployments/arbitrum.staging.json (1 hunks)
  • script/demoScripts/demoEverclear.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (44)
📓 Common learnings
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/UniV2StyleFacet.sol:0-0
Timestamp: 2025-08-27T13:47:28.646Z
Learning: In src/Periphery/Lda/Facets/UniV2StyleFacet.sol and similar LDA facets, mirooon prefers to rely on backend validation for pool addresses rather than adding contract code-size checks in the smart contract, as pool validation occurs during payload generation and transactions would fail anyway if sent to invalid addresses.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1283
File: deployments/ronin.diamond.json:65-68
Timestamp: 2025-08-07T10:20:01.383Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, carefully verify that target state configuration files (like script/deploy/_targetState.json) and deployment log files have been updated before flagging missing entries. The AI summary section should be consulted to understand all file changes, as manual searches might miss entries due to formatting differences or search limitations.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1256
File: deployments/zksync.diamond.json:81-87
Timestamp: 2025-07-04T08:59:08.108Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, carefully verify that target state configuration files (like script/deploy/_targetState.json) have been updated before flagging missing entries. The AI summary section should be consulted to understand all file changes, as manual searches might miss entries due to formatting differences or search limitations.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearV2Facet.sol:75-96
Timestamp: 2025-10-13T11:13:48.847Z
Learning: In EverclearV2Facet (and all LiFi facets), the team standard is to use msg.sender as the refund address with the refundExcessNative modifier, not requiring an explicit refund address parameter.
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: src/Facets/GlacisFacet.sol:1-3
Timestamp: 2025-01-28T11:28:16.225Z
Learning: The GlacisFacet contract audit will be conducted and added to the audit log in later stages of development. This is acceptable during the initial development phase.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearFacet.sol:4-13
Timestamp: 2025-10-10T10:56:04.861Z
Learning: LibAllowList is only required for facets that make arbitrary external calls to DEX aggregators (e.g., GenericSwapFacetV3). Bridge facets that call specific protocol contracts (like EverclearFacet calling IEverclearFeeAdapter) do not need to import LibAllowList.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: docs/LDAPeripheryRegistryFacet.md:14-27
Timestamp: 2025-08-29T14:05:25.335Z
Learning: mirooon prefers interface-level documentation to focus on the API contract and function purposes rather than implementation details like access control restrictions or specific modifiers, keeping documentation clean and consumable at the interface level.
📚 Learning: 2025-04-21T03:17:53.443Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1109
File: deployments/worldchain.json:28-28
Timestamp: 2025-04-21T03:17:53.443Z
Learning: For deployment PRs involving address updates like the RelayFacet to Worldchain, verify the actual presence of entries in files before reporting issues. The RelayFacet exists in the diamond log file and the PR diff already contains the necessary address change.

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/_deployments_log_file.json
  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-04-21T03:17:53.443Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1109
File: deployments/worldchain.json:28-28
Timestamp: 2025-04-21T03:17:53.443Z
Learning: For deployment PRs updating contract addresses (like RelayFacet on Worldchain), verify the presence of entries in all relevant files (worldchain.json, worldchain.diamond.json, _deployments_log_file.json) before reporting inconsistencies. The RelayFacet entry exists in all required deployment files with the correct address.

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-10-09T03:47:21.269Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: deployments/bsc.diamond.staging.json:4-7
Timestamp: 2024-10-09T03:47:21.269Z
Learning: In files with "staging" in their filename, such as `deployments/bsc.diamond.staging.json`, it is acceptable for facets to have empty "Name" and "Version" fields. Do not flag missing facet information in such files during reviews.

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/_deployments_log_file.json
  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-11-25T09:05:03.917Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: script/deploy/_targetState.json:49-49
Timestamp: 2024-11-25T09:05:03.917Z
Learning: The `RelayFacet` contract, when missing from the source code but referenced in deployment configurations, should be treated the same way as `OpBNBBridgeFacet` and can be ignored in code reviews.

Applied to files:

  • deployments/arbitrum.staging.json
📚 Learning: 2025-07-04T08:59:08.108Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1256
File: deployments/zksync.diamond.json:81-87
Timestamp: 2025-07-04T08:59:08.108Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, carefully verify that target state configuration files (like script/deploy/_targetState.json) have been updated before flagging missing entries. The AI summary section should be consulted to understand all file changes, as manual searches might miss entries due to formatting differences or search limitations.

Applied to files:

  • deployments/arbitrum.staging.json
📚 Learning: 2025-08-07T10:20:01.383Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1283
File: deployments/ronin.diamond.json:65-68
Timestamp: 2025-08-07T10:20:01.383Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, carefully verify that target state configuration files (like script/deploy/_targetState.json) and deployment log files have been updated before flagging missing entries. The AI summary section should be consulted to understand all file changes, as manual searches might miss entries due to formatting differences or search limitations.

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/_deployments_log_file.json
📚 Learning: 2025-09-09T10:39:26.383Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1357
File: deployments/lens.diamond.json:48-51
Timestamp: 2025-09-09T10:39:26.383Z
Learning: In the lifinance/contracts repository, when deployment JSON files show address changes (like AcrossFacetV3 address updates in deployments/*.diamond.json), the corresponding _deployments_log_file.json updates may be handled in separate PRs rather than the same PR that updates the diamond configuration files.

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/_deployments_log_file.json
  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-10-24T06:17:25.211Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: deployments/bsc.diamond.staging.json:100-101
Timestamp: 2024-10-24T06:17:25.211Z
Learning: In `deployments/bsc.diamond.staging.json`, the trailing comma after the last property in the `Periphery` object is acceptable and should not be flagged as a JSON formatting error.

Applied to files:

  • deployments/arbitrum.staging.json
📚 Learning: 2024-09-27T07:10:15.586Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 812
File: deployments/polygon.diamond.json:4-11
Timestamp: 2024-09-27T07:10:15.586Z
Learning: In `deployments/polygon.diamond.json`, it's acceptable for certain facets to have empty names and versions when specified by the developer.

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-09-16T01:39:54.099Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1381
File: deployments/arbitrum.json:65-69
Timestamp: 2025-09-16T01:39:54.099Z
Learning: When verifying facet deployments across .json and .diamond.json files, search by facet name rather than trying to cross-reference addresses between the files, as the same contract can have different addresses in different deployment files.

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/_deployments_log_file.json
  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-10-10T10:56:04.861Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearFacet.sol:4-13
Timestamp: 2025-10-10T10:56:04.861Z
Learning: LibAllowList is only required for facets that make arbitrary external calls to DEX aggregators (e.g., GenericSwapFacetV3). Bridge facets that call specific protocol contracts (like EverclearFacet calling IEverclearFeeAdapter) do not need to import LibAllowList.

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/_deployments_log_file.json
📚 Learning: 2025-09-25T07:47:30.735Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1324
File: src/Facets/EcoFacet.sol:306-336
Timestamp: 2025-09-25T07:47:30.735Z
Learning: In EcoFacet (src/Facets/EcoFacet.sol), the team intentionally uses variable-length validation for nonEVMReceiver addresses (up to 44 bytes) to support cross-ecosystem bridging with different address formats, rather than enforcing fixed 32-byte raw pubkeys.

Applied to files:

  • deployments/arbitrum.staging.json
📚 Learning: 2025-02-11T10:35:03.536Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 988
File: script/tasks/solidity/AddTokenApprovalsToCBridgeFacetPacked.s.sol:17-21
Timestamp: 2025-02-11T10:35:03.536Z
Learning: The CBridgeFacetPacked and cBridge addresses in AddTokenApprovalsToCBridgeFacetPacked.s.sol must not be zero addresses as they are required for token approvals to function properly.

Applied to files:

  • deployments/arbitrum.staging.json
📚 Learning: 2025-08-28T02:41:07.505Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1321
File: docs/RelayDepositoryFacet.md:9-10
Timestamp: 2025-08-28T02:41:07.505Z
Learning: Unit tests for RelayDepositoryFacet cannot verify fund forwarding behavior after deposits because the facet delegates to external IRelayDepository contracts. The forwarding logic is implemented in the Relay Protocol V2 Depository contracts, not in the facet itself.

Applied to files:

  • deployments/arbitrum.staging.json
📚 Learning: 2025-09-22T00:52:26.172Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1388
File: deployments/hyperevm.diamond.json:72-75
Timestamp: 2025-09-22T00:52:26.172Z
Learning: In diamond configuration files (deployments/*.diamond.json), it's acceptable to have multiple versions of the same facet (e.g., GlacisFacet v1.0.0 and v1.1.0) deployed at different contract addresses. This is intentional design for version coexistence, gradual migration, or backward compatibility purposes.

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/_deployments_log_file.json
  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-11-01T11:53:57.162Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 846
File: deployments/cronos.diamond.json:28-31
Timestamp: 2024-11-01T11:53:57.162Z
Learning: In `deployments/cronos.diamond.json`, both `GenericSwapFacet` and `GenericSwapFacetV3` are distinct facets that should be included together, as they serve different purposes.

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-11-05T17:14:24.059Z
Learnt from: maxklenk
Repo: lifinance/contracts PR: 782
File: script/demoScripts/demoPermit2.ts:119-124
Timestamp: 2024-11-05T17:14:24.059Z
Learning: In the file `script/demoScripts/demoPermit2.ts`, adding error handling for external API calls is not preferred as it may overload the demo.

Applied to files:

  • script/demoScripts/demoEverclear.ts
📚 Learning: 2025-08-22T10:03:58.794Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1299
File: script/demoScripts/demoAcrossV4.ts:728-737
Timestamp: 2025-08-22T10:03:58.794Z
Learning: Demo scripts in `script/demoScripts` are exempt from the citty CLI argument parsing requirement that applies to other TypeScript scripts. Templates for demo scripts don't use citty and this is acceptable.

Applied to files:

  • script/demoScripts/demoEverclear.ts
📚 Learning: 2025-06-05T14:27:30.714Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/demoPatcherDest.ts:0-0
Timestamp: 2025-06-05T14:27:30.714Z
Learning: For demo scripts in the `script/demoScripts/` directory, hardcoded values and simplified implementations are acceptable since they're designed to showcase functionality rather than be production-ready.

Applied to files:

  • script/demoScripts/demoEverclear.ts
📚 Learning: 2025-06-05T15:04:58.212Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/utils/cowSwapHelpers.ts:112-114
Timestamp: 2025-06-05T15:04:58.212Z
Learning: For demo scripts in the lifinance/contracts repository, security concerns like using Math.random() for nonce generation are acceptable since the focus is on demonstrating functionality rather than production-ready security implementation.

Applied to files:

  • script/demoScripts/demoEverclear.ts
📚 Learning: 2025-06-05T14:50:40.886Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/demoPatcherDest.ts:0-0
Timestamp: 2025-06-05T14:50:40.886Z
Learning: Demo scripts in this codebase can use hardcoded gas limits and other simplified values, as they prioritize demonstration clarity over production robustness.

Applied to files:

  • script/demoScripts/demoEverclear.ts
📚 Learning: 2025-06-05T14:25:19.137Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/demoPatcherDest_new.ts:0-0
Timestamp: 2025-06-05T14:25:19.137Z
Learning: Error handling for `findNeedleOffset` function calls is not needed in demo scripts in the lifinance/contracts repository, as indicated by the team's preference to keep demo scripts simpler.

Applied to files:

  • script/demoScripts/demoEverclear.ts
📚 Learning: 2025-05-28T17:33:33.959Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1170
File: deployments/_deployments_log_file.json:28060-28072
Timestamp: 2025-05-28T17:33:33.959Z
Learning: Deployment log files like `deployments/_deployments_log_file.json` are historical records that document the actual versions deployed at specific times. They should not be updated to match current contract versions - they must accurately reflect what was deployed when the deployment occurred.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2025-01-09T04:17:46.190Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 914
File: deployments/_deployments_log_file.json:26902-26916
Timestamp: 2025-01-09T04:17:46.190Z
Learning: Updates to _deployments_log_file.json can represent backfilling of historical deployment data, not just new deployments. Such updates don't require new audits.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2024-12-04T01:59:34.045Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 832
File: deployments/_deployments_log_file.json:23712-23720
Timestamp: 2024-12-04T01:59:34.045Z
Learning: In `deployments/_deployments_log_file.json`, duplicate deployment entries for the same version and address may occur because they correspond to deployments on different networks. These entries are acceptable and should not be flagged as duplicates in future reviews.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2025-05-28T17:33:10.529Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1170
File: deployments/_deployments_log_file.json:28706-28717
Timestamp: 2025-05-28T17:33:10.529Z
Learning: Deployment log files (like `_deployments_log_file.json`) are historical records that should not be updated to match current contract versions. They should accurately reflect the versions that were actually deployed at specific timestamps.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2024-09-30T03:52:27.281Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 812
File: deployments/_deployments_log_file.json:1914-1927
Timestamp: 2024-09-30T03:52:27.281Z
Learning: Duplicate entries in `deployments/_deployments_log_file.json` that are outdated do not require changes.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2025-11-05T15:17:14.748Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1193
File: deployments/_deployments_log_file.json:42563-42712
Timestamp: 2025-11-05T15:17:14.748Z
Learning: In deployment log files like `deployments/_deployments_log_file.json`, the `ZK_SOLC_VERSION` field should only be present for networks that have `isZkEVM: true` in `config/networks.json`. Non-zkEVM networks (like arbitrum, bsc, polygon, gnosis, etc.) should not have this field. Do not flag the absence of `ZK_SOLC_VERSION` as an inconsistency for non-zkEVM networks.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2025-02-12T09:44:12.961Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 985
File: script/deploy/_targetState.json:0-0
Timestamp: 2025-02-12T09:44:12.961Z
Learning: The bsca network intentionally maintains different facet versions between staging and production environments, specifically:
1. CalldataVerificationFacet: v1.1.1 in staging vs v1.1.2 in production
2. EmergencyPauseFacet: present only in production
3. Permit2Proxy: present only in production

Applied to files:

  • deployments/_deployments_log_file.json
  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-12-03T11:02:14.195Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 807
File: script/deploy/_targetState.json:181-181
Timestamp: 2024-12-03T11:02:14.195Z
Learning: HyphenFacet v1.0.0 is intentionally included in the BSC staging environment and should not be removed even if not present in production environments.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2025-08-27T13:47:28.646Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/UniV2StyleFacet.sol:0-0
Timestamp: 2025-08-27T13:47:28.646Z
Learning: In src/Periphery/Lda/Facets/UniV2StyleFacet.sol and similar LDA facets, mirooon prefers to rely on backend validation for pool addresses rather than adding contract code-size checks in the smart contract, as pool validation occurs during payload generation and transactions would fail anyway if sent to invalid addresses.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2024-12-03T11:01:57.084Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 807
File: script/deploy/_targetState.json:164-164
Timestamp: 2024-12-03T11:01:57.084Z
Learning: Version differences in `CalldataVerificationFacet` between staging and production are acceptable and not an issue.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2025-09-04T09:26:35.060Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1344
File: src/Facets/GardenFacet.sol:124-130
Timestamp: 2025-09-04T09:26:35.060Z
Learning: In src/Facets/GardenFacet.sol, the team has decided that registry lookup validation should only check for zero addresses and not perform additional contract existence checks (like htlcAddress.code.length > 0), preferring minimal validation for Garden HTLC registry addresses.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2024-11-26T01:16:27.721Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: deployments/worldchain.diamond.json:40-43
Timestamp: 2024-11-26T01:16:27.721Z
Learning: Version inconsistencies of 'GenericSwapFacetV3' across deployment configurations are acceptable if they are only due to differences in Solidity pragma directives.

Applied to files:

  • deployments/_deployments_log_file.json
  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-11-26T01:01:18.499Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: deployments/arbitrum.diamond.json:148-150
Timestamp: 2024-11-26T01:01:18.499Z
Learning: In `deployments/*.diamond.json` configuration files, facets that are part of an open PR and not yet merged into the main branch may have missing `Name` and `Version` fields.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-11-26T01:04:16.637Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: deployments/fantom.diamond.json:92-94
Timestamp: 2024-11-26T01:04:16.637Z
Learning: In `deployments/*.diamond.json` files, it's acceptable for facets to have empty `Name` and `Version` fields, and these should not be flagged as issues.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-11-21T08:39:29.530Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 861
File: config/dexs.json:748-752
Timestamp: 2024-11-21T08:39:29.530Z
Learning: In the 'worldchain' network, the addresses `0x50D5a8aCFAe13Dceb217E9a071F6c6Bd5bDB4155`, `0x8f023b4193a6b18C227B4a755f8e28B3D30Ef9a1`, and `0x603a538477d44064eA5A5d8C345b4Ff6fca1142a` are used as DEXs and should be included in `config/dexs.json`.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-07-15T05:05:28.134Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1140
File: config/permit2Proxy.json:3-3
Timestamp: 2025-07-15T05:05:28.134Z
Learning: In config/permit2Proxy.json, the addresses represent the Permit2 contract addresses on each chain, NOT the Permit2Proxy contract addresses. These Permit2 addresses are used as constructor arguments when deploying the Permit2Proxy contract. The Permit2Proxy acts as a wrapper/proxy that interacts with the underlying Permit2 contract on each network.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-02-11T10:33:52.791Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 988
File: script/deploy/facets/DeployPermit2Proxy.s.sol:33-37
Timestamp: 2025-02-11T10:33:52.791Z
Learning: The Permit2Proxy contract must not be deployed with zero addresses for its critical dependencies (LiFiDiamond, permit2Address, safeAddress). This is enforced by passing `false` to `_getConfigContractAddress` function.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-11-26T01:16:48.020Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: deployments/aurora.diamond.json:75-75
Timestamp: 2024-11-26T01:16:48.020Z
Learning: On networks where the `Permit2Proxy` contract is not deployed, the `Permit2Proxy` address is intentionally left empty in the configuration files.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-10-09T03:47:21.269Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/fuse.json:24-25
Timestamp: 2024-10-09T03:47:21.269Z
Learning: The `LiFiDEXAggregator.sol` contract is located in `src/Periphery/`.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-10-09T03:47:21.269Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: src/Periphery/Permit2Proxy.sol:75-108
Timestamp: 2024-10-09T03:47:21.269Z
Learning: In the `Permit2Proxy` contract (`src/Periphery/Permit2Proxy.sol`), reentrancy protection is not necessary for functions like `callDiamondWithEIP2612Signature` when calling our own trusted diamond contract (`LIFI_DIAMOND`).

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-02-24T09:35:34.908Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 984
File: src/Periphery/ReceiverChainflip.sol:48-62
Timestamp: 2025-02-24T09:35:34.908Z
Learning: Contract address validations for periphery contracts like ReceiverChainflip are handled in deployment scripts rather than in the constructor.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
🧬 Code graph analysis (1)
script/demoScripts/demoEverclear.ts (2)
script/common/types.ts (1)
  • SupportedChain (3-3)
script/demoScripts/utils/demoScriptHelpers.ts (9)
  • setupEnvironment (654-708)
  • ADDRESS_USDT_ARB (64-64)
  • ADDRESS_USDC_ARB (63-63)
  • ensureBalance (847-868)
  • ensureAllowance (873-907)
  • getUniswapDataERC20toExactERC20 (335-407)
  • ADDRESS_UNISWAP_ARB (80-80)
  • zeroPadAddressToBytes32 (563-569)
  • executeTransaction (806-842)
🔇 Additional comments (5)
deployments/arbitrum.staging.json (1)

64-65: EverclearFacet address mismatch detected between deployment files.

The address in deployments/arbitrum.staging.json:65 (0x28871221E2a1Ca351218797EF33d133d48d710ab) does not match the address recorded in deployments/_deployments_log_file.json for the same facet on Arbitrum staging (0x4582FD200173F1717F6C53fD1531b2F6fE33Fe3D). These must be consistent across all deployment configuration files. Update _deployments_log_file.json to use the correct address that matches the staging deployment.

⛔ Skipped due to learnings
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1109
File: deployments/worldchain.json:28-28
Timestamp: 2025-04-21T03:17:53.443Z
Learning: For deployment PRs updating contract addresses (like RelayFacet on Worldchain), verify the presence of entries in all relevant files (worldchain.json, worldchain.diamond.json, _deployments_log_file.json) before reporting inconsistencies. The RelayFacet entry exists in all required deployment files with the correct address.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1109
File: deployments/worldchain.json:28-28
Timestamp: 2025-04-21T03:17:53.443Z
Learning: For deployment PRs involving address updates like the RelayFacet to Worldchain, verify the actual presence of entries in files before reporting issues. The RelayFacet exists in the diamond log file and the PR diff already contains the necessary address change.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: deployments/bsc.diamond.staging.json:4-7
Timestamp: 2024-10-09T03:47:21.269Z
Learning: In files with "staging" in their filename, such as `deployments/bsc.diamond.staging.json`, it is acceptable for facets to have empty "Name" and "Version" fields. Do not flag missing facet information in such files during reviews.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1357
File: deployments/lens.diamond.json:48-51
Timestamp: 2025-09-09T10:39:26.383Z
Learning: In the lifinance/contracts repository, when deployment JSON files show address changes (like AcrossFacetV3 address updates in deployments/*.diamond.json), the corresponding _deployments_log_file.json updates may be handled in separate PRs rather than the same PR that updates the diamond configuration files.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1381
File: deployments/arbitrum.json:65-69
Timestamp: 2025-09-16T01:39:54.099Z
Learning: When verifying facet deployments across .json and .diamond.json files, search by facet name rather than trying to cross-reference addresses between the files, as the same contract can have different addresses in different deployment files.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1283
File: deployments/ronin.diamond.json:65-68
Timestamp: 2025-08-07T10:20:01.383Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, understand that _targetState.json tracks contract version numbers (not addresses) and _deployments_log_file.json contains deployment records with addresses that may not be organized in obvious network sections. Always verify the actual file structure before flagging missing entries.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: deployments/bsc.diamond.staging.json:100-101
Timestamp: 2024-10-24T06:17:25.211Z
Learning: In `deployments/bsc.diamond.staging.json`, the trailing comma after the last property in the `Periphery` object is acceptable and should not be flagged as a JSON formatting error.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 832
File: deployments/_deployments_log_file.json:23712-23720
Timestamp: 2024-12-04T01:59:34.045Z
Learning: In `deployments/_deployments_log_file.json`, duplicate deployment entries for the same version and address may occur because they correspond to deployments on different networks. These entries are acceptable and should not be flagged as duplicates in future reviews.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/scroll.diamond.json:82-82
Timestamp: 2024-10-09T03:47:21.269Z
Learning: In the `deployments/*.diamond.json` and `deployments/*.json` files, the `LiFiDEXAggregator` contract may intentionally have the same contract address across multiple networks. This is acceptable and should not be flagged as an issue in future code reviews.
Learnt from: ezynda3
Repo: lifinance/contracts PR: 843
File: script/deploy/facets/DeployRelayFacet.s.sol:0-0
Timestamp: 2024-10-31T09:07:36.301Z
Learning: In `script/deploy/facets/DeployRelayFacet.s.sol`, additional validation for the configuration file existence and address validity is unnecessary because the code will already fail appropriately if the configuration file is missing or the addresses are invalid.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1321
File: docs/RelayDepositoryFacet.md:9-10
Timestamp: 2025-08-28T02:41:07.505Z
Learning: Unit tests for RelayDepositoryFacet cannot verify fund forwarding behavior after deposits because the facet delegates to external IRelayDepository contracts. The forwarding logic is implemented in the Relay Protocol V2 Depository contracts, not in the facet itself.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: script/deploy/_targetState.json:49-49
Timestamp: 2024-11-25T09:05:03.917Z
Learning: The `RelayFacet` contract, when missing from the source code but referenced in deployment configurations, should be treated the same way as `OpBNBBridgeFacet` and can be ignored in code reviews.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearV2Facet.sol:75-96
Timestamp: 2025-10-13T11:13:48.847Z
Learning: In EverclearV2Facet (and all LiFi facets), the team standard is to use msg.sender as the refund address with the refundExcessNative modifier, not requiring an explicit refund address parameter.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1322
File: src/Facets/MayanFacet.sol:259-272
Timestamp: 2025-08-23T11:07:02.778Z
Learning: In src/Facets/MayanFacet.sol, the offset 0xe4 for parsing receiver addresses from HCDepositInitiator::deposit calldata is correct. The mload operation reads 32-byte words and the address extraction via address(uint160(uint256(receiver))) properly handles ABI padding, so theoretical byte-level offset calculations can be misleading when the actual implementation works correctly with real-world data.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearFacet.sol:4-13
Timestamp: 2025-10-10T10:56:04.861Z
Learning: LibAllowList is only required for facets that make arbitrary external calls to DEX aggregators (e.g., GenericSwapFacetV3). Bridge facets that call specific protocol contracts (like EverclearFacet calling IEverclearFeeAdapter) do not need to import LibAllowList.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: test/solidity/Periphery/GasZipPeriphery.t.sol:223-233
Timestamp: 2025-08-27T23:36:40.773Z
Learning: In bridge facet swap flows with requiresDeposit=false, tokens are already held by the diamond contract from previous swaps. When subsequent contracts like GasZipPeriphery call LibAsset.depositAsset, they pull tokens from msg.sender (the diamond) to themselves via transferFrom, requiring no additional approvals since the diamond already owns the tokens.
deployments/_deployments_log_file.json (1)

43365-43392: Verify that production deployment entries and audit information are appropriately handled.

The EverclearFacet entries follow the correct format for the deployment log, with proper structure and ZK_SOLC_VERSION handling (correctly empty for arbitrum). However, two aspects need clarification:

  1. Staging-only entries visible: The hunk shows only arbitrum staging entries. Per prior learnings, production deployments may be handled in separate PRs, but this should be verified to ensure completeness.
  2. Audit information absent: The PR objectives mention that new facets should have preliminary audit data (auditor and date). These entries have no audit metadata. Confirm whether audit information needs to be added now or will be populated in a follow-up PR once audits are completed.
script/demoScripts/demoEverclear.ts (1)

1-365: LGTM - Well-structured demo script!

The implementation is thorough and follows established demo script patterns. Key strengths:

  • Comprehensive documentation and logging throughout the flow
  • Proper error handling including detailed signature validation feedback (lines 346-363)
  • Correct use of '0x' for empty bytes at line 291 (addresses previous discussion)
  • Supports both simple bridge and swap+bridge modes with clear conditional logic
  • Appropriate use of helper functions for balance/allowance checks and transaction execution

The script correctly orchestrates the Everclear bridge flow: environment setup → optional swap → API intent fetch → calldata decoding → allowance management → transaction execution.

deployments/arbitrum.diamond.staging.json (2)

183-223: LGTM - Staging deployment changes align with Everclear integration.

The additions include:

  • EverclearFacet v1.0.0 (lines 200-203) and v2.0.0 (lines 208-211) for the new Everclear bridge integration
  • DexManagerFacet v1.0.1 (lines 196-199)
  • Multiple placeholder entries with empty Name/Version fields

The empty Name/Version entries are acceptable for staging files, and having multiple EverclearFacet versions is intentional for version coexistence during deployment and testing.

Based on learnings


233-233: Permit2Proxy address update noted.

The Permit2Proxy address has been updated to a new deployment. This change appears intentional and is mentioned in the PR's AI summary.


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
Copy link
Collaborator

lifi-action-bot commented Oct 10, 2025

Test Coverage Report

Line Coverage: 85.30% (2618 / 3069 lines)
Function Coverage: 89.25% ( 432 / 484 functions)
Branch Coverage: 61.75% ( 402 / 651 branches)
Test coverage (85.30%) is above min threshold (83%). Check passed.

Copy link
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: 7

♻️ Duplicate comments (3)
src/Facets/EverclearV2Facet.sol (2)

195-196: bytes32 → address downcast

This narrows to 160 bits. Team has previously accepted this risk; ensure input bytes32 is a left‑padded address.

Would you like an assertion added to validate the top 12 bytes are zero before casting?


208-209: Event emission after external call is intentional here

Per team convention, LiFiTransferStarted is emitted at the end of _startBridge. The nonReentrant guard is on the entrypoints.

Based on learnings.

src/Facets/EverclearFacet.sol (1)

208-209: Event emission after external call is intentional and accepted.

This pattern was previously discussed and accepted with nonReentrant-protected entrypoints; event is emitted after successful external interactions.

Based on learnings

🧹 Nitpick comments (12)
script/demoScripts/utils/demoScriptHelpers.ts (1)

97-99: Consider consolidating duplicate address padding functions.

The new addressToBytes32LeftPadded function (lines 97-99) duplicates the functionality of the existing leftPadAddressToBytes32 function (lines 92-95). Both convert an address to a 32-byte left-padded hex string, just using different approaches:

  • leftPadAddressToBytes32: Manual zero prefix concatenation
  • addressToBytes32LeftPadded: Using padStart(64, '0')

Consider one of the following:

  1. Remove the duplicate: Keep only one implementation (preferably padStart for clarity)
  2. Consolidate: Deprecate one and update all call sites to use a single function
  3. Document: If both are needed for specific use cases, add comments explaining when to use each

Example consolidation:

-export const leftPadAddressToBytes32 = (address: string): string => {
-  // Convert address to bytes32 format: pad with zeros to make it 32 bytes
-  return '0x000000000000000000000000' + address.slice(2)
-}
-
-export const addressToBytes32LeftPadded = (address: string): string => {
-  return '0x' + address.slice(2).padStart(64, '0')
-}
+/**
+ * Convert an Ethereum address to a 32-byte left-padded hex string.
+ * The address is stripped of its "0x" prefix and zero-padded to 64 characters.
+ */
+export const addressToBytes32LeftPadded = (address: string): string => {
+  return '0x' + address.slice(2).padStart(64, '0')
+}

If keeping both, verify all existing call sites of leftPadAddressToBytes32 and update them to use the new function.

script/demoScripts/demoEverclear.ts (2)

114-126: Harden API calls: check response.ok and handle errors

Current code assumes 200 OK and may throw opaque JSON errors. Guard all fetches.

Example:

-  const quoteResp = await fetch(`https://api.everclear.org/routes/quotes`, { ... })
-  const quoteData = await quoteResp.json()
+  const quoteResp = await fetch(`https://api.everclear.org/routes/quotes`, { ... })
+  if (!quoteResp.ok) {
+    const err = await quoteResp.text().catch(() => '')
+    throw new Error(`Quote request failed (${quoteResp.status}): ${err}`)
+  }
+  const quoteData = await quoteResp.json()

Repeat for the two /intents calls.

Also applies to: 130-145, 216-231


201-206: Avoid any; prefer typed contract or narrow call surface

Casting lifiDiamondContract to any loses safety. Prefer a typed write call (e.g., via a viem type helper or a small wrapper) so arg/struct validation is enforced at compile time.

docs/EverclearFacet.md (1)

79-79: Improve link text per MD059

Replace “here” links with descriptive text.

- The swap library can be found [here](../src/Libraries/LibSwap.sol).
+ See the swap library implementation in [LibSwap.sol](../src/Libraries/LibSwap.sol).

- It's used to emit events ... can be found [here](../src/Interfaces/ILiFi.sol).
+ See [ILiFi.sol](../src/Interfaces/ILiFi.sol) for BridgeData and events.

- A detailed explanation ... can be found [here](https://docs.li.fi/products/more-integration-options/li.fi-api/transferring-tokens-example).
+ See the guide: [Transferring tokens with the Li.Fi API](https://docs.li.fi/products/more-integration-options/li.fi-api/transferring-tokens-example).

Also applies to: 85-85, 116-116

src/Interfaces/IEverclearFeeAdapterV2.sol (3)

4-6: Fix NatSpec header order and add missing @notice.

Interfaces must include NatSpec in order: @title, @notice, @author, @Custom:version.

As per coding guidelines

-/// @title Interface for Everclear Fee Adapter V2
-/// @author LI.FI (https://li.fi)
-/// @custom:version 1.0.0
+/// @title Interface for Everclear Fee Adapter V2
+/// @notice Defines the Everclear V2 fee adapter API (intents, fees, and overloads for EVM/non‑EVM identifiers)
+/// @author LI.FI (https://li.fi)
+/// @custom:version 1.0.0

14-28: Align param docs with actual types (bytes32 identifiers).

Docstrings reference “address” while fields are bytes32 (supporting non‑EVM). Update wording to avoid confusion.

As per coding guidelines

- * @param receiver The address of the intent receiver
- * @param inputAsset The address of the intent asset on origin
- * @param outputAsset The address of the intent asset on destination
+ * @param receiver The receiver identifier (bytes32; EVM addresses are left‑padded)
+ * @param inputAsset The origin asset identifier (bytes32; EVM address left‑padded)
+ * @param outputAsset The destination asset identifier (bytes32; EVM address left‑padded)

44-66: Optional: Add brief NatSpec for the overloads.

A one-liner purpose + param summaries for both newIntent overloads will help consumers and satisfy stricter linters.

src/Facets/EverclearFacet.sol (2)

81-89: Use explicit refund address parameter instead of msg.sender.

Guideline: do not use msg.sender as refund address. Add a refundAddress param and pass it to refundExcessNative to avoid refunding an aggregator or unintended caller.

As per coding guidelines

Example:

-    function startBridgeTokensViaEverclear(
-        ILiFi.BridgeData memory _bridgeData,
-        EverclearData calldata _everclearData
-    )
+    function startBridgeTokensViaEverclear(
+        ILiFi.BridgeData memory _bridgeData,
+        EverclearData calldata _everclearData,
+        address payable refundAddress
+    )
         external
         payable
         nonReentrant
-        refundExcessNative(payable(msg.sender))
+        refundExcessNative(refundAddress)

Apply similarly to swapAndStartBridgeTokensViaEverclear.

Also applies to: 106-114


181-199: Validate bytes32<->address narrowing to prevent truncation.

When comparing/deriving EVM addresses from bytes32, ensure high bits are zero. Otherwise, implicit truncation may mask malformed inputs.

Example preconditions for the EVM branch:

// Receiver: bytes32(uint160(receiver)) == receiverAddress
uint256 recv32 = uint256(_everclearData.receiverAddress);
require(recv32 >> 160 == 0, "InvalidReceiverBytes32");

// Output asset: address from bytes32
uint256 out32 = uint256(_everclearData.outputAsset);
require(out32 >> 160 == 0, "InvalidOutputAssetBytes32");

If this risk is an accepted tradeoff (as with prior facets), please confirm the Everclear adapter/API guarantees canonical encoding. Based on learnings

src/Interfaces/IEverclearFeeAdapter.sol (2)

4-6: Fix NatSpec header order and add missing @notice.

Interfaces must include NatSpec in order: @title, @notice, @author, @Custom:version.

As per coding guidelines

-/// @title Interface for Everclear Fee Adapter
-/// @author LI.FI (https://li.fi)
-/// @custom:version 1.0.0
+/// @title Interface for Everclear Fee Adapter
+/// @notice Defines the Everclear fee adapter API (intents, fees, and EVM/non‑EVM overloads)
+/// @author LI.FI (https://li.fi)
+/// @custom:version 1.0.0

14-28: Clarify Intent docs to reflect canonical bytes32 fields.

Fields are bytes32 (canonicalized addresses or chain‑specific IDs). Update wording to avoid implying Solidity address type.

- * @param receiver The address of the intent receiver
- * @param inputAsset The address of the intent asset on origin
- * @param outputAsset The address of the intent asset on destination
+ * @param receiver The receiver identifier (bytes32; EVM addresses are left‑padded)
+ * @param inputAsset The origin asset identifier (bytes32; EVM address left‑padded)
+ * @param outputAsset The destination asset identifier (bytes32; EVM address left‑padded)
test/solidity/Facets/EverclearFacet.t.sol (1)

811-863: Add explicit test for fee > minAmount revert (if guard is added).

Once FeeExceedsAmount guard is in place, add a unit test asserting the specific revert when fee exceeds minAmount to lock in UX behavior.

I can draft the test diff after you confirm the chosen error name.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3ae54db and 533144a.

📒 Files selected for processing (18)
  • config/everclear.json (1 hunks)
  • deployments/_deployments_log_file.json (1 hunks)
  • deployments/arbitrum.diamond.staging.json (1 hunks)
  • deployments/arbitrum.staging.json (1 hunks)
  • docs/EverclearFacet.md (1 hunks)
  • script/demoScripts/demoEverclear.ts (1 hunks)
  • script/demoScripts/utils/demoScriptHelpers.ts (1 hunks)
  • script/deploy/facets/DeployEverclearFacet.s.sol (1 hunks)
  • script/deploy/facets/UpdateEverclearFacet.s.sol (1 hunks)
  • script/deploy/tron/deploy-and-register-everclear-facet.ts (1 hunks)
  • src/Facets/EverclearFacet.sol (1 hunks)
  • src/Facets/EverclearV2Facet.sol (1 hunks)
  • src/Interfaces/IEverclearFeeAdapter.sol (1 hunks)
  • src/Interfaces/IEverclearFeeAdapterV2.sol (1 hunks)
  • src/Periphery/LiFiDEXAggregator.sol (1 hunks)
  • templates/facet.template.hbs (2 hunks)
  • test/solidity/Facets/EverclearFacet.t.sol (1 hunks)
  • test/solidity/utils/MockEverclearFeeAdapter.sol (1 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
{src,test/solidity,script}/**/*.sol

📄 CodeRabbit inference engine (conventions.md)

{src,test/solidity,script}/**/*.sol: All Solidity files must start with a license identifier, followed by a blank line, then the pragma statement
Use SPDX license identifier // SPDX-License-Identifier: LGPL-3.0-only for all first-party Solidity files
Error names must be descriptive PascalCase, use custom errors instead of revert() strings, and omit error messages for gas optimization
Solidity variable/function naming: state variables camelCase; function params camelCase with leading underscore; constants and immutables in CONSTANT_CASE; private/internal variables camelCase; function names camelCase

Files:

  • src/Periphery/LiFiDEXAggregator.sol
  • src/Interfaces/IEverclearFeeAdapter.sol
  • src/Interfaces/IEverclearFeeAdapterV2.sol
  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
  • test/solidity/Facets/EverclearFacet.t.sol
  • test/solidity/utils/MockEverclearFeeAdapter.sol
  • src/Facets/EverclearV2Facet.sol
  • src/Facets/EverclearFacet.sol
src/**/*.sol

📄 CodeRabbit inference engine (conventions.md)

src/**/*.sol: Every contract must include NatSpec header in this order: @title, @author LI.FI (https://li.fi), @notice, @Custom:version X.Y.Z
All public/external functions must have NatSpec comments documenting purpose, params, and returns
Add inline comments for complex logic, optimizations, gas-saving techniques, and math steps
Emit GenericSwapCompleted after successful same-chain swap completion

Files:

  • src/Periphery/LiFiDEXAggregator.sol
  • src/Interfaces/IEverclearFeeAdapter.sol
  • src/Interfaces/IEverclearFeeAdapterV2.sol
  • src/Facets/EverclearV2Facet.sol
  • src/Facets/EverclearFacet.sol
**/*.sol

📄 CodeRabbit inference engine (conventions.md)

Follow solhint rules as configured in .solhint.json

Files:

  • src/Periphery/LiFiDEXAggregator.sol
  • src/Interfaces/IEverclearFeeAdapter.sol
  • src/Interfaces/IEverclearFeeAdapterV2.sol
  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
  • test/solidity/Facets/EverclearFacet.t.sol
  • test/solidity/utils/MockEverclearFeeAdapter.sol
  • src/Facets/EverclearV2Facet.sol
  • src/Facets/EverclearFacet.sol
{README.md,Deploy.md,docs/**}

📄 CodeRabbit inference engine (conventions.md)

Keep primary documentation up to date: README.md (overview/setup), Deploy.md (deployment), and docs/ (technical docs)

Files:

  • docs/EverclearFacet.md
src/Interfaces/**/*.sol

📄 CodeRabbit inference engine (conventions.md)

src/Interfaces/**/*.sol: All interfaces must reside under src/Interfaces, be in separate files from implementations, and use an I prefix (e.g., ILiFi)
Every interface must include NatSpec in this order: @title, @notice, @author LI.FI (https://li.fi), @Custom:version X.Y.Z

Files:

  • src/Interfaces/IEverclearFeeAdapter.sol
  • src/Interfaces/IEverclearFeeAdapterV2.sol
script/**/*.ts

📄 CodeRabbit inference engine (conventions.md)

script/**/*.ts: All TypeScript scripts must follow .eslintrc.cjs, use async/await, try/catch error handling, proper logging, environment variables, correct typings, use citty for CLI parsing, consola for logging, validate env vars via getEnvVar(), and exit with appropriate codes
Prefer existing helper functions over reimplementation (e.g., getDeployments, getProvider, getWalletFromPrivateKeyInDotEnv, sendTransaction, ensureBalanceAndAllowanceToDiamond, getUniswapData*)
Always use proper TypeChain types (e.g., ILiFi.BridgeDataStruct) and never use any for bridge data or contract structures
Before/after changes: verify imports and types exist, ensure typechain is generated, keep changes comprehensive and consistent, run TS compilation, remove unused imports, and ensure function signatures match usage
Scripts must execute with bunx tsx

Files:

  • script/demoScripts/utils/demoScriptHelpers.ts
  • script/deploy/tron/deploy-and-register-everclear-facet.ts
  • script/demoScripts/demoEverclear.ts
script/deploy/facets/Update*.s.sol

📄 CodeRabbit inference engine (conventions.md)

Update scripts must be named Update{ContractName}.s.sol, inherit UpdateScriptBase, call update("{ContractName}") and use getExcludes() to return excluded selectors

Files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
script/deploy/facets/Deploy*.s.sol

📄 CodeRabbit inference engine (conventions.md)

script/deploy/facets/Deploy*.s.sol: Deployment scripts for facets must be named Deploy{ContractName}.s.sol and inherit DeployScriptBase; deploy using deploy(type(ContractName).creationCode); omit getConstructorArgs() when not needed
When constructor args are required, implement getConstructorArgs() using stdJson, then call deploy(type(FacetName).creationCode) and return (deployed, constructorArgs)

Files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
test/solidity/**/*.t.sol

📄 CodeRabbit inference engine (conventions.md)

test/solidity/**/*.t.sol: Solidity test files must use .t.sol extension; organize imports with system libraries first, then project files
Test naming: successful tests prefixed test_, failure tests prefixed testRevert_, base/inherited tests prefixed testBase_; negative tests must check specific revert reasons
Each test contract must implement setUp() that configures block numbers, initializes base contracts, sets up facets, and uses vm.label; contracts inheriting TestBase.sol must call initTestBase() in setUp()
Use vm.startPrank()/vm.stopPrank() for user simulation; maintain blank-line formatting rules for tests (expectRevert separation, assertion grouping, spacing)
Use assertEq for equality, custom assertion modifiers for balance changes, vm.expectRevert with precise reasons, and vm.expectEmit(true,true,true,true,) to verify events and parameters

Files:

  • test/solidity/Facets/EverclearFacet.t.sol
src/Facets/**/*Facet.sol

📄 CodeRabbit inference engine (conventions.md)

src/Facets/**/*Facet.sol: Facet contracts must be located in src/Facets and include "Facet" in the contract name
Facet contracts must implement: internal _startBridge, swapAndStartBridgeTokensVia{FacetName}, and startBridgeTokensVia{FacetName}
Facet contracts must import/use: ILiFi, LibAsset, LibSwap, LibAllowList; and use security mixins ReentrancyGuard, SwapperV2, Validatable; ECDSA optional
Do not use msg.sender as refund address; require an explicit parameter for refund address
In {facetName}Data, receiverAddress must be the first field and be validated against bridgeData.receiver; verify targetChainId equals bridgeData.destinationChain for EVM-to-EVM
Apply required modifiers where appropriate: nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps/doesContainSourceSwaps, doesNotContainDestinationCalls/doesContainDestinationCalls
Emit LiFiTransferStarted at the start of a transaction before external calls; do not emit LiFiTransferCompleted or LiFiTransferRecovered in facets
For native fees in facets, use the _depositAndSwap variant and reserve required fees before execution
For non-EVM chains: receiverAddress must be bytes (not bytes32), must not be zero, and bridgeData.receiver must equal NON_EVM_ADDRESS

Files:

  • src/Facets/EverclearV2Facet.sol
  • src/Facets/EverclearFacet.sol
templates/**

📄 CodeRabbit inference engine (conventions.md)

Store all code generation templates for plop facet under templates/

Files:

  • templates/facet.template.hbs
🧠 Learnings (40)
📚 Learning: 2025-08-26T12:11:21.073Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: src/Periphery/Lda/Facets/CoreRouteFacet.sol:4-6
Timestamp: 2025-08-26T12:11:21.073Z
Learning: In the lifinance/contracts repository, OpenZeppelin's SafeERC20 library provides safePermit functionality for IERC20Permit tokens. This is confirmed by working implementations in both CoreRouteFacet.sol and LiFiDEXAggregator.sol that use the pattern "using SafeERC20 for IERC20Permit;" and successfully call safePermit with permit parameters.

Applied to files:

  • src/Periphery/LiFiDEXAggregator.sol
📚 Learning: 2025-08-26T12:11:21.073Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: src/Periphery/Lda/Facets/CoreRouteFacet.sol:4-6
Timestamp: 2025-08-26T12:11:21.073Z
Learning: OpenZeppelin's SafeERC20 library provides safePermit functionality for IERC20Permit tokens. This is confirmed by actual usage in the lifinance/contracts codebase where safePermit is used in multiple files including CoreRouteFacet.sol and LiFiDEXAggregator.sol. The pattern "using SafeERC20 for IERC20Permit;" is valid and working.

Applied to files:

  • src/Periphery/LiFiDEXAggregator.sol
📚 Learning: 2024-10-09T03:47:21.269Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#819
File: deployments/fuse.json:24-25
Timestamp: 2024-10-09T03:47:21.269Z
Learning: The `LiFiDEXAggregator.sol` contract is located in `src/Periphery/`.

Applied to files:

  • src/Periphery/LiFiDEXAggregator.sol
📚 Learning: 2025-08-26T12:11:21.073Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: src/Periphery/Lda/Facets/CoreRouteFacet.sol:4-6
Timestamp: 2025-08-26T12:11:21.073Z
Learning: OpenZeppelin's SafeERC20 library provides safePermit functionality for IERC20Permit tokens in modern versions. The usage pattern "using SafeERC20 for IERC20Permit;" is valid and enables safe permit operations. This is confirmed to be working in the lifinance/contracts codebase.

Applied to files:

  • src/Periphery/LiFiDEXAggregator.sol
📚 Learning: 2025-08-26T12:11:21.073Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: src/Periphery/Lda/Facets/CoreRouteFacet.sol:4-6
Timestamp: 2025-08-26T12:11:21.073Z
Learning: OpenZeppelin's SafeERC20 library provides safePermit functionality for IERC20Permit tokens. The using SafeERC20 for IERC20Permit; directive enables calling safePermit on IERC20Permit tokens safely.

Applied to files:

  • src/Periphery/LiFiDEXAggregator.sol
📚 Learning: 2025-08-26T12:11:21.073Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: src/Periphery/Lda/Facets/CoreRouteFacet.sol:4-6
Timestamp: 2025-08-26T12:11:21.073Z
Learning: OpenZeppelin's SafeERC20 library provides safePermit functionality for IERC20Permit tokens. The pattern "using SafeERC20 for IERC20Permit;" enables calling safePermit on IERC20Permit tokens safely. This functionality is available in recent versions of OpenZeppelin contracts.

Applied to files:

  • src/Periphery/LiFiDEXAggregator.sol
📚 Learning: 2024-10-14T08:23:38.076Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#831
File: src/Helpers/WithdrawablePeriphery.sol:26-30
Timestamp: 2024-10-14T08:23:38.076Z
Learning: In the `WithdrawablePeriphery.sol` contract, when transferring Ether in the `withdrawToken` function, prefer using `SafeTransferLib.safeTransferETH` instead of low-level `call` for safer Ether transfers.

Applied to files:

  • src/Periphery/LiFiDEXAggregator.sol
📚 Learning: 2025-08-27T23:01:41.042Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: src/Libraries/LibUniV3Logic.sol:4-5
Timestamp: 2025-08-27T23:01:41.042Z
Learning: In the lifinance/contracts repository, the pattern `import { IERC20, SafeERC20 } from "openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";` is correctly used throughout the codebase and works as expected. SafeERC20.sol re-exports IERC20 in modern OpenZeppelin versions, making this combined import valid. Do not suggest splitting these imports.

Applied to files:

  • src/Periphery/LiFiDEXAggregator.sol
📚 Learning: 2025-08-27T23:01:41.042Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: src/Libraries/LibUniV3Logic.sol:4-5
Timestamp: 2025-08-27T23:01:41.042Z
Learning: In modern OpenZeppelin versions (v4.0+), SafeERC20.sol re-exports IERC20, making the combined import `import { IERC20, SafeERC20 } from "openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";` completely valid and working. Do not suggest splitting these imports as they work correctly as a combined import.

Applied to files:

  • src/Periphery/LiFiDEXAggregator.sol
📚 Learning: 2025-04-21T03:17:53.443Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1109
File: deployments/worldchain.json:28-28
Timestamp: 2025-04-21T03:17:53.443Z
Learning: For deployment PRs involving address updates like the RelayFacet to Worldchain, verify the actual presence of entries in files before reporting issues. The RelayFacet exists in the diamond log file and the PR diff already contains the necessary address change.

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-04-21T03:17:53.443Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1109
File: deployments/worldchain.json:28-28
Timestamp: 2025-04-21T03:17:53.443Z
Learning: For deployment PRs updating contract addresses (like RelayFacet on Worldchain), verify the presence of entries in all relevant files (worldchain.json, worldchain.diamond.json, _deployments_log_file.json) before reporting inconsistencies. The RelayFacet entry exists in all required deployment files with the correct address.

Applied to files:

  • deployments/arbitrum.staging.json
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : Facet contracts must implement: internal _startBridge, swapAndStartBridgeTokensVia{FacetName}, and startBridgeTokensVia{FacetName}

Applied to files:

  • docs/EverclearFacet.md
  • test/solidity/Facets/EverclearFacet.t.sol
  • src/Facets/EverclearV2Facet.sol
  • src/Facets/EverclearFacet.sol
  • templates/facet.template.hbs
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to script/deploy/facets/Deploy*.s.sol : Deployment scripts for facets must be named Deploy{ContractName}.s.sol and inherit DeployScriptBase; deploy using deploy(type(ContractName).creationCode); omit getConstructorArgs() when not needed

Applied to files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to script/deploy/facets/Update*.s.sol : Update scripts must be named Update{ContractName}.s.sol, inherit UpdateScriptBase, call update("{ContractName}") and use getExcludes() to return excluded selectors

Applied to files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
📚 Learning: 2025-08-26T15:19:07.800Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: script/deploy/facets/LDA/DeployAlgebraFacet.s.sol:4-4
Timestamp: 2025-08-26T15:19:07.800Z
Learning: DeployScriptBase.sol is located at script/deploy/facets/utils/DeployScriptBase.sol, not script/deploy/utils/DeployScriptBase.sol. Import paths from script/deploy/facets/LDA/ should use "../utils/DeployScriptBase.sol" to reference it correctly.

Applied to files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-10-02T18:14:45.047Z
Learnt from: mirooon
PR: lifinance/contracts#1406
File: script/deploy/facets/UpdateUnitFacet.s.sol:1-3
Timestamp: 2025-10-02T18:14:45.047Z
Learning: For update scripts in script/deploy/facets/, the SPDX license identifier should be immediately followed by the pragma statement without a blank line in between, as confirmed by mirooon for script/deploy/facets/UpdateUnitFacet.s.sol.

Applied to files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to script/deploy/facets/Deploy*.s.sol : When constructor args are required, implement getConstructorArgs() using stdJson, then call deploy(type(FacetName).creationCode) and return (deployed, constructorArgs)

Applied to files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-09-25T00:04:16.437Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1395
File: script/deploy/zksync/DeployFeeForwarder.zksync.s.sol:4-4
Timestamp: 2025-09-25T00:04:16.437Z
Learning: ZkSync deployment scripts have their own DeployScriptBase.sol located at script/deploy/zksync/utils/DeployScriptBase.sol, and all ZkSync deployment scripts use the relative import path "./utils/DeployScriptBase.sol" to reference it, not "../facets/utils/DeployScriptBase.sol".

Applied to files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-01-28T14:27:50.689Z
Learnt from: ezynda3
PR: lifinance/contracts#924
File: script/deploy/zksync/DeployReceiverStargateV2.s.sol:19-21
Timestamp: 2025-01-28T14:27:50.689Z
Learning: In LiFi's deployment scripts, the `deploy` method in `DeployScriptBase` handles the concatenation of constructor arguments with the contract's creation code, so child contracts don't need to concatenate the arguments explicitly.

Applied to files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : Apply required modifiers where appropriate: nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps/doesContainSourceSwaps, doesNotContainDestinationCalls/doesContainDestinationCalls

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
  • src/Facets/EverclearV2Facet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : Facet contracts must import/use: ILiFi, LibAsset, LibSwap, LibAllowList; and use security mixins ReentrancyGuard, SwapperV2, Validatable; ECDSA optional

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
  • src/Facets/EverclearV2Facet.sol
  • src/Facets/EverclearFacet.sol
  • templates/facet.template.hbs
📚 Learning: 2025-09-16T07:56:45.093Z
Learnt from: ezynda3
PR: lifinance/contracts#1324
File: test/solidity/Facets/EcoFacet.t.sol:135-141
Timestamp: 2025-09-16T07:56:45.093Z
Learning: In EcoFacet test setup, the isNative parameter in swap-and-bridge flows refers to the bridge token type (output), not the swap input type. The ERC20 branch (isNative=false) can still swap from native ETH to ERC20 tokens, requiring msg.value = swapData[0].fromAmount for the ETH input to the swap.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2024-10-22T03:16:28.754Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#807
File: test/solidity/Facets/GasZipFacet.t.sol:212-213
Timestamp: 2024-10-22T03:16:28.754Z
Learning: In the `GasZipFacetTest`, for the test case `testBase_Revert_SwapAndBridgeWithInvalidSwapData()`, a generic revert is expected, so `vm.expectRevert();` without specifying the expected error is appropriate.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-01-09T04:17:46.190Z
Learnt from: ezynda3
PR: lifinance/contracts#914
File: deployments/_deployments_log_file.json:26902-26916
Timestamp: 2025-01-09T04:17:46.190Z
Learning: Updates to _deployments_log_file.json can represent backfilling of historical deployment data, not just new deployments. Such updates don't require new audits.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2025-08-07T10:20:01.383Z
Learnt from: mirooon
PR: lifinance/contracts#1283
File: deployments/ronin.diamond.json:65-68
Timestamp: 2025-08-07T10:20:01.383Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, carefully verify that target state configuration files (like script/deploy/_targetState.json) and deployment log files have been updated before flagging missing entries. The AI summary section should be consulted to understand all file changes, as manual searches might miss entries due to formatting differences or search limitations.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2025-09-09T10:39:26.383Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1357
File: deployments/lens.diamond.json:48-51
Timestamp: 2025-09-09T10:39:26.383Z
Learning: In the lifinance/contracts repository, when deployment JSON files show address changes (like AcrossFacetV3 address updates in deployments/*.diamond.json), the corresponding _deployments_log_file.json updates may be handled in separate PRs rather than the same PR that updates the diamond configuration files.

Applied to files:

  • deployments/_deployments_log_file.json
  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-07-04T08:59:08.108Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1256
File: deployments/zksync.diamond.json:81-87
Timestamp: 2025-07-04T08:59:08.108Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, carefully verify that target state configuration files (like script/deploy/_targetState.json) have been updated before flagging missing entries. The AI summary section should be consulted to understand all file changes, as manual searches might miss entries due to formatting differences or search limitations.

Applied to files:

  • deployments/_deployments_log_file.json
📚 Learning: 2025-09-22T00:52:26.172Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1388
File: deployments/hyperevm.diamond.json:72-75
Timestamp: 2025-09-22T00:52:26.172Z
Learning: In diamond configuration files (deployments/*.diamond.json), it's acceptable to have multiple versions of the same facet (e.g., GlacisFacet v1.0.0 and v1.1.0) deployed at different contract addresses. This is intentional design for version coexistence, gradual migration, or backward compatibility purposes.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-09-27T07:10:15.586Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#812
File: deployments/polygon.diamond.json:4-11
Timestamp: 2024-09-27T07:10:15.586Z
Learning: In `deployments/polygon.diamond.json`, it's acceptable for certain facets to have empty names and versions when specified by the developer.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-09-16T01:39:54.099Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1381
File: deployments/arbitrum.json:65-69
Timestamp: 2025-09-16T01:39:54.099Z
Learning: When verifying facet deployments across .json and .diamond.json files, search by facet name rather than trying to cross-reference addresses between the files, as the same contract can have different addresses in different deployment files.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : In {facetName}Data, receiverAddress must be the first field and be validated against bridgeData.receiver; verify targetChainId equals bridgeData.destinationChain for EVM-to-EVM

Applied to files:

  • src/Facets/EverclearV2Facet.sol
  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : Emit LiFiTransferStarted at the start of a transaction before external calls; do not emit LiFiTransferCompleted or LiFiTransferRecovered in facets

Applied to files:

  • src/Facets/EverclearV2Facet.sol
📚 Learning: 2025-10-02T18:10:09.934Z
Learnt from: mirooon
PR: lifinance/contracts#1406
File: src/Facets/UnitFacet.sol:75-81
Timestamp: 2025-10-02T18:10:09.934Z
Learning: In UnitFacet.sol and similar facet contracts in src/Facets/, the LiFiTransferStarted event emission should ALWAYS be at the end of the _startBridge internal function, after all validations and asset transfers have been completed successfully.

Applied to files:

  • src/Facets/EverclearV2Facet.sol
  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : For non-EVM chains: receiverAddress must be bytes (not bytes32), must not be zero, and bridgeData.receiver must equal NON_EVM_ADDRESS

Applied to files:

  • src/Facets/EverclearV2Facet.sol
📚 Learning: 2025-07-16T01:04:55.857Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1275
File: src/Facets/AllBridgeFacet.sol:186-188
Timestamp: 2025-07-16T01:04:55.857Z
Learning: In LiFi facet contracts, when public entry point functions have `nonReentrant` modifier protection, internal functions like `_startBridge` that they call benefit from this reentrancy protection, making event emission order after external calls acceptable from a security perspective.

Applied to files:

  • src/Facets/EverclearV2Facet.sol
  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-07-16T01:03:08.106Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1275
File: src/Facets/AllBridgeFacet.sol:164-164
Timestamp: 2025-07-16T01:03:08.106Z
Learning: In src/Facets/AllBridgeFacet.sol, the team has decided that explicit validation for address downcasting from `_bridgeData.sendingAssetId` to `bytes32(uint256(uint160(_bridgeData.sendingAssetId)))` is not required, accepting the potential risk of silent overflow from unsafe downcasting.

Applied to files:

  • src/Facets/EverclearV2Facet.sol
  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : Facet contracts must be located in src/Facets and include "Facet" in the contract name

Applied to files:

  • templates/facet.template.hbs
📚 Learning: 2025-10-02T18:14:51.385Z
Learnt from: mirooon
PR: lifinance/contracts#1406
File: src/Facets/UnitFacet.sol:1-2
Timestamp: 2025-10-02T18:14:51.385Z
Learning: For facet contracts in src/Facets/, the SPDX license identifier should be immediately followed by the pragma statement without a blank line in between, as confirmed by mirooon for src/Facets/UnitFacet.sol.

Applied to files:

  • templates/facet.template.hbs
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : For native fees in facets, use the _depositAndSwap variant and reserve required fees before execution

Applied to files:

  • templates/facet.template.hbs
📚 Learning: 2024-11-26T01:16:27.721Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#782
File: deployments/worldchain.diamond.json:40-43
Timestamp: 2024-11-26T01:16:27.721Z
Learning: Version inconsistencies of 'GenericSwapFacetV3' across deployment configurations are acceptable if they are only due to differences in Solidity pragma directives.

Applied to files:

  • templates/facet.template.hbs
🧬 Code graph analysis (2)
script/deploy/tron/deploy-and-register-everclear-facet.ts (5)
script/deploy/tron/utils.ts (12)
  • getEnvironment (131-138)
  • validateBalance (1115-1130)
  • hexToTronAddress (1098-1103)
  • confirmDeployment (1135-1173)
  • checkExistingDeployment (665-695)
  • getContractVersion (289-310)
  • deployContractWithLogging (699-753)
  • printDeploymentSummary (1178-1216)
  • getContractAddress (221-240)
  • getFacetSelectors (610-660)
  • displayRegistrationInfo (1251-1271)
  • registerFacetToDiamond (880-1040)
script/demoScripts/utils/demoScriptHelpers.ts (2)
  • getEnvVar (591-597)
  • getPrivateKeyForEnvironment (918-924)
script/deploy/tron/types.ts (2)
  • ITronDeploymentConfig (1-12)
  • IDeploymentResult (66-73)
script/deploy/tron/TronContractDeployer.ts (1)
  • TronContractDeployer (18-529)
script/deploy/tron/constants.ts (1)
  • MIN_BALANCE_WARNING (14-14)
script/demoScripts/demoEverclear.ts (2)
script/common/types.ts (1)
  • SupportedChain (3-3)
script/demoScripts/utils/demoScriptHelpers.ts (5)
  • setupEnvironment (654-708)
  • ensureBalance (847-868)
  • ensureAllowance (873-907)
  • addressToBytes32LeftPadded (97-99)
  • executeTransaction (806-842)
🪛 GitHub Check: Olympix Integrated Security
src/Facets/EverclearV2Facet.sol

[notice] 129-129:
Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events


[warning] 158-158:
Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call


[notice] 184-184:
Performing a narrowing downcast may result in silent overflow due to bit truncation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unsafe-downcast


[warning] 191-191:
Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call

src/Facets/EverclearFacet.sol

[notice] 129-129:
Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events


[warning] 158-158:
Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call


[notice] 184-184:
Performing a narrowing downcast may result in silent overflow due to bit truncation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unsafe-downcast


[warning] 191-191:
Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call

🪛 markdownlint-cli2 (0.18.1)
docs/EverclearFacet.md

79-79: Link text should be descriptive

(MD059, descriptive-link-text)


85-85: Link text should be descriptive

(MD059, descriptive-link-text)


116-116: Link text should be descriptive

(MD059, descriptive-link-text)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: run-unit-tests
  • GitHub Check: enforce-min-test-coverage
🔇 Additional comments (14)
src/Periphery/LiFiDEXAggregator.sol (1)

5-6: LGTM: Import reorganization improves clarity.

Splitting the IERC20Permit import from the SafeERC20 import is appropriate since IERC20Permit is defined in a separate file (extensions/IERC20Permit.sol). This makes the import sources explicit and maintains the same functionality.

templates/facet.template.hbs (3)

1-1: LGTM: License identifier updated to match guidelines.

The license identifier has been corrected from LGPL-3.0 to LGPL-3.0-only, which aligns with the coding guidelines requirement for first-party Solidity files.

As per coding guidelines


5-7: LGTM: Essential library imports added.

The addition of LibDiamond, LibAsset, and LibSwap imports aligns with facet contract conventions. These libraries are used for:

  • LibDiamond: Owner enforcement (line 59)
  • LibAsset: Asset handling operations (line 84)
  • LibSwap: Swap data structures and operations (line 108)

As per coding guidelines


12-12: LGTM: Title annotation format corrected.

Removing the space between the name and "Facet" makes the title consistent with actual facet contract naming conventions (e.g., EverclearFacet, AcrossFacet), where the contract name and "Facet" suffix form a single word.

script/deploy/facets/UpdateEverclearFacet.s.sol (1)

1-16: LGTM: Update script follows conventions.

The update script correctly follows all coding guidelines and conventions:

  • ✓ Named Update{ContractName}.s.sol
  • ✓ Inherits UpdateScriptBase
  • ✓ Calls update("EverclearFacet") with the correct facet name
  • ✓ SPDX license identifier immediately followed by pragma
  • ✓ Returns (address[] memory facets, bytes memory cutData) as expected

As per coding guidelines

deployments/arbitrum.staging.json (1)

64-65: Resolved: EverclearFacet address consistency confirmed across deployment files and logs. Verified presence in deployments/arbitrum.staging.json, deployments/arbitrum.diamond.staging.json, and deployments/_deployments_log_file.json.

config/everclear.json (1)

1-10: Verify fee adapter deployment and V2 configuration.

  • Confirm the fee adapter at 0x15a7cA97D1ed168fB34a4055CEFa2E2f9Bdb6C75 is deployed on Mainnet and Arbitrum (e.g. via eth_getCode RPC or Etherscan/Ethplorer).
  • If V2 isn’t yet deployed, replace the empty-string value for feeAdapterV2 with null or omit the field entirely to avoid ambiguity.
  • Update the config once V2 is live with the correct address.
script/deploy/tron/deploy-and-register-everclear-facet.ts (2)

37-90: Good CLI/script hygiene

Uses citty, consola, env validation, guarded exits, and retries. Looks solid.


3-6: TronWeb named import is correct TronWeb v6 uses named exports; no change is needed.

Likely an incorrect or invalid review comment.

src/Facets/EverclearFacet.sol (2)

158-172: OK to ignore return values here.

newIntent returns values but success/failure is conveyed by revert semantics; no action needed. Tool warning can be ignored.

Also applies to: 191-205


44-54: Non‑EVM receiver type differs from guideline (bytes vs bytes32).

Guideline suggests bytes for non‑EVM receiverAddress. Here it’s bytes32 (and corresponding event BridgeToNonEVMChainBytes32). Confirm this deviation is intentional for Everclear and documented; otherwise consider switching to bytes for consistency.

As per coding guidelines

src/Interfaces/IEverclearFeeAdapter.sol (1)

29-42: Units: “amount normalized to 18 decimals” — verify producer responsibilities.

Facet passes token amounts as-is; confirm the adapter normalizes to 18 decimals internally or require callers to normalize to avoid ambiguity in implementers.

test/solidity/Facets/EverclearFacet.t.sol (1)

247-260: Non‑EVM path coverage looks good.

Validation for NON_EVM_ADDRESS, Solana mapping, event assertions, and native fee flows are covered well.

Please confirm Solana Everclear chain ID 1399811149 matches current Everclear routing for the targeted networks.

Also applies to: 791-807

deployments/arbitrum.diamond.staging.json (1)

184-215: Confirm empty facets, EverclearFacet duplicates, and Permit2Proxy update

  • Several facet slots in deployments/arbitrum.diamond.staging.json have empty Name/Version entries—confirm these placeholders are intentional or remove them.
  • EverclearFacet is registered at three addresses with version 1.0.0—confirm co-deployment of identical versions is expected.
  • No references remain to the old Permit2Proxy address; ensure all configs/scripts now point to the new Permit2Proxy address.

…for invalid call data and unsupported chain IDs, changed SPDX license to LGPL-3.0-only in deployment scripts, and removed duplicate EverclearFacet entries from deployment JSON
Copy link
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: 1

🧹 Nitpick comments (2)
script/deploy/facets/UpdateEverclearFacet.s.sol (2)

7-7: Inconsistent contract name for update script.

The contract is named DeployScript but this is an update script. Consider renaming to UpdateScript or a more descriptive name that reflects its purpose as an update script rather than a deployment script.


5-8: Remove unused imports and declarations.

The stdJson import and using stdJson for string declaration are not used anywhere in this file. Remove them to reduce code clutter.

Apply this diff:

 import { UpdateScriptBase } from "./utils/UpdateScriptBase.sol";
-import { stdJson } from "forge-std/StdJson.sol";
 
 contract DeployScript is UpdateScriptBase {
-    using stdJson for string;
-
     function run()
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 533144a and d50ab7b.

📒 Files selected for processing (5)
  • deployments/arbitrum.diamond.staging.json (1 hunks)
  • script/deploy/facets/DeployEverclearFacet.s.sol (1 hunks)
  • script/deploy/facets/UpdateEverclearFacet.s.sol (1 hunks)
  • src/Facets/EverclearFacet.sol (1 hunks)
  • src/Facets/EverclearV2Facet.sol (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • deployments/arbitrum.diamond.staging.json
  • src/Facets/EverclearV2Facet.sol
🧰 Additional context used
📓 Path-based instructions (6)
{src,test/solidity,script}/**/*.sol

📄 CodeRabbit inference engine (conventions.md)

{src,test/solidity,script}/**/*.sol: All Solidity files must start with a license identifier, followed by a blank line, then the pragma statement
Use SPDX license identifier // SPDX-License-Identifier: LGPL-3.0-only for all first-party Solidity files
Error names must be descriptive PascalCase, use custom errors instead of revert() strings, and omit error messages for gas optimization
Solidity variable/function naming: state variables camelCase; function params camelCase with leading underscore; constants and immutables in CONSTANT_CASE; private/internal variables camelCase; function names camelCase

Files:

  • src/Facets/EverclearFacet.sol
  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
src/**/*.sol

📄 CodeRabbit inference engine (conventions.md)

src/**/*.sol: Every contract must include NatSpec header in this order: @title, @author LI.FI (https://li.fi), @notice, @Custom:version X.Y.Z
All public/external functions must have NatSpec comments documenting purpose, params, and returns
Add inline comments for complex logic, optimizations, gas-saving techniques, and math steps
Emit GenericSwapCompleted after successful same-chain swap completion

Files:

  • src/Facets/EverclearFacet.sol
src/Facets/**/*Facet.sol

📄 CodeRabbit inference engine (conventions.md)

src/Facets/**/*Facet.sol: Facet contracts must be located in src/Facets and include "Facet" in the contract name
Facet contracts must implement: internal _startBridge, swapAndStartBridgeTokensVia{FacetName}, and startBridgeTokensVia{FacetName}
Facet contracts must import/use: ILiFi, LibAsset, LibSwap, LibAllowList; and use security mixins ReentrancyGuard, SwapperV2, Validatable; ECDSA optional
Do not use msg.sender as refund address; require an explicit parameter for refund address
In {facetName}Data, receiverAddress must be the first field and be validated against bridgeData.receiver; verify targetChainId equals bridgeData.destinationChain for EVM-to-EVM
Apply required modifiers where appropriate: nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps/doesContainSourceSwaps, doesNotContainDestinationCalls/doesContainDestinationCalls
Emit LiFiTransferStarted at the start of a transaction before external calls; do not emit LiFiTransferCompleted or LiFiTransferRecovered in facets
For native fees in facets, use the _depositAndSwap variant and reserve required fees before execution
For non-EVM chains: receiverAddress must be bytes (not bytes32), must not be zero, and bridgeData.receiver must equal NON_EVM_ADDRESS

Files:

  • src/Facets/EverclearFacet.sol
**/*.sol

📄 CodeRabbit inference engine (conventions.md)

Follow solhint rules as configured in .solhint.json

Files:

  • src/Facets/EverclearFacet.sol
  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
script/deploy/facets/Update*.s.sol

📄 CodeRabbit inference engine (conventions.md)

Update scripts must be named Update{ContractName}.s.sol, inherit UpdateScriptBase, call update("{ContractName}") and use getExcludes() to return excluded selectors

Files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
script/deploy/facets/Deploy*.s.sol

📄 CodeRabbit inference engine (conventions.md)

script/deploy/facets/Deploy*.s.sol: Deployment scripts for facets must be named Deploy{ContractName}.s.sol and inherit DeployScriptBase; deploy using deploy(type(ContractName).creationCode); omit getConstructorArgs() when not needed
When constructor args are required, implement getConstructorArgs() using stdJson, then call deploy(type(FacetName).creationCode) and return (deployed, constructorArgs)

Files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
🧠 Learnings (27)
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : Facet contracts must implement: internal _startBridge, swapAndStartBridgeTokensVia{FacetName}, and startBridgeTokensVia{FacetName}

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : In {facetName}Data, receiverAddress must be the first field and be validated against bridgeData.receiver; verify targetChainId equals bridgeData.destinationChain for EVM-to-EVM

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-10-02T18:10:09.934Z
Learnt from: mirooon
PR: lifinance/contracts#1406
File: src/Facets/UnitFacet.sol:75-81
Timestamp: 2025-10-02T18:10:09.934Z
Learning: In UnitFacet.sol and similar facet contracts in src/Facets/, the LiFiTransferStarted event emission should ALWAYS be at the end of the _startBridge internal function, after all validations and asset transfers have been completed successfully.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : Emit LiFiTransferStarted at the start of a transaction before external calls; do not emit LiFiTransferCompleted or LiFiTransferRecovered in facets

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : Facet contracts must import/use: ILiFi, LibAsset, LibSwap, LibAllowList; and use security mixins ReentrancyGuard, SwapperV2, Validatable; ECDSA optional

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : Apply required modifiers where appropriate: nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps/doesContainSourceSwaps, doesNotContainDestinationCalls/doesContainDestinationCalls

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-07-16T01:04:55.857Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1275
File: src/Facets/AllBridgeFacet.sol:186-188
Timestamp: 2025-07-16T01:04:55.857Z
Learning: In LiFi facet contracts, when public entry point functions have `nonReentrant` modifier protection, internal functions like `_startBridge` that they call benefit from this reentrancy protection, making event emission order after external calls acceptable from a security perspective.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-07-16T01:03:08.106Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1275
File: src/Facets/AllBridgeFacet.sol:164-164
Timestamp: 2025-07-16T01:03:08.106Z
Learning: In src/Facets/AllBridgeFacet.sol, the team has decided that explicit validation for address downcasting from `_bridgeData.sendingAssetId` to `bytes32(uint256(uint160(_bridgeData.sendingAssetId)))` is not required, accepting the potential risk of silent overflow from unsafe downcasting.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2024-12-02T06:33:33.309Z
Learnt from: ezynda3
PR: lifinance/contracts#827
File: src/Facets/DeBridgeDlnFacet.sol:0-0
Timestamp: 2024-12-02T06:33:33.309Z
Learning: In Solidity version 0.8.0 and above, arithmetic underflows and overflows automatically cause a revert; therefore, explicit checks for arithmetic underflows are not necessary in functions like `_startBridge` in `DeBridgeDlnFacet.sol`.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2024-10-22T03:14:52.578Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#807
File: src/Facets/GasZipFacet.sol:53-53
Timestamp: 2024-10-22T03:14:52.578Z
Learning: In `src/Facets/GasZipFacet.sol`, when checking `msg.value`, the team prefers to use strict equality (`msg.value == _bridgeData.minAmount`) to save gas and avoid refunding excess Ether.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-07-16T01:04:11.083Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1275
File: src/Facets/AllBridgeFacet.sol:175-175
Timestamp: 2025-07-16T01:04:11.083Z
Learning: In AllBridgeFacet.sol, zero fee validation is not required at the contract level because the backend system ensures that calldata and msg.value are properly aligned before transactions reach the contract.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to script/deploy/facets/Deploy*.s.sol : Deployment scripts for facets must be named Deploy{ContractName}.s.sol and inherit DeployScriptBase; deploy using deploy(type(ContractName).creationCode); omit getConstructorArgs() when not needed

Applied to files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to script/deploy/facets/Update*.s.sol : Update scripts must be named Update{ContractName}.s.sol, inherit UpdateScriptBase, call update("{ContractName}") and use getExcludes() to return excluded selectors

Applied to files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
📚 Learning: 2025-10-02T18:14:45.047Z
Learnt from: mirooon
PR: lifinance/contracts#1406
File: script/deploy/facets/UpdateUnitFacet.s.sol:1-3
Timestamp: 2025-10-02T18:14:45.047Z
Learning: For update scripts in script/deploy/facets/, the SPDX license identifier should be immediately followed by the pragma statement without a blank line in between, as confirmed by mirooon for script/deploy/facets/UpdateUnitFacet.s.sol.

Applied to files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-08-26T15:19:07.800Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: script/deploy/facets/LDA/DeployAlgebraFacet.s.sol:4-4
Timestamp: 2025-08-26T15:19:07.800Z
Learning: DeployScriptBase.sol is located at script/deploy/facets/utils/DeployScriptBase.sol, not script/deploy/utils/DeployScriptBase.sol. Import paths from script/deploy/facets/LDA/ should use "../utils/DeployScriptBase.sol" to reference it correctly.

Applied to files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to script/deploy/facets/Deploy*.s.sol : When constructor args are required, implement getConstructorArgs() using stdJson, then call deploy(type(FacetName).creationCode) and return (deployed, constructorArgs)

Applied to files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-09-25T00:04:16.437Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1395
File: script/deploy/zksync/DeployFeeForwarder.zksync.s.sol:4-4
Timestamp: 2025-09-25T00:04:16.437Z
Learning: ZkSync deployment scripts have their own DeployScriptBase.sol located at script/deploy/zksync/utils/DeployScriptBase.sol, and all ZkSync deployment scripts use the relative import path "./utils/DeployScriptBase.sol" to reference it, not "../facets/utils/DeployScriptBase.sol".

Applied to files:

  • script/deploy/facets/UpdateEverclearFacet.s.sol
  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-01-28T14:27:50.689Z
Learnt from: ezynda3
PR: lifinance/contracts#924
File: script/deploy/zksync/DeployReceiverStargateV2.s.sol:19-21
Timestamp: 2025-01-28T14:27:50.689Z
Learning: In LiFi's deployment scripts, the `deploy` method in `DeployScriptBase` handles the concatenation of constructor arguments with the contract's creation code, so child contracts don't need to concatenate the arguments explicitly.

Applied to files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-08-27T22:29:51.839Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: test/solidity/Periphery/Lda/Facets/SyncSwapV2Facet.t.sol:1-2
Timestamp: 2025-08-27T22:29:51.839Z
Learning: Test files in test/solidity/**/*.t.sol should use the LGPL-3.0-only SPDX license identifier, not Unlicense.

Applied to files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to {src,test/solidity,script}/**/*.sol : Use SPDX license identifier // SPDX-License-Identifier: LGPL-3.0-only for all first-party Solidity files

Applied to files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-09-24T23:55:07.082Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1395
File: script/deploy/facets/DeployFeeForwarder.s.sol:1-1
Timestamp: 2025-09-24T23:55:07.082Z
Learning: All Solidity files in the lifinance/contracts repository, including deployment scripts in script/deploy/, must use the SPDX license identifier "// SPDX-License-Identifier: LGPL-3.0-only" as specified in conventions.md. This applies to all .sol files in src/, test/solidity/, and script/ directories.

Applied to files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-08-29T14:06:33.384Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: script/deploy/facets/LDA/UpdateUniV2StyleFacet.s.sol:1-2
Timestamp: 2025-08-29T14:06:33.384Z
Learning: For LDA deployment and update scripts in script/deploy/facets/LDA/, the SPDX license identifier should be immediately followed by the pragma statement without a blank line in between, as confirmed by mirooon for script/deploy/facets/LDA/UpdateUniV2StyleFacet.s.sol.

Applied to files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-08-29T14:05:37.002Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: script/deploy/facets/LDA/DeployLDAOwnershipFacet.s.sol:1-3
Timestamp: 2025-08-29T14:05:37.002Z
Learning: For deployment script files in script/deploy/facets/LDA/, the SPDX license identifier should be immediately followed by the pragma statement without a blank line in between, as confirmed by mirooon for script/deploy/facets/LDA/DeployLDAOwnershipFacet.s.sol.

Applied to files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-08-29T14:06:01.072Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: script/deploy/facets/LDA/UpdateCurveFacet.s.sol:1-2
Timestamp: 2025-08-29T14:06:01.072Z
Learning: For script/deploy/facets/LDA/UpdateCurveFacet.s.sol and similar LDA update scripts, the SPDX license identifier should be immediately followed by the pragma statement without requiring a blank line in between, as confirmed by mirooon.

Applied to files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-08-29T14:05:58.427Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: script/deploy/facets/LDA/DeployLDAPeripheryRegistryFacet.s.sol:1-3
Timestamp: 2025-08-29T14:05:58.427Z
Learning: For deployment scripts in script/deploy/facets/LDA/, the SPDX license identifier should be immediately followed by the pragma statement without a blank line in between, following the same convention as other LDA-related files, as confirmed by mirooon for script/deploy/facets/LDA/DeployLDAPeripheryRegistryFacet.s.sol.

Applied to files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-08-29T11:18:56.656Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: src/Periphery/LDA/Facets/NativeWrapperFacet.sol:1-2
Timestamp: 2025-08-29T11:18:56.656Z
Learning: For src/Periphery/LDA/Facets/NativeWrapperFacet.sol, the SPDX license identifier should be immediately followed by the pragma statement without a blank line in between, as confirmed by mirooon.

Applied to files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
📚 Learning: 2025-08-29T14:05:31.360Z
Learnt from: mirooon
PR: lifinance/contracts#1328
File: script/deploy/facets/LDA/DeployLDAEmergencyPauseFacet.s.sol:1-2
Timestamp: 2025-08-29T14:05:31.360Z
Learning: For LDA deployment scripts in script/deploy/facets/LDA/, the SPDX license identifier should be immediately followed by the pragma statement without requiring a blank line in between, as confirmed by mirooon.

Applied to files:

  • script/deploy/facets/DeployEverclearFacet.s.sol
🔇 Additional comments (9)
script/deploy/facets/UpdateEverclearFacet.s.sol (1)

10-15: LGTM!

The run() function correctly delegates to update("EverclearFacet") and returns the facets and cutData as expected for an update script.

script/deploy/facets/DeployEverclearFacet.s.sol (3)

1-2: License identifier correctly updated.

The SPDX license identifier has been updated to LGPL-3.0-only as required by the coding guidelines, addressing the previous review comment.


8-20: LGTM!

The deployment script correctly:

  • Extends DeployScriptBase with proper contract name
  • Implements getConstructorArgs() to read configuration
  • Deploys using deploy(type(EverclearFacet).creationCode) pattern
  • Returns both the deployed contract and constructor arguments

The implementation follows all deployment script conventions.


22-31: JSON path is valid: .mainnet.feeAdapter & .arbitrum.feeAdapter exist in config/everclear.json, and _getConfigContractAddress (via stdJson.readAddress) handles the leading dot.

src/Facets/EverclearFacet.sol (5)

56-59: Implement the agreed-upon custom error for fee validation.

In previous review comments, you agreed to add a specific FeeExceedsAmount custom error for better user experience when the fee exceeds the bridged amount. This custom error has not yet been added to the contract.

Referencing past review discussion.

Apply this diff to add the custom error:

 /// @notice Reverts when the destination chain is not supported by Everclear
 error UnsupportedEverclearChainId();
+/// @notice Reverts when the Everclear fee exceeds the bridged amount
+error FeeExceedsAmount();

133-138: Use the specific custom error for fee validation.

The validation currently uses the generic InvalidCallData() error when the fee exceeds minAmount. Per the agreed-upon improvement from previous review, this should use a specific FeeExceedsAmount() error for clearer user feedback.

Referencing past review discussion.

Apply this diff once the custom error is defined:

 // make sure receiver address has a value to prevent potential loss of funds
 // contract does NOT validate _everclearData.deadline and _everclearData.sig to save gas here. Fee adapter will signature with fee and deadline in message anyway.
 if (
     _everclearData.outputAsset == bytes32(0) ||
     _bridgeData.minAmount < _everclearData.fee
-) revert InvalidCallData();
+) {
+    if (_everclearData.outputAsset == bytes32(0)) revert InvalidCallData();
+    if (_bridgeData.minAmount < _everclearData.fee) revert FeeExceedsAmount();
+}

77-95: LGTM! Entry point functions are properly structured.

Both entry point functions correctly implement:

  • All required modifiers (nonReentrant, refundExcessNative, validateBridgeData, doesNotContainDestinationCalls, noNativeAsset)
  • Appropriate source swap validation (doesNotContainSourceSwaps vs containsSourceSwaps)
  • Proper asset handling via LibAsset.depositAsset and _depositAndSwap
  • Clear NatSpec documentation

Also applies to: 101-122


129-215: LGTM! Internal bridging logic is well-implemented.

The _startBridge function correctly handles:

  • Asset validation and approval (lines 135-144)
  • Non-EVM vs EVM destination routing with proper address validation (lines 147-212)
  • Receiver address validation for both paths
  • Chain ID validation and mapping (Solana → Everclear chain ID)
  • Fee deduction arithmetic protected by the minAmount check
  • Event emission at the end after all operations complete

The event emission order (line 214) after external calls is acceptable given the nonReentrant protection on public entry points.

Based on learnings.


161-175: Ignore unchecked return values from newIntent

The call to newIntent will revert on failure and only returns the intentId and Intent struct (not a success flag). Since this facet does not need those returned values, it’s safe to leave them unchecked.

Likely an incorrect or invalid review comment.

@mirooon mirooon marked this pull request as ready for review October 10, 2025 10:54
@lifi-action-bot
Copy link
Collaborator

lifi-action-bot commented Oct 10, 2025

🤖 GitHub Action: Security Alerts Review 🔍

🟢 Dismissed Security Alerts with Comments
The following alerts were dismissed with proper comments:

🟢 View Alert - File: src/Facets/EverclearV2Facet.sol
🔹 Performing a narrowing downcast may result in silent overflow due to bit truncation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unsafe-downcast
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: we do not loose data here

🟢 View Alert - File: src/Facets/EverclearFacet.sol
🔹 Performing a narrowing downcast may result in silent overflow due to bit truncation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unsafe-downcast
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: we do not loose data here

🟢 View Alert - File: src/Facets/EverclearV2Facet.sol
🔹 Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: this is our convention that we emit event after external call

🟢 View Alert - File: src/Facets/EverclearFacet.sol
🔹 Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: this is our convention that we emit event after external call

🟢 View Alert - File: src/Facets/EverclearV2Facet.sol
🔹 Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: no need to check here

🟢 View Alert - File: src/Facets/EverclearV2Facet.sol
🔹 Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: no need to check here

🟢 View Alert - File: src/Facets/EverclearFacet.sol
🔹 Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: not needed to check these values

🟢 View Alert - File: src/Facets/EverclearFacet.sol
🔹 Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: no need to check

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Casting a large uint to int (even at same byte width) may lead to overflow. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/uint-to-int-conversion
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: safe. The amountIn value comes from the pool’s reserves, which are much smaller than the maximum number allowed by int256

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: The return value from IUniswapV3Pool(pool).swap() is not needed because the result is handled by the callback function uniswapV3SwapCallback

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 External calls in a loop may lead to denial of service if those calls revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/calls-in-loop
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: expected and safe. If the call fails, the whole transaction reverts,

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Parameters passed to a constructor that are not validated for correct values may lead to contract creation in an undesired state. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/no-parameter-validation-in-constructor
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: The _owner is already validated in the constructor and the priviledged array t is optiona

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 The contract uses low-level calls without properly verifying the input parameters, potentially leading to unexpected behavior or vulnerabilities. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/low-level-call-params-verified
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: using low-level call to handle non-compliant ERC20s like USDT (returns no bool on approve) This pattern is widely used and handles both compliant and non-compliant tokens safely

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Parameters passed to a constructor that are not validated for correct values may lead to contract creation in an undesired state. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/no-parameter-validation-in-constructor
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: We as the deployer ensure that all constructor parameters, including _bentoBox address, are validated off-chain prior to deployment. This contract is only deployed via automated scripts with predefined, verified inputs. On-chain checks for zero addresses are therefore not requir

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: The return value is not critical for execution flow and is therefore intentionally ignored.

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: 3rd returned value intentionally ignored

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: return values unused. function reverts on failure

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: return values unused would be unsued and function reverts on failure

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Unchecked zero values passed as parameters may be in error or an indication of potentially insecure code design. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/zero-as-parameter
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: Token being zero will revert (nonexistent token), and zero address as spender can’t benefit Safe by design

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Unchecked zero values passed as parameters may be in error or an indication of potentially insecure code design. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/zero-as-parameter
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: TODO: Unrealated to this PR

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Unchecked zero values passed as parameters may be in error or an indication of potentially insecure code design. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/zero-as-parameter
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: TODO Unrelated to this PR

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Unchecked zero values passed as parameters may be in error or an indication of potentially insecure code design. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/zero-as-parameter
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: The amountIn value is always set before this point and only passed here if it is greater than zero

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Unchecked zero values passed as parameters may be in error or an indication of potentially insecure code design. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/zero-as-parameter
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: Not crucial, it would fail anyway

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Unchecked zero values passed as parameters may be in error or an indication of potentially insecure code design. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/zero-as-parameter
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: True but we as a deployer make sure that this param is not zero address

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Making an external call without a gas budget may consume all of the transaction's gas, causing it to revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/call-without-gas-budget
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: It’s wrapped with a success check and fallback decoding logic to handle both cases safely

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Using a payable fallback (including receive) with no explicit functionality may indicate incomplete contract logic. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/empty-payable-fallback
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: This empty receive() function is required to support native token unwrapping

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 External calls in a loop may lead to denial of service if those calls revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/calls-in-loop
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: If the swap fails, the whole transaction reverts

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 External calls in a loop may lead to denial of service if those calls revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/calls-in-loop
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: if the Curve pool is invalid or the call fails, the transaction reverts as expected

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 External calls in a loop may lead to denial of service if those calls revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/calls-in-loop
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: If the swap fails, the whole transaction reverts

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 External calls in a loop may lead to denial of service if those calls revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/calls-in-loop
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: The swap() call is expected to revert if the pool doesn't support the swap or the input is invalid

No unresolved security alerts! 🎉

@lifi-action-bot lifi-action-bot marked this pull request as draft October 10, 2025 10:55
@mirooon mirooon marked this pull request as ready for review October 10, 2025 11:00
Copy link
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

♻️ Duplicate comments (1)
src/Facets/EverclearV2Facet.sol (1)

215-216: Event emission order is acceptable per team convention

Emitting LiFiTransferStarted after external call is aligned with current practice and protected by nonReentrant on entrypoints.

Based on learnings

🧹 Nitpick comments (3)
src/Facets/EverclearV2Facet.sol (3)

1-2: Insert required blank line between SPDX and pragma

Formatting is mandated: license line, then a blank line, then pragma.

As per coding guidelines

-// SPDX-License-Identifier: LGPL-3.0-only
-pragma solidity ^0.8.17;
+// SPDX-License-Identifier: LGPL-3.0-only
+
+pragma solidity ^0.8.17;

36-55: Align non‑EVM receiver type with guideline (bytes, not bytes32)

Guideline says non‑EVM receiverAddress must be bytes. Current type is bytes32. If IEverclearFeeAdapterV2 requires bytes32, document this constraint; otherwise, consider widening to bytes and adjusting event/newIntent overload.

As per coding guidelines


75-96: Add tests for critical paths and invariants

Please cover: fee > minAmount revert, msg.value != nativeFee revert, EVM receiver mismatch revert, non‑EVM zero receiver revert, Solana mapping happy path, destinationChainId > uint32.max revert, bytes32->address upper‑bits non‑zero revert, and ERC20 approval/allowance path.

Also applies to: 98-123

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d50ab7b and f264b7b.

📒 Files selected for processing (2)
  • src/Facets/EverclearFacet.sol (1 hunks)
  • src/Facets/EverclearV2Facet.sol (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
{src,test/solidity,script}/**/*.sol

📄 CodeRabbit inference engine (conventions.md)

{src,test/solidity,script}/**/*.sol: All Solidity files must start with a license identifier, followed by a blank line, then the pragma statement
Use SPDX license identifier // SPDX-License-Identifier: LGPL-3.0-only for all first-party Solidity files
Error names must be descriptive PascalCase, use custom errors instead of revert() strings, and omit error messages for gas optimization
Solidity variable/function naming: state variables camelCase; function params camelCase with leading underscore; constants and immutables in CONSTANT_CASE; private/internal variables camelCase; function names camelCase

Files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
src/**/*.sol

📄 CodeRabbit inference engine (conventions.md)

src/**/*.sol: Every contract must include NatSpec header in this order: @title, @author LI.FI (https://li.fi), @notice, @Custom:version X.Y.Z
All public/external functions must have NatSpec comments documenting purpose, params, and returns
Add inline comments for complex logic, optimizations, gas-saving techniques, and math steps
Emit GenericSwapCompleted after successful same-chain swap completion

Files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
src/Facets/**/*Facet.sol

📄 CodeRabbit inference engine (conventions.md)

src/Facets/**/*Facet.sol: Facet contracts must be located in src/Facets and include "Facet" in the contract name
Facet contracts must implement: internal _startBridge, swapAndStartBridgeTokensVia{FacetName}, and startBridgeTokensVia{FacetName}
Facet contracts must import/use: ILiFi, LibAsset, LibSwap, LibAllowList; and use security mixins ReentrancyGuard, SwapperV2, Validatable; ECDSA optional
Do not use msg.sender as refund address; require an explicit parameter for refund address
In {facetName}Data, receiverAddress must be the first field and be validated against bridgeData.receiver; verify targetChainId equals bridgeData.destinationChain for EVM-to-EVM
Apply required modifiers where appropriate: nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps/doesContainSourceSwaps, doesNotContainDestinationCalls/doesContainDestinationCalls
Emit LiFiTransferStarted at the start of a transaction before external calls; do not emit LiFiTransferCompleted or LiFiTransferRecovered in facets
For native fees in facets, use the _depositAndSwap variant and reserve required fees before execution
For non-EVM chains: receiverAddress must be bytes (not bytes32), must not be zero, and bridgeData.receiver must equal NON_EVM_ADDRESS

Files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
**/*.sol

📄 CodeRabbit inference engine (conventions.md)

Follow solhint rules as configured in .solhint.json

Files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
🧠 Learnings (12)
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : Facet contracts must implement: internal _startBridge, swapAndStartBridgeTokensVia{FacetName}, and startBridgeTokensVia{FacetName}

Applied to files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : In {facetName}Data, receiverAddress must be the first field and be validated against bridgeData.receiver; verify targetChainId equals bridgeData.destinationChain for EVM-to-EVM

Applied to files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
📚 Learning: 2025-10-02T18:10:09.934Z
Learnt from: mirooon
PR: lifinance/contracts#1406
File: src/Facets/UnitFacet.sol:75-81
Timestamp: 2025-10-02T18:10:09.934Z
Learning: In UnitFacet.sol and similar facet contracts in src/Facets/, the LiFiTransferStarted event emission should ALWAYS be at the end of the _startBridge internal function, after all validations and asset transfers have been completed successfully.

Applied to files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : Emit LiFiTransferStarted at the start of a transaction before external calls; do not emit LiFiTransferCompleted or LiFiTransferRecovered in facets

Applied to files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
📚 Learning: 2025-10-10T10:56:04.861Z
Learnt from: mirooon
PR: lifinance/contracts#1413
File: src/Facets/EverclearFacet.sol:4-13
Timestamp: 2025-10-10T10:56:04.861Z
Learning: LibAllowList is only required for facets that make arbitrary external calls to DEX aggregators (e.g., GenericSwapFacetV3). Bridge facets that call specific protocol contracts (like EverclearFacet calling IEverclearFeeAdapter) do not need to import LibAllowList.

Applied to files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : Apply required modifiers where appropriate: nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps/doesContainSourceSwaps, doesNotContainDestinationCalls/doesContainDestinationCalls

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-07-16T01:04:55.857Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1275
File: src/Facets/AllBridgeFacet.sol:186-188
Timestamp: 2025-07-16T01:04:55.857Z
Learning: In LiFi facet contracts, when public entry point functions have `nonReentrant` modifier protection, internal functions like `_startBridge` that they call benefit from this reentrancy protection, making event emission order after external calls acceptable from a security perspective.

Applied to files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
📚 Learning: 2025-07-16T01:03:08.106Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1275
File: src/Facets/AllBridgeFacet.sol:164-164
Timestamp: 2025-07-16T01:03:08.106Z
Learning: In src/Facets/AllBridgeFacet.sol, the team has decided that explicit validation for address downcasting from `_bridgeData.sendingAssetId` to `bytes32(uint256(uint160(_bridgeData.sendingAssetId)))` is not required, accepting the potential risk of silent overflow from unsafe downcasting.

Applied to files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
📚 Learning: 2024-12-02T06:33:33.309Z
Learnt from: ezynda3
PR: lifinance/contracts#827
File: src/Facets/DeBridgeDlnFacet.sol:0-0
Timestamp: 2024-12-02T06:33:33.309Z
Learning: In Solidity version 0.8.0 and above, arithmetic underflows and overflows automatically cause a revert; therefore, explicit checks for arithmetic underflows are not necessary in functions like `_startBridge` in `DeBridgeDlnFacet.sol`.

Applied to files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
📚 Learning: 2024-10-22T03:14:52.578Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#807
File: src/Facets/GasZipFacet.sol:53-53
Timestamp: 2024-10-22T03:14:52.578Z
Learning: In `src/Facets/GasZipFacet.sol`, when checking `msg.value`, the team prefers to use strict equality (`msg.value == _bridgeData.minAmount`) to save gas and avoid refunding excess Ether.

Applied to files:

  • src/Facets/EverclearFacet.sol
  • src/Facets/EverclearV2Facet.sol
📚 Learning: 2025-07-16T01:04:11.083Z
Learnt from: 0xDEnYO
PR: lifinance/contracts#1275
File: src/Facets/AllBridgeFacet.sol:175-175
Timestamp: 2025-07-16T01:04:11.083Z
Learning: In AllBridgeFacet.sol, zero fee validation is not required at the contract level because the backend system ensures that calldata and msg.value are properly aligned before transactions reach the contract.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-09-12T10:17:51.686Z
Learnt from: CR
PR: lifinance/contracts#0
File: conventions.md:0-0
Timestamp: 2025-09-12T10:17:51.686Z
Learning: Applies to src/Facets/**/*Facet.sol : For non-EVM chains: receiverAddress must be bytes (not bytes32), must not be zero, and bridgeData.receiver must equal NON_EVM_ADDRESS

Applied to files:

  • src/Facets/EverclearV2Facet.sol
🔇 Additional comments (12)
src/Facets/EverclearFacet.sol (10)

1-13: LGTM!

The file structure follows all coding guidelines: proper SPDX license identifier, pragma statement, and all required imports (ILiFi, LibAsset, LibSwap, ReentrancyGuard, SwapperV2, Validatable). LibAllowList is correctly omitted since this facet only calls the specific FEE_ADAPTER contract via IEverclearFeeAdapter interface, not arbitrary DEX aggregators.

Based on learnings.


15-25: LGTM!

The contract declaration follows all coding guidelines: complete NatSpec header with @title, @author, @notice, and @Custom:version, plus all required security mixins (ILiFi, ReentrancyGuard, SwapperV2, Validatable, LiFiData).

Based on coding guidelines.


26-32: LGTM!

Storage and constants follow naming conventions: FEE_ADAPTER is properly immutable and documented, and EVERCLEAR_CHAIN_ID_SOLANA uses CONSTANT_CASE as required by coding guidelines.

Based on coding guidelines.


34-55: LGTM!

The EverclearData struct correctly places receiverAddress as the first field as required by coding guidelines. Using bytes32 allows the facet to handle both EVM addresses and non-EVM chain identifiers.

Based on coding guidelines.


57-71: LGTM!

Error naming follows PascalCase convention, and the constructor properly validates that _feeAdapter is not the zero address before setting the immutable FEE_ADAPTER.

Based on coding guidelines.


75-96: LGTM!

The function follows all coding guidelines: correctly named startBridgeTokensViaEverclear, includes all required modifiers (nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps, doesNotContainDestinationCalls, noNativeAsset), and follows the standard pattern of depositing assets before calling the internal _startBridge function.

Based on coding guidelines.


98-123: LGTM!

The function follows all coding guidelines: correctly named swapAndStartBridgeTokensViaEverclear, includes all required modifiers with containsSourceSwaps (correctly different from the no-swap variant), and follows the standard swap-then-bridge pattern using _depositAndSwap.

Based on coding guidelines.


130-145: Fee validation correctly prevents underflow.

The check at line 138 (_bridgeData.minAmount < _everclearData.fee) correctly addresses the concern from the past review comment about preventing silent underflow when fee is deducted at lines 167 and 203. The code uses InvalidCallData() instead of a more specific custom error like FeeExceedsAmount, which is less descriptive but still functional and may align with the codebase's error handling conventions.

The approval of the full minAmount (before fee deduction) is correct since the fee is handled separately by the FEE_ADAPTER.


147-213: LGTM!

Both non-EVM and EVM bridging paths are correctly implemented:

Non-EVM path (lines 147-183):

  • Validates receiverAddress != bytes32(0) as required by coding guidelines for non-EVM chains
  • Correctly maps Solana chain ID to Everclear's chain ID constant
  • Properly emits BridgeToNonEVMChainBytes32 event

EVM path (lines 184-213):

  • Validates that bridgeData.receiver matches everclearData.receiverAddress (lines 187-190) as required by coding guidelines
  • Validates destinationChainId fits in uint32 before casting

The downcasts at lines 188 and 202, and unchecked return values from FEE_ADAPTER.newIntent at lines 162 and 198 were flagged by static analysis but dismissed by the team with appropriate justification.

Based on coding guidelines and past review comments.


215-215: LGTM!

The LiFiTransferStarted event emission at the end of _startBridge, after all external calls, is correct according to the established pattern in LiFi facets. As learned from previous reviews: "LiFiTransferStarted event emission should ALWAYS be at the end of the _startBridge internal function, after all validations and asset transfers have been completed successfully." The nonReentrant modifier on the public entry points provides reentrancy protection.

Based on learnings.

src/Facets/EverclearV2Facet.sol (2)

136-140: Good: explicit checks for outputAsset and fee <= minAmount

Prevents ambiguous underflow and invalid params. LGTM.


192-197: Good: range check before uint32 downcast of destinationChainId

Prevents truncation. LGTM.

Copy link

@0xHarbs 0xHarbs left a comment

Choose a reason for hiding this comment

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

Looks good

Copy link
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: 1

♻️ Duplicate comments (1)
docs/EverclearFacet.md (1)

18-21: Fix swapAndStartBridgeTokensViaEverclear signature in docs to match the facet.

The second bullet still omits the function keyword, uses everclearData instead of EverclearData, and passes the struct by memory instead of calldata. To keep docs in sync with EverclearFacet.sol, consider updating to:

-- `swapAndStartBridgeTokensViaEverclear(BridgeData memory _bridgeData, LibSwap.SwapData[] calldata _swapData, everclearData memory _everclearData)`
+- `function swapAndStartBridgeTokensViaEverclear(BridgeData memory _bridgeData, LibSwap.SwapData[] calldata _swapData, EverclearData calldata _everclearData)`
🧹 Nitpick comments (3)
src/Interfaces/IEverclearFeeAdapter.sol (1)

14-42: Clarify NatSpec for Intent fields that are bytes32 rather than address.

The NatSpec currently describes initiator, receiver, inputAsset, and outputAsset as “the address …”, but the struct types are bytes32. To avoid confusion for integrators (especially around EVM vs non‑EVM encodings), consider clarifying that these are bytes32-encoded identifiers / addresses rather than plain address types, or adjust the wording accordingly.

docs/EverclearFacet.md (1)

84-89: Minor documentation polish: hyphenation and link text.

  • Line 86: consider changing “swap specific library” → “swap‑specific library” for correct hyphenation.
  • Lines 88, 94, 125: links with text “here” are flagged by markdownlint as non‑descriptive. Using more explicit link text (e.g., “LibSwap library”, “BridgeData interface”, “/quote endpoint example guide”) will read better and satisfy MD lint.

Also applies to: 94-95, 125-125

src/Facets/EverclearFacet.sol (1)

135-139: Small comment wording nit in _startBridge (optional).

The inline comment:

// contract does NOT validate _everclearData.deadline and _everclearData.sig to save gas here. Fee adapter will signature with fee and deadline in message anyway.

reads a bit awkwardly (“will signature”). Consider rephrasing to something like:

// Contract does NOT validate _everclearData.deadline and _everclearData.sig to save gas.
// The fee adapter validates the signature (including fee and deadline) in its own logic.

Purely cosmetic; no impact on behavior.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f264b7b and 02661a7.

📒 Files selected for processing (5)
  • config/everclear.json (1 hunks)
  • docs/EverclearFacet.md (1 hunks)
  • src/Facets/EverclearFacet.sol (1 hunks)
  • src/Interfaces/IEverclearFeeAdapter.sol (1 hunks)
  • test/solidity/Facets/EverclearFacet.t.sol (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • config/everclear.json
🧰 Additional context used
🧠 Learnings (50)
📓 Common learnings
Learnt from: mirooon
Repo: lifinance/contracts PR: 1283
File: deployments/ronin.diamond.json:65-68
Timestamp: 2025-08-07T10:20:01.383Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, carefully verify that target state configuration files (like script/deploy/_targetState.json) and deployment log files have been updated before flagging missing entries. The AI summary section should be consulted to understand all file changes, as manual searches might miss entries due to formatting differences or search limitations.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1256
File: deployments/zksync.diamond.json:81-87
Timestamp: 2025-07-04T08:59:08.108Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, carefully verify that target state configuration files (like script/deploy/_targetState.json) have been updated before flagging missing entries. The AI summary section should be consulted to understand all file changes, as manual searches might miss entries due to formatting differences or search limitations.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: src/Periphery/GasZipPeriphery.sol:49-53
Timestamp: 2024-09-23T02:04:16.323Z
Learning: When `LibAsset.maxApproveERC20` is used with `type(uint256).max`, the team acknowledges and accepts the associated security risks. In future reviews, avoid flagging this as a concern.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1334
File: deployments/mainnet.json:54-54
Timestamp: 2025-08-26T02:20:52.515Z
Learning: For deployment PRs in the lifinance/contracts repository, carefully verify the specific scope mentioned in the PR title and description before suggesting updates to other networks. Not all deployments are cross-network updates - some are targeted to specific chains only.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/UniV2StyleFacet.sol:0-0
Timestamp: 2025-08-27T13:47:28.646Z
Learning: In src/Periphery/Lda/Facets/UniV2StyleFacet.sol and similar LDA facets, mirooon prefers to rely on backend validation for pool addresses rather than adding contract code-size checks in the smart contract, as pool validation occurs during payload generation and transactions would fail anyway if sent to invalid addresses.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1237
File: conventions.md:56-60
Timestamp: 2025-07-03T01:44:43.968Z
Learning: Always consult the conventions.md file for the latest rules and conventions when reviewing PRs or code changes in the lifinance/contracts repository. Make suggestions when code changes do not match the documented conventions in this file.
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1324
File: src/Facets/EcoFacet.sol:1-1
Timestamp: 2025-09-30T12:00:56.667Z
Learning: In the lifinance/contracts repository, audit logging is handled manually by the team, and merging is automatically restricted until an audit has been logged. Missing audit entries in auditLog.json should not be flagged as critical blocking issues during review, as the team has process controls in place to prevent merging without proper audits.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearFacet.sol:4-13
Timestamp: 2025-10-10T10:56:04.861Z
Learning: LibAllowList is only required for facets that make arbitrary external calls to DEX aggregators (e.g., GenericSwapFacetV3). Bridge facets that call specific protocol contracts (like EverclearFacet calling IEverclearFeeAdapter) do not need to import LibAllowList.
Learnt from: ezynda3
Repo: lifinance/contracts PR: 843
File: src/Facets/RelayFacet.sol:165-170
Timestamp: 2024-10-31T09:09:38.568Z
Learning: In the `RelayFacet` contract (`src/Facets/RelayFacet.sol`), within the `_startBridge` function, low-level `call` is intentionally used to transfer tokens so that extra bytes can be added to the calldata, as required for integrating with Relay Protocol.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1456
File: src/Facets/PolymerCCTPFacet.sol:220-224
Timestamp: 2025-11-13T00:53:43.774Z
Learning: In src/Facets/PolymerCCTPFacet.sol, the PolymerCCTPFeeSent event intentionally emits _bridgeData.minAmount (the pre-fee total) as its first parameter rather than the net bridged amount (bridgeAmount after fee deduction), because off-chain logic requires this pre-fee value to pick up deposits.
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1324
File: test/solidity/Facets/EcoFacet.t.sol:135-141
Timestamp: 2025-09-16T07:56:45.093Z
Learning: In EcoFacet test setup, the isNative parameter in swap-and-bridge flows refers to the bridge token type (output), not the swap input type. The ERC20 branch (isNative=false) can still swap from native ETH to ERC20 tokens, requiring msg.value = swapData[0].fromAmount for the ETH input to the swap.
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1324
File: src/Facets/EcoFacet.sol:306-336
Timestamp: 2025-09-25T07:47:30.735Z
Learning: In EcoFacet (src/Facets/EcoFacet.sol), the team intentionally uses variable-length validation for nonEVMReceiver addresses (up to 44 bytes) to support cross-ecosystem bridging with different address formats, rather than enforcing fixed 32-byte raw pubkeys.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1456
File: test/solidity/Facets/PolymerCCTPFacet.t.sol:325-333
Timestamp: 2025-11-13T00:53:25.372Z
Learning: In src/Facets/PolymerCCTPFacet.sol, the PolymerCCTPFeeSent event must emit the original bridgeData.minAmount (before polymer fee deduction) as the first parameter, not the net bridge amount, because off-chain logic requires this value to properly pick up and process the deposit.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1275
File: src/Facets/AllBridgeFacet.sol:175-175
Timestamp: 2025-07-16T01:04:11.083Z
Learning: In AllBridgeFacet.sol, zero fee validation is not required at the contract level because the backend system ensures that calldata and msg.value are properly aligned before transactions reach the contract.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: docs/LDAPeripheryRegistryFacet.md:14-27
Timestamp: 2025-08-29T14:05:25.335Z
Learning: mirooon prefers interface-level documentation to focus on the API contract and function purposes rather than implementation details like access control restrictions or specific modifiers, keeping documentation clean and consumable at the interface level.
📚 Learning: 2025-10-10T10:56:04.861Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearFacet.sol:4-13
Timestamp: 2025-10-10T10:56:04.861Z
Learning: LibAllowList is only required for facets that make arbitrary external calls to DEX aggregators (e.g., GenericSwapFacetV3). Bridge facets that call specific protocol contracts (like EverclearFacet calling IEverclearFeeAdapter) do not need to import LibAllowList.

Applied to files:

  • docs/EverclearFacet.md
  • src/Facets/EverclearFacet.sol
  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-10-02T18:10:09.934Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1406
File: src/Facets/UnitFacet.sol:75-81
Timestamp: 2025-10-02T18:10:09.934Z
Learning: In UnitFacet.sol and similar facet contracts in src/Facets/, the LiFiTransferStarted event emission should ALWAYS be at the end of the _startBridge internal function, after all validations and asset transfers have been completed successfully.

Applied to files:

  • docs/EverclearFacet.md
  • src/Facets/EverclearFacet.sol
  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-10-13T11:13:48.847Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearV2Facet.sol:75-96
Timestamp: 2025-10-13T11:13:48.847Z
Learning: In EverclearV2Facet (and all LiFi facets), the team standard is to use msg.sender as the refund address with the refundExcessNative modifier, not requiring an explicit refund address parameter.

Applied to files:

  • docs/EverclearFacet.md
  • src/Facets/EverclearFacet.sol
  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-11-13T00:53:43.774Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1456
File: src/Facets/PolymerCCTPFacet.sol:220-224
Timestamp: 2025-11-13T00:53:43.774Z
Learning: In src/Facets/PolymerCCTPFacet.sol, the PolymerCCTPFeeSent event intentionally emits _bridgeData.minAmount (the pre-fee total) as its first parameter rather than the net bridged amount (bridgeAmount after fee deduction), because off-chain logic requires this pre-fee value to pick up deposits.

Applied to files:

  • docs/EverclearFacet.md
  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-07-16T01:03:08.106Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1275
File: src/Facets/AllBridgeFacet.sol:164-164
Timestamp: 2025-07-16T01:03:08.106Z
Learning: In src/Facets/AllBridgeFacet.sol, the team has decided that explicit validation for address downcasting from `_bridgeData.sendingAssetId` to `bytes32(uint256(uint160(_bridgeData.sendingAssetId)))` is not required, accepting the potential risk of silent overflow from unsafe downcasting.

Applied to files:

  • docs/EverclearFacet.md
  • src/Facets/EverclearFacet.sol
  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-11-13T00:53:25.372Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1456
File: test/solidity/Facets/PolymerCCTPFacet.t.sol:325-333
Timestamp: 2025-11-13T00:53:25.372Z
Learning: In src/Facets/PolymerCCTPFacet.sol, the PolymerCCTPFeeSent event must emit the original bridgeData.minAmount (before polymer fee deduction) as the first parameter, not the net bridge amount, because off-chain logic requires this value to properly pick up and process the deposit.

Applied to files:

  • docs/EverclearFacet.md
  • src/Facets/EverclearFacet.sol
📚 Learning: 2024-10-31T09:09:38.568Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 843
File: src/Facets/RelayFacet.sol:165-170
Timestamp: 2024-10-31T09:09:38.568Z
Learning: In the `RelayFacet` contract (`src/Facets/RelayFacet.sol`), within the `_startBridge` function, low-level `call` is intentionally used to transfer tokens so that extra bytes can be added to the calldata, as required for integrating with Relay Protocol.

Applied to files:

  • docs/EverclearFacet.md
  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-08-29T11:53:38.549Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: test/solidity/Periphery/LDA/BaseCoreRouteTest.t.sol:379-388
Timestamp: 2025-08-29T11:53:38.549Z
Learning: In test/solidity/Periphery/LDA/BaseCoreRouteTest.t.sol, for the revert-testing helper function _executeAndVerifySwap, only the aggregator branch (CommandType.DistributeSelfERC20) should use amountIn-1 to underfund and trigger insufficient balance errors, while user-funded branches should use the full amountIn to test other error conditions.

Applied to files:

  • docs/EverclearFacet.md
  • src/Facets/EverclearFacet.sol
  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-08-29T10:02:09.041Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1299
File: src/Facets/AcrossFacetPackedV4.sol:118-136
Timestamp: 2025-08-29T10:02:09.041Z
Learning: In AcrossFacetPackedV4.sol, the team explicitly chooses to omit calldata length validation in gas-optimized packed functions like startBridgeTokensViaAcrossV4NativePacked to save gas, accepting the trade-off of potential out-of-bounds reverts for better gas efficiency.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2024-10-14T08:23:38.076Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 831
File: src/Helpers/WithdrawablePeriphery.sol:26-30
Timestamp: 2024-10-14T08:23:38.076Z
Learning: In the `WithdrawablePeriphery.sol` contract, when transferring Ether in the `withdrawToken` function, prefer using `SafeTransferLib.safeTransferETH` instead of low-level `call` for safer Ether transfers.

Applied to files:

  • docs/EverclearFacet.md
  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-06-05T11:25:43.443Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1187
File: .github/workflows/versionControlAndAuditCheck.yml:596-612
Timestamp: 2025-06-05T11:25:43.443Z
Learning: The user mirooon has an internal system for tracking tickets and technical debt. They acknowledged the security concern about disabled commit hash verification in the audit workflow and plan to implement conditional logic to skip verification only for revert PRs in a future update.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-08-27T23:36:40.773Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: test/solidity/Periphery/GasZipPeriphery.t.sol:223-233
Timestamp: 2025-08-27T23:36:40.773Z
Learning: In bridge facet swap flows with requiresDeposit=false, tokens are already held by the diamond contract from previous swaps. When subsequent contracts like GasZipPeriphery call LibAsset.depositAsset, they pull tokens from msg.sender (the diamond) to themselves via transferFrom, requiring no additional approvals since the diamond already owns the tokens.

Applied to files:

  • docs/EverclearFacet.md
  • src/Facets/EverclearFacet.sol
  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-06-13T08:30:26.220Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1207
File: deployments/_deployments_log_file.json:34037-34080
Timestamp: 2025-06-13T08:30:26.220Z
Learning: LiFiDiamond contains generic withdrawal logic, so individual facet contracts (e.g., PioneerFacet) do not need their own Ether-withdraw functions.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-09-16T07:56:45.093Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1324
File: test/solidity/Facets/EcoFacet.t.sol:135-141
Timestamp: 2025-09-16T07:56:45.093Z
Learning: In EcoFacet test setup, the isNative parameter in swap-and-bridge flows refers to the bridge token type (output), not the swap input type. The ERC20 branch (isNative=false) can still swap from native ETH to ERC20 tokens, requiring msg.value = swapData[0].fromAmount for the ETH input to the swap.

Applied to files:

  • docs/EverclearFacet.md
  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-07-16T01:04:11.083Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1275
File: src/Facets/AllBridgeFacet.sol:175-175
Timestamp: 2025-07-16T01:04:11.083Z
Learning: In AllBridgeFacet.sol, zero fee validation is not required at the contract level because the backend system ensures that calldata and msg.value are properly aligned before transactions reach the contract.

Applied to files:

  • docs/EverclearFacet.md
  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-01-22T12:36:12.699Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: test/solidity/Facets/GlacisFacet.t.sol:214-262
Timestamp: 2025-01-22T12:36:12.699Z
Learning: In the LiFi contracts, token pair validation is handled by third-party contracts, and route discovery including liquidity checks are performed off-chain. The contract only receives pre-validated routes, making token pair and liquidity validation tests unnecessary at the contract level.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-07-16T01:04:55.857Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1275
File: src/Facets/AllBridgeFacet.sol:186-188
Timestamp: 2025-07-16T01:04:55.857Z
Learning: In LiFi facet contracts, when public entry point functions have `nonReentrant` modifier protection, internal functions like `_startBridge` that they call benefit from this reentrancy protection, making event emission order after external calls acceptable from a security perspective.

Applied to files:

  • docs/EverclearFacet.md
  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-08-29T11:07:57.743Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/LDA/Facets/CurveFacet.sol:87-91
Timestamp: 2025-08-29T11:07:57.743Z
Learning: In src/Periphery/LDA/Facets/CurveFacet.sol, modern Curve pools (isV2=true, representing V2/NG pools) should reject native tokenIn by adding an early revert check when LibAsset.isNativeAsset(tokenIn) is true, since ICurveV2 exchange functions are non-payable and cannot accept native ETH.

Applied to files:

  • src/Facets/EverclearFacet.sol
  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-09-25T07:47:30.735Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1324
File: src/Facets/EcoFacet.sol:306-336
Timestamp: 2025-09-25T07:47:30.735Z
Learning: In EcoFacet (src/Facets/EcoFacet.sol), the team intentionally uses variable-length validation for nonEVMReceiver addresses (up to 44 bytes) to support cross-ecosystem bridging with different address formats, rather than enforcing fixed 32-byte raw pubkeys.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2024-11-25T09:04:55.880Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: script/deploy/_targetState.json:143-143
Timestamp: 2024-11-25T09:04:55.880Z
Learning: Errors about the missing `OpBNBBridgeFacet` contract are expected when it is referenced in the target state but not yet merged into the main branch.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2024-10-09T03:47:21.269Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: src/Periphery/Permit2Proxy.sol:75-108
Timestamp: 2024-10-09T03:47:21.269Z
Learning: In the `Permit2Proxy` contract (`src/Periphery/Permit2Proxy.sol`), reentrancy protection is not necessary for functions like `callDiamondWithEIP2612Signature` when calling our own trusted diamond contract (`LIFI_DIAMOND`).

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2024-10-10T03:33:59.733Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: test/solidity/Helpers/WithdrawablePeriphery.t.sol:15-21
Timestamp: 2024-10-10T03:33:59.733Z
Learning: In Solidity, events cannot be imported from another contract; they need to be redefined or imported from an interface.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2024-10-10T03:18:20.721Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: test/solidity/Helpers/WithdrawablePeriphery.t.sol:22-35
Timestamp: 2024-10-10T03:18:20.721Z
Learning: In Solidity tests for withdrawal functions in `test/solidity/Helpers/WithdrawablePeriphery.t.sol`, do not suggest adding tests where the withdrawal amount exceeds the contract's balance, as such tests are unnecessary because any contract will fail in that case.

Applied to files:

  • src/Facets/EverclearFacet.sol
  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2024-12-02T06:33:33.309Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 827
File: src/Facets/DeBridgeDlnFacet.sol:0-0
Timestamp: 2024-12-02T06:33:33.309Z
Learning: In Solidity version 0.8.0 and above, arithmetic underflows and overflows automatically cause a revert; therefore, explicit checks for arithmetic underflows are not necessary in functions like `_startBridge` in `DeBridgeDlnFacet.sol`.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2024-10-09T03:47:21.269Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: src/Periphery/GasZipPeriphery.sol:57-62
Timestamp: 2024-10-09T03:47:21.269Z
Learning: In the `GasZipPeriphery` contract, it's acceptable to let low-level calls like `liFiDEXAggregator.call` fail without explicit error handling, as failing the entire transaction is sufficient and saves gas.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-07-17T04:21:26.825Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1266
File: script/deploy/safe/execute-pending-timelock-tx.ts:627-628
Timestamp: 2025-07-17T04:21:26.825Z
Learning: In the lifinance/contracts repository, 0xDEnYO prefers to keep '0x0' as a fallback address in gas estimation calls rather than throwing errors when the wallet account address is not available, prioritizing code simplicity over strict validation.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2024-09-23T02:04:16.323Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: src/Periphery/GasZipPeriphery.sol:49-53
Timestamp: 2024-09-23T02:04:16.323Z
Learning: When `LibAsset.maxApproveERC20` is used with `type(uint256).max`, the team acknowledges and accepts the associated security risks. In future reviews, avoid flagging this as a concern.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-08-29T10:02:15.095Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1299
File: src/Facets/AcrossFacetPackedV4.sol:186-214
Timestamp: 2025-08-29T10:02:15.095Z
Learning: In AcrossFacetPackedV4.sol, calldata length validation is intentionally omitted to prioritize gas optimization over safety checks. The team accepts the risk of potential out-of-bounds reads in favor of lower gas costs for the packed implementation.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2024-10-22T03:14:52.578Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: src/Facets/GasZipFacet.sol:53-53
Timestamp: 2024-10-22T03:14:52.578Z
Learning: In `src/Facets/GasZipFacet.sol`, when checking `msg.value`, the team prefers to use strict equality (`msg.value == _bridgeData.minAmount`) to save gas and avoid refunding excess Ether.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-09-25T07:48:53.243Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1324
File: src/Facets/EcoFacet.sol:280-303
Timestamp: 2025-09-25T07:48:53.243Z
Learning: In src/Facets/EcoFacet.sol, the team prefers to allow natural Solidity reverts (array bounds, insufficient data) in route validation rather than adding explicit guards with custom errors, as the reverts achieve the same security outcome while keeping code simpler.

Applied to files:

  • src/Facets/EverclearFacet.sol
  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-08-27T22:23:51.257Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/NativeWrapperFacet.sol:0-0
Timestamp: 2025-08-27T22:23:51.257Z
Learning: In src/Periphery/Lda/Facets/NativeWrapperFacet.sol, the wrapNative function should not validate msg.value == amountIn because CoreRouteFacet's DistributeNative command (command type 3) overrides the amountIn parameter with address(this).balance, making such validation incorrect and causing false failures.

Applied to files:

  • src/Facets/EverclearFacet.sol
  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-08-27T13:51:52.704Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/NativeWrapperFacet.sol:33-0
Timestamp: 2025-08-27T13:51:52.704Z
Learning: In LDA facets like NativeWrapperFacet, mirooon prefers to rely on CoreRouteFacet's upstream validation for parameters like `from` rather than adding defensive validation checks in individual facets, since CoreRouteFacet ensures only valid values (msg.sender, address(this), or INTERNAL_INPUT_SOURCE) are passed to the facets.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-08-27T13:47:28.646Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/UniV2StyleFacet.sol:0-0
Timestamp: 2025-08-27T13:47:28.646Z
Learning: In src/Periphery/Lda/Facets/UniV2StyleFacet.sol and similar LDA facets, mirooon prefers to rely on backend validation for pool addresses rather than adding contract code-size checks in the smart contract, as pool validation occurs during payload generation and transactions would fail anyway if sent to invalid addresses.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2024-10-09T03:47:21.269Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: src/Periphery/GasZipPeriphery.sol:4-14
Timestamp: 2024-10-09T03:47:21.269Z
Learning: In `GasZipPeriphery.sol`, `LibUtil` and `Validatable` are used, so ensure not to suggest their removal in future reviews.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-10-02T18:14:51.385Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1406
File: src/Facets/UnitFacet.sol:1-2
Timestamp: 2025-10-02T18:14:51.385Z
Learning: For facet contracts in src/Facets/, the SPDX license identifier should be immediately followed by the pragma statement without a blank line in between, as confirmed by mirooon for src/Facets/UnitFacet.sol.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-08-29T11:18:56.656Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/LDA/Facets/NativeWrapperFacet.sol:1-2
Timestamp: 2025-08-29T11:18:56.656Z
Learning: For src/Periphery/LDA/Facets/NativeWrapperFacet.sol, the SPDX license identifier should be immediately followed by the pragma statement without a blank line in between, as confirmed by mirooon.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-08-27T23:01:41.042Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Libraries/LibUniV3Logic.sol:4-5
Timestamp: 2025-08-27T23:01:41.042Z
Learning: In the lifinance/contracts repository, the pattern `import { IERC20, SafeERC20 } from "openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";` is correctly used throughout the codebase and works as expected. SafeERC20.sol re-exports IERC20 in modern OpenZeppelin versions, making this combined import valid. Do not suggest splitting these imports.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-08-27T13:07:58.254Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/CurveFacet.sol:0-0
Timestamp: 2025-08-27T13:07:58.254Z
Learning: In the LiFi contracts codebase, ICurveLegacy interface is defined inline in src/Periphery/LiFiDEXAggregator.sol with a non-payable exchange function. The CurveFacet diff shows importing it from a separate file that doesn't exist, creating a compilation issue.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-08-19T05:07:19.448Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1303
File: script/deploy/tron/utils.ts:3-5
Timestamp: 2025-08-19T05:07:19.448Z
Learning: In the lifinance/contracts repository, consola and TronWeb should be imported as named exports: `import { consola } from 'consola'` and `import { TronWeb } from 'tronweb'`. Do not flag these as incorrect default export usage. Both libraries provide named exports, not default exports.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-08-19T05:07:19.448Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1303
File: script/deploy/tron/utils.ts:3-5
Timestamp: 2025-08-19T05:07:19.448Z
Learning: In the lifinance/contracts repository, consola and TronWeb should be imported as named exports: `import { consola } from 'consola'` and `import { TronWeb } from 'tronweb'`. Do not flag these as incorrect default export usage.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2024-11-25T09:05:03.917Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: script/deploy/_targetState.json:49-49
Timestamp: 2024-11-25T09:05:03.917Z
Learning: The `RelayFacet` contract, when missing from the source code but referenced in deployment configurations, should be treated the same way as `OpBNBBridgeFacet` and can be ignored in code reviews.

Applied to files:

  • src/Facets/EverclearFacet.sol
📚 Learning: 2025-07-11T09:43:22.393Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1193
File: test/solidity/Facets/AllowListMigratorFacet.t.sol:39-52
Timestamp: 2025-07-11T09:43:22.393Z
Learning: For fork-based tests like AllowListMigratorFacet.t.sol that work with existing deployed contracts (mainnet diamond), initTestBase() is intentionally omitted since the standard test initialization is not needed.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-01-22T12:36:12.699Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: test/solidity/Facets/GlacisFacet.t.sol:214-262
Timestamp: 2025-01-22T12:36:12.699Z
Learning: The GlacisFacet test suite inherits from TestBaseFacet which already covers various failure scenarios including invalid receiver address, invalid amounts, same chain bridging, and insufficient funds, making additional failure scenario tests redundant.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-01-28T11:29:09.566Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: test/solidity/Facets/GlacisFacet.t.sol:0-0
Timestamp: 2025-01-28T11:29:09.566Z
Learning: Empty test methods with explanatory comments are acceptable in test classes when the feature being tested (e.g., native token bridging) is not supported by the implementation.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-08-28T02:41:07.505Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1321
File: docs/RelayDepositoryFacet.md:9-10
Timestamp: 2025-08-28T02:41:07.505Z
Learning: Unit tests for RelayDepositoryFacet cannot verify fund forwarding behavior after deposits because the facet delegates to external IRelayDepository contracts. The forwarding logic is implemented in the Relay Protocol V2 Depository contracts, not in the facet itself.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-02-21T09:05:22.118Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 984
File: test/solidity/Facets/ChainflipFacet.t.sol:269-269
Timestamp: 2025-02-21T09:05:22.118Z
Learning: Fixed gas amounts in test files (e.g., ChainflipFacet.t.sol) don't require extensive documentation or configuration as they are only used for testing purposes.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2024-10-31T09:10:16.115Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 843
File: test/solidity/Facets/RelayFacet.t.sol:0-0
Timestamp: 2024-10-31T09:10:16.115Z
Learning: In the `signData` function within `RelayFacetTest` in `test/solidity/Facets/RelayFacet.t.sol`, the use of the EIP-712 standard for hashing and signing is not required.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2024-10-22T03:16:28.754Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: test/solidity/Facets/GasZipFacet.t.sol:212-213
Timestamp: 2024-10-22T03:16:28.754Z
Learning: In the `GasZipFacetTest`, for the test case `testBase_Revert_SwapAndBridgeWithInvalidSwapData()`, a generic revert is expected, so `vm.expectRevert();` without specifying the expected error is appropriate.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2024-10-22T03:24:24.705Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: test/solidity/Facets/GasZipFacet.t.sol:337-339
Timestamp: 2024-10-22T03:24:24.705Z
Learning: In `GasZipFacet` tests, when expecting a failure due to insufficient balance for sending value, the test should expect a generic revert without specifying a specific error.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
🪛 LanguageTool
docs/EverclearFacet.md

[grammar] ~86-~86: Use a hyphen to join words.
Context: ...ameter. Swapping is performed by a swap specific library that expects an array o...

(QB_NEW_EN_HYPHEN)

🪛 markdownlint-cli2 (0.18.1)
docs/EverclearFacet.md

88-88: Link text should be descriptive

(MD059, descriptive-link-text)


94-94: Link text should be descriptive

(MD059, descriptive-link-text)


125-125: Link text should be descriptive

(MD059, descriptive-link-text)

🔇 Additional comments (3)
src/Facets/EverclearFacet.sol (1)

64-71: Fee adapter wiring and _startBridge flow look consistent and safe.

  • Constructor properly validates _feeAdapter and stores an immutable FEE_ADAPTER.

  • The _startBridge guard

    if (
        _everclearData.outputAsset == bytes32(0) ||
        _bridgeData.minAmount < _everclearData.fee
    ) revert InvalidCallData();

    cleanly prevents minAmount - fee underflow and ensures a valid output asset before approving and calling the adapter.

  • Both non‑EVM and EVM branches compute the bridged amount as _bridgeData.minAmount - _everclearData.fee, pass the fee via FeeParams, and only emit LiFiTransferStarted(_bridgeData) after the external newIntent call, which matches the facet conventions and the earlier review feedback.

Overall the core Everclear bridging logic looks sound and aligned with the existing LiFi facet patterns.

Also applies to: 128-145, 161-176, 198-212

test/solidity/Facets/EverclearFacet.t.sol (2)

57-67: Fee-signing helper and payload in tests look correct and consistent.

  • toEthSignedMessageHash faithfully reproduces the standard EIP‑191 "\x19Ethereum Signed Message:\n32" prefixing and hashing, matching OpenZeppelin’s implementation.

  • The tests construct signatures over abi.encode(fee, nativeFee, bridgeData.sendingAssetId, deadline) and then wrap with toEthSignedMessageHash, which aligns with the inline comment:

    // The FeeAdapter signs: abi.encode(_tokenFee, _nativeFee, _inputAsset, _deadline)

This is a solid, explicit specification of the expected signing scheme and provides a good ground truth for aligning the documentation (see separate docs comment).

Also applies to: 118-131


580-641: Native-fee scenarios are well covered; behavior matches refundExcessNative expectations.

The tests around skip_test_CanBridgeTokensWithNativeFee, test_CanSwapAndBridgeTokensWithNativeFee, and test_ExcessNativeFeeGetsRefunded thoroughly exercise:

  • Correct signature construction when nativeFee > 0.
  • Successful flows when the exact native fee is provided.
  • Swap+bridge with native fee via a dedicated facet instance and Uniswap path.
  • Excess native fee being refunded so that balanceBefore - balanceAfter == nativeFee.

This gives good confidence that the interaction between Everclear’s nativeFee, the fee adapter, and the refundExcessNative modifier is implemented correctly in the facet.

Also applies to: 642-717, 842-885

Copy link
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: 1

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

708-759: Consider using the diamond instance consistently.

All native fee tests create new standalone TestEverclearFacet instances instead of using the diamond instance that's set up in setUp(). This differs from the base tests which use the diamond instance (e.g., everclearFacet at line 268).

While standalone facets may be intentional for testing specific scenarios, this inconsistency could mask integration issues that would only surface when the facet is deployed through the diamond proxy.

Consider whether native fee scenarios should also be tested through the diamond instance to ensure consistent behavior with the actual deployment pattern.

Also applies to: 785-859, 861-906, 908-951, 953-994

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 02661a7 and 2364e1d.

📒 Files selected for processing (1)
  • test/solidity/Facets/EverclearFacet.t.sol (1 hunks)
🧰 Additional context used
🧠 Learnings (19)
📓 Common learnings
Learnt from: mirooon
Repo: lifinance/contracts PR: 1283
File: deployments/ronin.diamond.json:65-68
Timestamp: 2025-08-07T10:20:01.383Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, carefully verify that target state configuration files (like script/deploy/_targetState.json) and deployment log files have been updated before flagging missing entries. The AI summary section should be consulted to understand all file changes, as manual searches might miss entries due to formatting differences or search limitations.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1256
File: deployments/zksync.diamond.json:81-87
Timestamp: 2025-07-04T08:59:08.108Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, carefully verify that target state configuration files (like script/deploy/_targetState.json) have been updated before flagging missing entries. The AI summary section should be consulted to understand all file changes, as manual searches might miss entries due to formatting differences or search limitations.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/UniV2StyleFacet.sol:0-0
Timestamp: 2025-08-27T13:47:28.646Z
Learning: In src/Periphery/Lda/Facets/UniV2StyleFacet.sol and similar LDA facets, mirooon prefers to rely on backend validation for pool addresses rather than adding contract code-size checks in the smart contract, as pool validation occurs during payload generation and transactions would fail anyway if sent to invalid addresses.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: src/Periphery/GasZipPeriphery.sol:49-53
Timestamp: 2024-09-23T02:04:16.323Z
Learning: When `LibAsset.maxApproveERC20` is used with `type(uint256).max`, the team acknowledges and accepts the associated security risks. In future reviews, avoid flagging this as a concern.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearFacet.sol:4-13
Timestamp: 2025-10-10T10:56:04.861Z
Learning: LibAllowList is only required for facets that make arbitrary external calls to DEX aggregators (e.g., GenericSwapFacetV3). Bridge facets that call specific protocol contracts (like EverclearFacet calling IEverclearFeeAdapter) do not need to import LibAllowList.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: docs/LDAPeripheryRegistryFacet.md:14-27
Timestamp: 2025-08-29T14:05:25.335Z
Learning: mirooon prefers interface-level documentation to focus on the API contract and function purposes rather than implementation details like access control restrictions or specific modifiers, keeping documentation clean and consumable at the interface level.
📚 Learning: 2025-07-11T09:43:22.393Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1193
File: test/solidity/Facets/AllowListMigratorFacet.t.sol:39-52
Timestamp: 2025-07-11T09:43:22.393Z
Learning: For fork-based tests like AllowListMigratorFacet.t.sol that work with existing deployed contracts (mainnet diamond), initTestBase() is intentionally omitted since the standard test initialization is not needed.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-01-22T12:36:12.699Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: test/solidity/Facets/GlacisFacet.t.sol:214-262
Timestamp: 2025-01-22T12:36:12.699Z
Learning: The GlacisFacet test suite inherits from TestBaseFacet which already covers various failure scenarios including invalid receiver address, invalid amounts, same chain bridging, and insufficient funds, making additional failure scenario tests redundant.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-01-28T11:29:09.566Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: test/solidity/Facets/GlacisFacet.t.sol:0-0
Timestamp: 2025-01-28T11:29:09.566Z
Learning: Empty test methods with explanatory comments are acceptable in test classes when the feature being tested (e.g., native token bridging) is not supported by the implementation.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-08-29T11:07:57.743Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/LDA/Facets/CurveFacet.sol:87-91
Timestamp: 2025-08-29T11:07:57.743Z
Learning: In src/Periphery/LDA/Facets/CurveFacet.sol, modern Curve pools (isV2=true, representing V2/NG pools) should reject native tokenIn by adding an early revert check when LibAsset.isNativeAsset(tokenIn) is true, since ICurveV2 exchange functions are non-payable and cannot accept native ETH.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2024-10-10T03:18:20.721Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: test/solidity/Helpers/WithdrawablePeriphery.t.sol:22-35
Timestamp: 2024-10-10T03:18:20.721Z
Learning: In Solidity tests for withdrawal functions in `test/solidity/Helpers/WithdrawablePeriphery.t.sol`, do not suggest adding tests where the withdrawal amount exceeds the contract's balance, as such tests are unnecessary because any contract will fail in that case.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-07-16T01:03:08.106Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1275
File: src/Facets/AllBridgeFacet.sol:164-164
Timestamp: 2025-07-16T01:03:08.106Z
Learning: In src/Facets/AllBridgeFacet.sol, the team has decided that explicit validation for address downcasting from `_bridgeData.sendingAssetId` to `bytes32(uint256(uint160(_bridgeData.sendingAssetId)))` is not required, accepting the potential risk of silent overflow from unsafe downcasting.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-02-21T09:05:22.118Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 984
File: test/solidity/Facets/ChainflipFacet.t.sol:269-269
Timestamp: 2025-02-21T09:05:22.118Z
Learning: Fixed gas amounts in test files (e.g., ChainflipFacet.t.sol) don't require extensive documentation or configuration as they are only used for testing purposes.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-10-10T10:56:04.861Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearFacet.sol:4-13
Timestamp: 2025-10-10T10:56:04.861Z
Learning: LibAllowList is only required for facets that make arbitrary external calls to DEX aggregators (e.g., GenericSwapFacetV3). Bridge facets that call specific protocol contracts (like EverclearFacet calling IEverclearFeeAdapter) do not need to import LibAllowList.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-08-28T02:41:07.505Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1321
File: docs/RelayDepositoryFacet.md:9-10
Timestamp: 2025-08-28T02:41:07.505Z
Learning: Unit tests for RelayDepositoryFacet cannot verify fund forwarding behavior after deposits because the facet delegates to external IRelayDepository contracts. The forwarding logic is implemented in the Relay Protocol V2 Depository contracts, not in the facet itself.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-10-02T18:10:09.934Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1406
File: src/Facets/UnitFacet.sol:75-81
Timestamp: 2025-10-02T18:10:09.934Z
Learning: In UnitFacet.sol and similar facet contracts in src/Facets/, the LiFiTransferStarted event emission should ALWAYS be at the end of the _startBridge internal function, after all validations and asset transfers have been completed successfully.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-09-16T07:56:45.093Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1324
File: test/solidity/Facets/EcoFacet.t.sol:135-141
Timestamp: 2025-09-16T07:56:45.093Z
Learning: In EcoFacet test setup, the isNative parameter in swap-and-bridge flows refers to the bridge token type (output), not the swap input type. The ERC20 branch (isNative=false) can still swap from native ETH to ERC20 tokens, requiring msg.value = swapData[0].fromAmount for the ETH input to the swap.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-08-27T23:36:40.773Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: test/solidity/Periphery/GasZipPeriphery.t.sol:223-233
Timestamp: 2025-08-27T23:36:40.773Z
Learning: In bridge facet swap flows with requiresDeposit=false, tokens are already held by the diamond contract from previous swaps. When subsequent contracts like GasZipPeriphery call LibAsset.depositAsset, they pull tokens from msg.sender (the diamond) to themselves via transferFrom, requiring no additional approvals since the diamond already owns the tokens.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-08-27T22:23:51.257Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/NativeWrapperFacet.sol:0-0
Timestamp: 2025-08-27T22:23:51.257Z
Learning: In src/Periphery/Lda/Facets/NativeWrapperFacet.sol, the wrapNative function should not validate msg.value == amountIn because CoreRouteFacet's DistributeNative command (command type 3) overrides the amountIn parameter with address(this).balance, making such validation incorrect and causing false failures.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-07-16T01:04:11.083Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1275
File: src/Facets/AllBridgeFacet.sol:175-175
Timestamp: 2025-07-16T01:04:11.083Z
Learning: In AllBridgeFacet.sol, zero fee validation is not required at the contract level because the backend system ensures that calldata and msg.value are properly aligned before transactions reach the contract.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2024-10-22T03:16:28.754Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: test/solidity/Facets/GasZipFacet.t.sol:212-213
Timestamp: 2024-10-22T03:16:28.754Z
Learning: In the `GasZipFacetTest`, for the test case `testBase_Revert_SwapAndBridgeWithInvalidSwapData()`, a generic revert is expected, so `vm.expectRevert();` without specifying the expected error is appropriate.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-10-13T11:13:48.847Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearV2Facet.sol:75-96
Timestamp: 2025-10-13T11:13:48.847Z
Learning: In EverclearV2Facet (and all LiFi facets), the team standard is to use msg.sender as the refund address with the refundExcessNative modifier, not requiring an explicit refund address parameter.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2025-08-29T11:53:38.549Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: test/solidity/Periphery/LDA/BaseCoreRouteTest.t.sol:379-388
Timestamp: 2025-08-29T11:53:38.549Z
Learning: In test/solidity/Periphery/LDA/BaseCoreRouteTest.t.sol, for the revert-testing helper function _executeAndVerifySwap, only the aggregator branch (CommandType.DistributeSelfERC20) should use amountIn-1 to underfund and trigger insufficient balance errors, while user-funded branches should use the full amountIn to test other error conditions.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
📚 Learning: 2024-10-22T03:24:24.705Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: test/solidity/Facets/GasZipFacet.t.sol:337-339
Timestamp: 2024-10-22T03:24:24.705Z
Learning: In `GasZipFacet` tests, when expecting a failure due to insufficient balance for sending value, the test should expect a generic revert without specifying a specific error.

Applied to files:

  • test/solidity/Facets/EverclearFacet.t.sol
🔇 Additional comments (7)
test/solidity/Facets/EverclearFacet.t.sol (7)

57-117: LGTM: Signature creation helpers are well-implemented.

The toEthSignedMessageHash and createEverclearV2Signature functions correctly implement the EIP-191 signing standard and match the expected V2 FeeAdapter signature format with proper encoding of all parameters.


119-202: LGTM: Comprehensive test setup.

The setUp() function properly initializes the test environment including facet deployment to diamond, allowlist configuration, signer setup, and creation of valid test data with V2 signatures.


204-342: LGTM: Base tests are well-structured.

The test implementations properly verify:

  • Swap and bridge flows with event emission
  • Balance changes with precise assertions
  • Non-EVM chain bridging with correct event parameters
  • Fuzz testing with appropriate bounds

The empty native token tests are acceptable since the facet doesn't support native assets.


373-622: LGTM: Comprehensive revert test coverage.

The revert tests thoroughly validate error conditions including:

  • Invalid output asset and receiver address validation
  • EVM vs non-EVM receiver mismatches
  • Native asset rejection (as expected for this facet)
  • Constructor validation

All error paths are properly tested with appropriate expectRevert assertions.


638-706: Clarify why this test is skipped.

The skip_test_CanBridgeTokensWithNativeFee test is fully implemented and uses the correct V2 signature format (matching the base tests), but has the skip_ prefix. If this test passes with V2 signatures while the other native fee tests use simplified signatures, it suggests the other tests may have incorrect signature formats.

Please clarify:

  1. Why is this test skipped if it appears to be correctly implemented?
  2. Should the other native fee tests (lines 708, 785, 861, 908, 953) use the same V2 signature format as this test?

908-951: LGTM: Refund mechanism properly tested.

The test_ExcessNativeFeeGetsRefunded test correctly verifies that excess native fees are refunded to msg.sender, checking the exact balance difference before and after the transaction. This aligns with the expected refundExcessNative modifier behavior.


996-1026: LGTM: Unsupported chain validation tested.

The test properly validates that the facet reverts with UnsupportedEverclearChainId when attempting to bridge to TRON, a non-EVM chain not supported by Everclear.

Copy link
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: 0

♻️ Duplicate comments (1)
docs/EverclearFacet.md (1)

20-21: Fix function signature formatting (recurring issue).

The function signature still has the issues from the previous review:

  • Missing function keyword
  • Type name uses incorrect casing: everclearData should be EverclearData
  • Parameter qualifier should be calldata, not memory

Despite approval, the fix does not appear to have been applied. Apply this correction:

-- `swapAndStartBridgeTokensViaEverclear(BridgeData memory _bridgeData, LibSwap.SwapData[] calldata _swapData, everclearData memory _everclearData)`
+- `function swapAndStartBridgeTokensViaEverclear(BridgeData memory _bridgeData, LibSwap.SwapData[] calldata _swapData, EverclearData calldata _everclearData)`
🧹 Nitpick comments (4)
docs/EverclearFacet.md (4)

84-84: Hyphenate compound adjective for clarity.

Use swap-specific (with hyphen) to properly form the compound adjective:

-Swapping is performed by a swap specific library that expects an array of calldata to can be run on various DEXs (i.e. Uniswap) to make one or multiple swaps before performing another action.
+Swapping is performed by a swap-specific library that expects an array of calldata to can be run on various DEXs (i.e. Uniswap) to make one or multiple swaps before performing another action.

86-86: Use descriptive link text instead of generic "[here]".

Replace the generic link label with descriptive text:

-The swap library can be found [here](../src/Libraries/LibSwap.sol).
+The swap library can be found [here in LibSwap](../src/Libraries/LibSwap.sol).

92-92: Use descriptive link text instead of generic "[here]".

Replace the generic link label with descriptive text:

-This parameter is strictly for analytics purposes. It's used to emit events that we can later track and index in our subgraphs and provide data on how our contracts are being used. `BridgeData` and the events we can emit can be found [here](../src/Interfaces/ILiFi.sol).
+This parameter is strictly for analytics purposes. It's used to emit events that we can later track and index in our subgraphs and provide data on how our contracts are being used. `BridgeData` and the events we can emit can be found [in ILiFi.sol](../src/Interfaces/ILiFi.sol).

123-123: Use descriptive link text instead of generic "[here]".

Replace the generic link label with descriptive text:

-A detailed explanation on how to use the /quote endpoint and how to trigger the transaction can be found [here](https://docs.li.fi/products/more-integration-options/li.fi-api/transferring-tokens-example).
+A detailed explanation on how to use the /quote endpoint and how to trigger the transaction can be found [in the LiFi API documentation](https://docs.li.fi/products/more-integration-options/li.fi-api/transferring-tokens-example).
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7c9a130 and 3e3a7c0.

📒 Files selected for processing (1)
  • docs/EverclearFacet.md (1 hunks)
🧰 Additional context used
🧠 Learnings (22)
📓 Common learnings
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/UniV2StyleFacet.sol:0-0
Timestamp: 2025-08-27T13:47:28.646Z
Learning: In src/Periphery/Lda/Facets/UniV2StyleFacet.sol and similar LDA facets, mirooon prefers to rely on backend validation for pool addresses rather than adding contract code-size checks in the smart contract, as pool validation occurs during payload generation and transactions would fail anyway if sent to invalid addresses.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1283
File: deployments/ronin.diamond.json:65-68
Timestamp: 2025-08-07T10:20:01.383Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, carefully verify that target state configuration files (like script/deploy/_targetState.json) and deployment log files have been updated before flagging missing entries. The AI summary section should be consulted to understand all file changes, as manual searches might miss entries due to formatting differences or search limitations.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1256
File: deployments/zksync.diamond.json:81-87
Timestamp: 2025-07-04T08:59:08.108Z
Learning: When analyzing deployment PRs in the lifinance/contracts repository, carefully verify that target state configuration files (like script/deploy/_targetState.json) have been updated before flagging missing entries. The AI summary section should be consulted to understand all file changes, as manual searches might miss entries due to formatting differences or search limitations.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearV2Facet.sol:75-96
Timestamp: 2025-10-13T11:13:48.847Z
Learning: In EverclearV2Facet (and all LiFi facets), the team standard is to use msg.sender as the refund address with the refundExcessNative modifier, not requiring an explicit refund address parameter.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: src/Periphery/GasZipPeriphery.sol:49-53
Timestamp: 2024-09-23T02:04:16.323Z
Learning: When `LibAsset.maxApproveERC20` is used with `type(uint256).max`, the team acknowledges and accepts the associated security risks. In future reviews, avoid flagging this as a concern.
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: script/deploy/_targetState.json:49-49
Timestamp: 2024-11-25T09:05:03.917Z
Learning: The `RelayFacet` contract, when missing from the source code but referenced in deployment configurations, should be treated the same way as `OpBNBBridgeFacet` and can be ignored in code reviews.
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: docs/LDAPeripheryRegistryFacet.md:14-27
Timestamp: 2025-08-29T14:05:25.335Z
Learning: mirooon prefers interface-level documentation to focus on the API contract and function purposes rather than implementation details like access control restrictions or specific modifiers, keeping documentation clean and consumable at the interface level.
📚 Learning: 2025-10-10T10:56:04.861Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearFacet.sol:4-13
Timestamp: 2025-10-10T10:56:04.861Z
Learning: LibAllowList is only required for facets that make arbitrary external calls to DEX aggregators (e.g., GenericSwapFacetV3). Bridge facets that call specific protocol contracts (like EverclearFacet calling IEverclearFeeAdapter) do not need to import LibAllowList.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-10-13T11:13:48.847Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1413
File: src/Facets/EverclearV2Facet.sol:75-96
Timestamp: 2025-10-13T11:13:48.847Z
Learning: In EverclearV2Facet (and all LiFi facets), the team standard is to use msg.sender as the refund address with the refundExcessNative modifier, not requiring an explicit refund address parameter.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-10-02T18:10:09.934Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1406
File: src/Facets/UnitFacet.sol:75-81
Timestamp: 2025-10-02T18:10:09.934Z
Learning: In UnitFacet.sol and similar facet contracts in src/Facets/, the LiFiTransferStarted event emission should ALWAYS be at the end of the _startBridge internal function, after all validations and asset transfers have been completed successfully.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-11-13T00:53:43.774Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1456
File: src/Facets/PolymerCCTPFacet.sol:220-224
Timestamp: 2025-11-13T00:53:43.774Z
Learning: In src/Facets/PolymerCCTPFacet.sol, the PolymerCCTPFeeSent event intentionally emits _bridgeData.minAmount (the pre-fee total) as its first parameter rather than the net bridged amount (bridgeAmount after fee deduction), because off-chain logic requires this pre-fee value to pick up deposits.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2024-10-31T09:09:38.568Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 843
File: src/Facets/RelayFacet.sol:165-170
Timestamp: 2024-10-31T09:09:38.568Z
Learning: In the `RelayFacet` contract (`src/Facets/RelayFacet.sol`), within the `_startBridge` function, low-level `call` is intentionally used to transfer tokens so that extra bytes can be added to the calldata, as required for integrating with Relay Protocol.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-08-29T11:53:38.549Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: test/solidity/Periphery/LDA/BaseCoreRouteTest.t.sol:379-388
Timestamp: 2025-08-29T11:53:38.549Z
Learning: In test/solidity/Periphery/LDA/BaseCoreRouteTest.t.sol, for the revert-testing helper function _executeAndVerifySwap, only the aggregator branch (CommandType.DistributeSelfERC20) should use amountIn-1 to underfund and trigger insufficient balance errors, while user-funded branches should use the full amountIn to test other error conditions.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-11-13T00:53:25.372Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1456
File: test/solidity/Facets/PolymerCCTPFacet.t.sol:325-333
Timestamp: 2025-11-13T00:53:25.372Z
Learning: In src/Facets/PolymerCCTPFacet.sol, the PolymerCCTPFeeSent event must emit the original bridgeData.minAmount (before polymer fee deduction) as the first parameter, not the net bridge amount, because off-chain logic requires this value to properly pick up and process the deposit.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-08-29T10:02:09.041Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1299
File: src/Facets/AcrossFacetPackedV4.sol:118-136
Timestamp: 2025-08-29T10:02:09.041Z
Learning: In AcrossFacetPackedV4.sol, the team explicitly chooses to omit calldata length validation in gas-optimized packed functions like startBridgeTokensViaAcrossV4NativePacked to save gas, accepting the trade-off of potential out-of-bounds reverts for better gas efficiency.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2024-10-14T08:23:38.076Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 831
File: src/Helpers/WithdrawablePeriphery.sol:26-30
Timestamp: 2024-10-14T08:23:38.076Z
Learning: In the `WithdrawablePeriphery.sol` contract, when transferring Ether in the `withdrawToken` function, prefer using `SafeTransferLib.safeTransferETH` instead of low-level `call` for safer Ether transfers.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-07-16T01:03:08.106Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1275
File: src/Facets/AllBridgeFacet.sol:164-164
Timestamp: 2025-07-16T01:03:08.106Z
Learning: In src/Facets/AllBridgeFacet.sol, the team has decided that explicit validation for address downcasting from `_bridgeData.sendingAssetId` to `bytes32(uint256(uint160(_bridgeData.sendingAssetId)))` is not required, accepting the potential risk of silent overflow from unsafe downcasting.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-06-05T11:25:43.443Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1187
File: .github/workflows/versionControlAndAuditCheck.yml:596-612
Timestamp: 2025-06-05T11:25:43.443Z
Learning: The user mirooon has an internal system for tracking tickets and technical debt. They acknowledged the security concern about disabled commit hash verification in the audit workflow and plan to implement conditional logic to skip verification only for revert PRs in a future update.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2024-10-31T09:10:16.115Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 843
File: test/solidity/Facets/RelayFacet.t.sol:0-0
Timestamp: 2024-10-31T09:10:16.115Z
Learning: In the `signData` function within `RelayFacetTest` in `test/solidity/Facets/RelayFacet.t.sol`, the use of the EIP-712 standard for hashing and signing is not required.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-09-19T14:10:55.064Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1324
File: src/Facets/EcoFacet.sol:68-71
Timestamp: 2025-09-19T14:10:55.064Z
Learning: In src/Facets/EcoFacet.sol, the team prefers to use msg.sender as the refund address for native tokens in the refundExcessNative modifier, contrary to the general guideline of requiring explicit refund parameters.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-08-27T22:23:51.257Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/NativeWrapperFacet.sol:0-0
Timestamp: 2025-08-27T22:23:51.257Z
Learning: In src/Periphery/Lda/Facets/NativeWrapperFacet.sol, the wrapNative function should not validate msg.value == amountIn because CoreRouteFacet's DistributeNative command (command type 3) overrides the amountIn parameter with address(this).balance, making such validation incorrect and causing false failures.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-08-29T11:07:57.743Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/LDA/Facets/CurveFacet.sol:87-91
Timestamp: 2025-08-29T11:07:57.743Z
Learning: In src/Periphery/LDA/Facets/CurveFacet.sol, modern Curve pools (isV2=true, representing V2/NG pools) should reject native tokenIn by adding an early revert check when LibAsset.isNativeAsset(tokenIn) is true, since ICurveV2 exchange functions are non-payable and cannot accept native ETH.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-08-27T23:36:40.773Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: test/solidity/Periphery/GasZipPeriphery.t.sol:223-233
Timestamp: 2025-08-27T23:36:40.773Z
Learning: In bridge facet swap flows with requiresDeposit=false, tokens are already held by the diamond contract from previous swaps. When subsequent contracts like GasZipPeriphery call LibAsset.depositAsset, they pull tokens from msg.sender (the diamond) to themselves via transferFrom, requiring no additional approvals since the diamond already owns the tokens.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-06-13T08:30:26.220Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1207
File: deployments/_deployments_log_file.json:34037-34080
Timestamp: 2025-06-13T08:30:26.220Z
Learning: LiFiDiamond contains generic withdrawal logic, so individual facet contracts (e.g., PioneerFacet) do not need their own Ether-withdraw functions.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-09-16T07:56:45.093Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1324
File: test/solidity/Facets/EcoFacet.t.sol:135-141
Timestamp: 2025-09-16T07:56:45.093Z
Learning: In EcoFacet test setup, the isNative parameter in swap-and-bridge flows refers to the bridge token type (output), not the swap input type. The ERC20 branch (isNative=false) can still swap from native ETH to ERC20 tokens, requiring msg.value = swapData[0].fromAmount for the ETH input to the swap.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-01-22T12:36:12.699Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: test/solidity/Facets/GlacisFacet.t.sol:214-262
Timestamp: 2025-01-22T12:36:12.699Z
Learning: In the LiFi contracts, token pair validation is handled by third-party contracts, and route discovery including liquidity checks are performed off-chain. The contract only receives pre-validated routes, making token pair and liquidity validation tests unnecessary at the contract level.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-07-16T01:04:11.083Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1275
File: src/Facets/AllBridgeFacet.sol:175-175
Timestamp: 2025-07-16T01:04:11.083Z
Learning: In AllBridgeFacet.sol, zero fee validation is not required at the contract level because the backend system ensures that calldata and msg.value are properly aligned before transactions reach the contract.

Applied to files:

  • docs/EverclearFacet.md
📚 Learning: 2025-07-16T01:04:55.857Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1275
File: src/Facets/AllBridgeFacet.sol:186-188
Timestamp: 2025-07-16T01:04:55.857Z
Learning: In LiFi facet contracts, when public entry point functions have `nonReentrant` modifier protection, internal functions like `_startBridge` that they call benefit from this reentrancy protection, making event emission order after external calls acceptable from a security perspective.

Applied to files:

  • docs/EverclearFacet.md
🪛 LanguageTool
docs/EverclearFacet.md

[grammar] ~84-~84: Use a hyphen to join words.
Context: ...ameter. Swapping is performed by a swap specific library that expects an array o...

(QB_NEW_EN_HYPHEN)

🪛 markdownlint-cli2 (0.18.1)
docs/EverclearFacet.md

86-86: Link text should be descriptive

(MD059, descriptive-link-text)


92-92: Link text should be descriptive

(MD059, descriptive-link-text)


123-123: Link text should be descriptive

(MD059, descriptive-link-text)

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.

5 participants