Skip to content

Add AcrossV4SwapFacet for Across Protocol swap-and-bridge integration [GenericErrors v1.0.3, AcrossV4SwapFacet v1.0.0, IAcrossSpokePoolV4 v1.0.1, ISpokePoolPeriphery v1.0.0, ISponsoredCCTPSrcPeriphery v1.0.0, ISponsoredOFTSrcPeriphery v1.0.0]#1550

Open
ezynda3 wants to merge 70 commits intomainfrom
implement-across-swap-facet

Conversation

@ezynda3
Copy link
Contributor

@ezynda3 ezynda3 commented Dec 22, 2025

Which Jira task belongs to this PR?

N/A - Implementation based on technical planning in scratch/across-plan.md

Why did I implement it this way?

This PR implements AcrossV4SwapFacet, a new bridge facet that integrates with Across Protocol's SpokePoolPeriphery contract to enable swap-and-bridge functionality via the Across Swap API.

Key Architecture Decision

Unlike the existing AcrossFacetV4 (which calls SpokePool directly), this facet uses the SpokePoolPeriphery contract:

  • AcrossFacetV4: User → LiFi Diamond → SpokePool.deposit() (cross-chain only)
  • AcrossV4SwapFacet: User → LiFi Diamond → SpokePoolPeriphery.swapAndBridge() → SwapProxy (DEX) → SpokePool.deposit() (swap + cross-chain)

The periphery contract provides:

  • Isolated DEX execution via SwapProxy for security
  • Slippage validation
  • Proportional output adjustment for partial fills

Implementation Details

7 Phase Implementation:

  1. ISpokePoolPeriphery Interface - Complete interface with TransferType enum, Fees/BaseDepositData/SwapAndDepositData structs
  2. AcrossV4SwapFacet Contract - Two public methods: startBridgeTokensViaAcrossV4Swap() (bridge only) and swapAndStartBridgeTokensViaAcrossV4Swap() (LiFi swap + bridge)
  3. Configuration - Added SpokePoolPeriphery and SpokePool addresses for 10 networks
  4. Deploy Script - Reads config and encodes constructor arguments
  5. Update Script - Minimal implementation (no init function needed)
  6. Tests - Integration with TestBaseFacet suite, 14/18 tests passing (4 expected failures due to empty routerCalldata)
  7. Documentation - Complete docs with architecture diagram, methods, structs, and API examples

Scope Limitations (Gasful Flow Only):

  • No permit/permit2/authorization variants (TransferType.Approval only)
  • No submission fees (set to zero)
  • No nonce management (use 0 for gasful flow)
  • No native token wrapping in periphery (caller wraps ETH beforehand)

Files Changed:

  • src/Interfaces/ISpokePoolPeriphery.sol (NEW) - Periphery contract interface
  • src/Facets/AcrossV4SwapFacet.sol (NEW) - Main facet implementation
  • config/across-v4-swap.json (NEW) - Network configuration
  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol (NEW) - Deployment script
  • script/deploy/facets/UpdateAcrossV4SwapFacet.s.sol (NEW) - Update script
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol (NEW) - Test suite
  • docs/AcrossV4SwapFacet.md (NEW) - Complete documentation
  • script/demoScripts/demoAcrossV4Swap.ts (NEW) - Demo script template

Checklist before requesting a review

Notes on Test Failures:

4 tests fail with expected behavior:

  • testBase_CanBridgeTokens
  • testBase_CanBridgeTokens_fuzzed
  • testBase_CanSwapAndBridgeTokens
  • testBase_Revert_BridgeWithInvalidDestinationCallFlag

Reason: Tests use empty routerCalldata, causing SpokePoolPeriphery to revert. These require valid DEX calldata from the Across Swap API for integration testing.

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>

Next Steps Before Mainnet:

  1. Manual testing with actual Across Swap API responses
  2. Testnet deployment and end-to-end verification
  3. Integration tests with real swap data
  4. Verify SpokePoolPeriphery address 0x649C790f02B7e04a5A2e60b6EE6e7d5B2E6B29A5 on all networks
  5. Security audit

@lifi-action-bot lifi-action-bot marked this pull request as draft December 22, 2025 08:08
@lifi-action-bot lifi-action-bot changed the title Add AcrossV4SwapFacet for Across Protocol swap-and-bridge integration Add AcrossV4SwapFacet for Across Protocol swap-and-bridge integration [AcrossV4SwapFacet v1.0.0, ISpokePoolPeriphery v1.0.0] Dec 22, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 22, 2025

Note

Reviews paused

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

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds an Across V4 Swap facet and its interfaces, configs, deploy/demo tooling, extensive Foundry tests, EIP‑712 backend-signing utilities, and helper-script hardening to enable calldata-driven Across V4 swap+bridge flows (including sponsored and backend-signed paths).

Changes

Cohort / File(s) Summary
Facet Implementation & Core Interfaces
src/Facets/AcrossV4SwapFacet.sol, src/Interfaces/ISpokePoolPeriphery.sol, src/Interfaces/IAcrossSpokePoolV4.sol
New AcrossV4SwapFacet with immutable periphery addresses, AcrossV4SwapFacetData + SwapApiTarget, two public entrypoints, multi-path routing, EIP‑712 signature verification for specific targets, validations, helpers; adds DepositParams struct.
Sponsored Periphery Interfaces
src/Interfaces/ISponsoredOFTSrcPeriphery.sol, src/Interfaces/ISponsoredCCTPSrcPeriphery.sol
New interfaces describing sponsored OFT/CCTP quote shapes and signed entrypoints used by sponsored flows.
Tests & Test Utilities
test/solidity/Facets/Across/..., test/solidity/utils/*.sol
Adds large test suites (sponsored flows, refunds, signature validation, non‑EVM handling, edge cases) and new test helpers (EIP‑712 signing, backend-sign utilities, mocks).
Demo Script & Docs
script/demoScripts/demoAcrossV4Swap.ts, docs/AcrossV4SwapFacet.md
New TypeScript demo to build/fetch Across V4 calldata, generate backend signatures, and encode diamond calldata; comprehensive documentation and examples.
Deployment Scripts (forge & zksync)
script/deploy/facets/DeployAcrossV4SwapFacet.s.sol, script/deploy/facets/UpdateAcrossV4SwapFacet.s.sol, script/deploy/zksync/DeployAcrossV4SwapFacet.zksync.s.sol, script/deploy/zksync/UpdateAcrossV4SwapFacet.zksync.s.sol
Add deploy/update scripts reading constructor args from config/acrossV4Swap.json and config/global.json; update scripts exclude immutable selectors.
zksync ScriptBase Utils
script/deploy/zksync/utils/ScriptBase.sol
Adds overload for _getConfigContractAddress with zero-address check and clearer error handling.
Config & Deployment Metadata
config/acrossV4Swap.json, script/deploy/resources/deployRequirements.json, config/global.json, deployments/arbitrum*.json, deployments/arbitrum.staging.json, deployments/arbitrum.staging.json
Add per-network acrossV4Swap.json; add facet to deploy requirements; add backendSigner to global.json; update deployments mapping and staging JSON entries.
Scripts & Tooling Hardening
script/helperFunctions.sh, .gitignore
Robust JSON merge/write/validation with fallbacks and atomic writes; add OUTPUT_MODE/OUTPUT_PATH params to saveDiamondFacets/saveDiamondPeriphery; removed config/whitelist.staging.json from .gitignore.
Errors & NEAR deploy tweak
src/Errors/GenericErrors.sol, script/deploy/facets/DeployNEARIntentsFacet.s.sol, config/nearintents.json (removed)
Added InvalidSignature() error and bumped annotation; NEAR Intents deploy script updated to read backendSigner from config/global.json; removed old NEAR config file.
CI / Policy docs
.cursor/rules/100-solidity-basics.mdc, .cursor/rules/102-facets.mdc
License header guidance for new Solidity files and documentation advising EIP‑712 backend signatures / trust assumptions for opaque calldata-driven facets.
Misc: Demo/Deployment helpers & zksync utils
script/deploy/...
New deploy scripts for zksync and other networks; added constructor/run/getConstructorArgs patterns across scripts.
Docs / Tests for refunds
test/solidity/Facets/Across/SwapAPI/AcrossV4SwapFacet.SponsoredRefunds.t.sol
New tests validating refund behavior for sponsored OFT and CCTP flows and helpers to inject refund recipients into periphery calldata.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

AuditCompleted

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change (adding AcrossV4SwapFacet) and includes version information, clearly indicating the primary deliverable of this PR.
Description check ✅ Passed The description is comprehensive, covering Jira reference, implementation rationale, architecture decisions, detailed implementation phases, scope limitations, files changed, test status, and pre-deployment checklist items. All major template sections are addressed.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch implement-across-swap-facet

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • JIRA integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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.

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

🧹 Nitpick comments (7)
script/demoScripts/demoAcrossV4Swap.ts (1)

1-125: Template contains placeholders that need completion before use.

This commented-out demo template includes:

  • Line 32: ACROSS_V4_SWAP_FACET_ABI is undefined; use AcrossV4SwapFacet.abi from the imported factory
  • Lines 103-105: AcrossV4SwapDataStruct fields are empty placeholder comments; populate with actual structure matching the facet's AcrossV4SwapData (depositData, swapToken, exchange, transferType, routerCalldata, minExpectedInputTokenAmount, enableProportionalAdjustment)
🔎 Suggested corrections
-//   } = await setupEnvironment(srcChain, ACROSS_V4_SWAP_FACET_ABI)
+//   } = await setupEnvironment(srcChain, AcrossV4SwapFacet.abi)
 //   const acrossV4SwapData: AcrossV4SwapFacet.AcrossV4SwapDataStruct = {
-//     // Add your specific fields for AcrossV4Swap here.
+//     depositData: {
+//       inputToken: SRC_TOKEN_ADDRESS,
+//       outputToken: '0x...', // bytes32 destination token
+//       outputAmount: amount,
+//       depositor: signerAddress,
+//       recipient: '0x...', // bytes32 recipient
+//       destinationChainId,
+//       exclusiveRelayer: '0x0000000000000000000000000000000000000000000000000000000000000000',
+//       quoteTimestamp: Math.floor(Date.now() / 1000),
+//       fillDeadline: Math.floor(Date.now() / 1000) + 3600,
+//       exclusivityParameter: 0,
+//       message: '0x'
+//     },
+//     swapToken: SRC_TOKEN_ADDRESS,
+//     exchange: ADDRESS_UNISWAP, // Example
+//     transferType: 0, // ISpokePoolPeriphery.TransferType.Approval
+//     routerCalldata: '0x', // Populate with actual DEX calldata
+//     minExpectedInputTokenAmount: amount,
+//     enableProportionalAdjustment: false
 //   }
docs/AcrossV4SwapFacet.md (2)

91-91: Minor grammar correction.

Consider hyphenating "swap-specific" for proper compound adjective usage.

🔎 Proposed fix
-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 that can be run on various DEXs (i.e. Uniswap) to make one or multiple swaps before performing another action.

93-93: Improve link descriptiveness.

Replace generic "here" link text with descriptive phrases for better accessibility and clarity.

🔎 Proposed fixes

Line 93:

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

Line 99:

-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).

Line 130:

-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 [LI.FI API documentation](https://docs.li.fi/products/more-integration-options/li.fi-api/transferring-tokens-example).

Also applies to: 99-99, 130-130

src/Interfaces/ISpokePoolPeriphery.sol (1)

22-22: Correct version reference in comment.

The comment references "Across V3 deposits" but this interface is for Across V4 Swap integration.

🔎 Proposed fix
-    /// @notice Base deposit data for Across V3 deposits
+    /// @notice Base deposit data for Across V4 deposits
src/Facets/AcrossV4SwapFacet.sol (3)

90-110: Consider updating minExpectedInputTokenAmount after swap to reflect positive slippage.

After _depositAndSwap updates _bridgeData.minAmount with the actual post-swap amount (line 102-107), the _acrossV4SwapData.minExpectedInputTokenAmount still holds the pre-swap value. If the swap produced positive slippage, this discrepancy could cause the SpokePoolPeriphery to use a suboptimal slippage tolerance.

Based on learnings, facets with minAmountOut parameters should adjust bridge parameters proportionally after swaps to account for positive slippage.

🔎 Proposed adjustment

After line 107, update the Across-specific min amount to reflect the updated bridge amount:

     _bridgeData.minAmount = _depositAndSwap(
         _bridgeData.transactionId,
         _bridgeData.minAmount,
         _swapData,
         payable(msg.sender)
     );

+    // Update minExpectedInputTokenAmount to reflect positive slippage from swap
+    AcrossV4SwapData memory updatedAcrossData = _acrossV4SwapData;
+    updatedAcrossData.minExpectedInputTokenAmount = _bridgeData.minAmount;
+
-    _startBridge(_bridgeData, _acrossV4SwapData);
+    _startBridge(_bridgeData, updatedAcrossData);

Note: If depositData.outputAmount also needs proportional adjustment, apply similar logic to that field.


117-154: Event emission after external call may cause ordering issues.

Line 153 emits LiFiTransferStarted after the external call to SPOKE_POOL_PERIPHERY.swapAndBridge (line 151). If the periphery or spoke pool emit events during their execution, event ordering in the transaction log may not reflect the logical flow. While nonReentrant prevents reentrancy attacks, event listeners might observe the periphery's events before LiFi's event.

Consider emitting LiFiTransferStarted before the external call, or document this ordering behavior if intentional.

🔎 Proposed reordering
     // Call the periphery's swapAndBridge function
+    emit LiFiTransferStarted(_bridgeData);
+
     SPOKE_POOL_PERIPHERY.swapAndBridge(swapAndDepositData);
-
-    emit LiFiTransferStarted(_bridgeData);
 }

18-18: Contract can receive ETH but has no explicit withdrawal mechanism (likely safe).

The static analysis tool flags that the contract is payable but lacks a withdrawal function. However, this is a false positive in the context of a Diamond facet with refundExcessNative modifier that returns excess native tokens to msg.sender. Any native ETH sent to the facet is either forwarded to the periphery or refunded, so funds should not be locked.

If this facet is not intended to custody funds, consider adding explicit NatSpec documentation to clarify this for bug bounty purposes.

🔎 Suggested NatSpec addition

Add to the contract-level NatSpec:

 /// @title AcrossV4SwapFacet
 /// @author LI.FI (https://li.fi)
 /// @notice Provides functionality for bridging through Across Protocol using the Swap API (SpokePoolPeriphery)
+/// @notice This contract is not intended to custody user funds. Any native tokens received are either forwarded to the SpokePoolPeriphery or refunded to the sender via the refundExcessNative modifier.
 /// @custom:version 1.0.0

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

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

188-200: Prefer direct address assertions for better error messages.

Using assertEq(bool, true) obscures the actual values on failure. Direct address comparison provides clearer diagnostics.

🔎 Proposed fix
     function test_contractIsSetUpCorrectly() public {
         acrossV4SwapFacet = new TestAcrossV4SwapFacet(
             ISpokePoolPeriphery(SPOKE_POOL_PERIPHERY),
             SPOKE_POOL
         );

-        assertEq(
-            address(acrossV4SwapFacet.SPOKE_POOL_PERIPHERY()) ==
-                SPOKE_POOL_PERIPHERY,
-            true
-        );
-        assertEq(acrossV4SwapFacet.SPOKE_POOL() == SPOKE_POOL, true);
+        assertEq(
+            address(acrossV4SwapFacet.SPOKE_POOL_PERIPHERY()),
+            SPOKE_POOL_PERIPHERY
+        );
+        assertEq(acrossV4SwapFacet.SPOKE_POOL(), SPOKE_POOL);
     }
📜 Review details

Configuration used: Repository 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 9cf765d and 5e5ac45.

📒 Files selected for processing (5)
  • config/across-v4-swap.json
  • deployments/arbitrum.diamond.staging.json
  • deployments/arbitrum.staging.json
  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
🚧 Files skipped from review as they are similar to previous changes (1)
  • config/across-v4-swap.json
🧰 Additional context used
📓 Path-based instructions (12)
script/deploy/**/*.s.sol

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Place deployment scripts in script/deploy/facets/ for facet deployments or script/deploy/ for other contracts. Use Foundry's Script contract pattern.

Files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Use remappings defined in remappings.txt for imports: lifi/src/, test/test/, and external libs like @openzeppelin/, solmate/, solady/, permit2/

**/*.sol: Single Diamond (EIP-2535) as main entrypoint for all protocol interactions
Delegate complex logic to libraries (LibAsset, LibSwap, LibAllowList, SwapperV2, Validatable) and helper contracts

After Solidity changes, run forge test (or note suites remaining)

**/*.sol: Own files must use // SPDX-License-Identifier: LGPL-3.0-only immediately followed by the pragma statement with no blank line in between
All contracts must use pragma solidity ^0.8.17;
Functions and variables use camelCase; constants and immutables are CONSTANT_CASE
Function parameters use leading underscore (e.g., _amount)
Contracts and interfaces must include NatSpec: @title (matching contract/interface name), @author LI.FI (https://li.fi), @notice describing purpose, and @custom:version X.Y.Z
Public and external functions require NatSpec including params and returns documentation
For pure test/script scaffolding keep NatSpec headers minimal but retain SPDX and pragma
Use single blank lines between logical sections and between function declarations
Follow in-function blank-line rules: blank lines before emits/returns; no stray gaps
Use custom errors instead of revert strings; prefer existing errors/helpers before adding new ones
Use generic errors from src/Errors/GenericErrors.sol; bump @custom:version when adding; facet-specific errors stay local
Adhere to rules in .solhint.json
Avoid assembly unless necessary and heavily commented with justification (why assembly is needed); prefer existing helpers over new implementations

Do not mix interface and implementation in the same file

Files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
**/*Swap*.sol

📄 CodeRabbit inference engine (.cursor/rules/002-architecture.mdc)

Emit GenericSwapCompleted event for same-chain swaps

Files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
{src,script,test}/**/*.{sol,ts}

📄 CodeRabbit inference engine (.cursor/rules/105-security.mdc)

Validate all external inputs and configuration (including script/env values) explicitly; prefer existing validation helpers (e.g., Validatable, config readers) over ad-hoc checks

Files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
{src,script}/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/105-security.mdc)

{src,script}/**/*.sol: Do not weaken existing access controls, timelock flows, or Safe multisig protections; any change that touches admin-only functionality must call out its governance impact
Avoid introducing new external call patterns in facets or scripts without checking existing libraries (LibAsset, LibSwap, LibAllowList) for prior art

Files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
script/**/{Deploy,Update}*.s.sol

📄 CodeRabbit inference engine (.cursor/rules/107-solidity-scripts.mdc)

Use Foundry deploy/update script patterns with Deploy*.s.sol or Update*.s.sol naming and JSON config via stdJson

Files:

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

📄 CodeRabbit inference engine (.cursor/rules/107-solidity-scripts.mdc)

Deploy scripts should use DeployScriptBase pattern with deploy(type(Contract).creationCode) and only add getConstructorArgs() when needed, reading from JSON via stdJson

Files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
script/deploy/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/107-solidity-scripts.mdc)

Keep deployment scripts under script/deploy/ directory structure (and script/deploy/zksync/ when relevant) and reuse helper/config files like deployRequirements.json and targetState.json instead of creating new patterns

Files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
test/solidity/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Place test files in test/solidity/ mirroring the src/ directory structure for organization

Files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
**/test/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/103-solidity-interfaces.mdc)

Test interfaces may define inline interfaces as needed for testing purposes

Files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
test/**/*.t.sol

📄 CodeRabbit inference engine (.cursor/rules/400-solidity-tests.mdc)

test/**/*.t.sol: Tests under test/solidity/, mirroring src/ structure; require setUp() function; call initTestBase() when inheriting TestBase directly or indirectly; label actors with vm.label
For facet tests, inherit from TestBaseFacet rather than TestBase, since standard facet functions need to be overridden
Import ordering: system libraries first (e.g., forge-std, ds-test), then project files (e.g., lifi/, test/)
Test function names: test_ prefix for success tests, testRevert_ prefix for failure tests, testBase_ prefix for base tests
Test structure: setup → execute → assert; use vm.startPrank / vm.stopPrank, labels, and base inits
Always assert specific revert reasons; use vm.expectRevert with specific reason
Use vm.expectEmit(true, true, true, true, <addr>) for event assertions
Apply blank line conventions: add gap after vm.expectRevert before the call, and gap before assertions/events
For whitelist flows, inherit TestWhitelistManagerBase and use addToWhitelist / setFunctionWhitelistBySelector helpers
If a facet does not support native tokens, override tests such as testBase_CanSwapAndBridgeNativeTokens and testBase_CanBridgeNativeTokens with public override and include a comment explaining why the test is intentionally skipped

Files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
**/*.{test.ts,t.sol}

📄 CodeRabbit inference engine (.cursor/rules/401-testing-patterns.mdc)

**/*.{test.ts,t.sol}: Prefer adding or updating tests alongside logic changes
Keep tests structured as setup → execute → assert
Assert specific failure conditions (avoid overly-broad "catch-all" assertions)

Files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
🧠 Learnings (57)
📓 Common learnings
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must implement required functions: `_startBridge` (internal), `swapAndStartBridgeTokensVia{FacetName}`, and `startBridgeTokensVia{FacetName}`
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)
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.
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.
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: 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: 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.
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: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/utils/lib/cowShedSdk.ts:0-0
Timestamp: 2025-06-05T14:50:17.275Z
Learning: For demo scripts and example code, ezynda3 prefers to keep the code simple and focused on demonstrating the core functionality rather than adding extensive input validation or defensive programming measures.
📚 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/arbitrum.staging.json
  • deployments/arbitrum.diamond.staging.json
  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 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
📚 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/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: 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/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
📚 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: 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/arbitrum.diamond.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-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must implement required functions: `_startBridge` (internal), `swapAndStartBridgeTokensVia{FacetName}`, and `startBridgeTokensVia{FacetName}`

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/arbitrum.diamond.staging.json
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)

Applied to files:

  • deployments/arbitrum.staging.json
  • deployments/arbitrum.diamond.staging.json
  • test/solidity/Facets/AcrossV4SwapFacet.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:

  • deployments/arbitrum.staging.json
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed

Applied to files:

  • deployments/arbitrum.staging.json
  • test/solidity/Facets/AcrossV4SwapFacet.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:

  • 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-02-13T08:57:00.095Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 984
File: docs/ChainflipFacet.md:0-0
Timestamp: 2025-02-13T08:57:00.095Z
Learning: The ChainflipData struct in ChainflipFacet has three fields:
1. uint32 dstToken - The destination token identifier in Chainflip
2. bytes32 nonEvmAddress - The non-EVM destination address
3. bytes cfParameters - Additional parameters for Chainflip protocol

Applied to files:

  • deployments/arbitrum.staging.json
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable

Applied to files:

  • deployments/arbitrum.staging.json
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets, validate `targetChainId` against `bridgeData.destinationChain` for EVM-to-EVM bridges

Applied to files:

  • deployments/arbitrum.staging.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-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.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.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-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: 2025-04-21T03:15:12.236Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1109
File: deployments/worldchain.diamond.json:84-85
Timestamp: 2025-04-21T03:15:12.236Z
Learning: In deployment JSON files that contain "diamond" in their filename (located in the deployments folder), periphery contracts may have empty string values for their addresses. This indicates that the contract is not deployed on that particular chain and should not be flagged as an issue during code reviews.

Applied to files:

  • deployments/arbitrum.diamond.staging.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/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/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: 2025-01-21T11:04:46.116Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 937
File: config/dexs.json:95-99
Timestamp: 2025-01-21T11:04:46.116Z
Learning: In the dexs.json configuration, utility contracts (like FeeCollector, LiFuelFeeCollector, TokenWrapper) can be treated as DEX contracts since they are handled similarly in the system's logic.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-01-21T11:07:36.236Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 937
File: script/deploy/facets/DeployLiFiDEXAggregator.s.sol:33-35
Timestamp: 2025-01-21T11:07:36.236Z
Learning: In the LiFiDEXAggregator contract deployment (DeployLiFiDEXAggregator.s.sol), the refundWallet address from global.json is used as the owner parameter in the contract's constructor, which is then passed to the WithdrawablePeriphery base contract.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2024-10-04T09:01:56.514Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/base.diamond.json:123-123
Timestamp: 2024-10-04T09:01:56.514Z
Learning: In the `lifinance/contracts` repository, it's acceptable to retain references to the old `LiFuelFeeCollector` address (`0xc4f7A34b8d283f66925eF0f5CCdFC2AF3030DeaE`) in deployment files when updating them is not necessary.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-04-22T09:04:44.244Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1112
File: deployments/soneium.diamond.json:81-81
Timestamp: 2025-04-22T09:04:44.244Z
Learning: In the lifinance/contracts repository, it's normal and expected for periphery contracts to have empty address values in deployment files when they are not deployed on a particular network. This applies to all periphery contracts including ReceiverChainflip, ReceiverStargateV2, and others. PRs should not flag empty periphery contract addresses as issues.

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must include bridge-specific configuration storage (e.g., `recoverGas` for StargateV2, protocol-specific constants)

Applied to files:

  • deployments/arbitrum.diamond.staging.json
📚 Learning: 2025-12-17T10:27:05.481Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/001-project-structure.mdc:0-0
Timestamp: 2025-12-17T10:27:05.481Z
Learning: Applies to script/deploy/**/*.s.sol : Place deployment scripts in `script/deploy/facets/` for facet deployments or `script/deploy/` for other contracts. Use Foundry's `Script` contract pattern.

Applied to files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2025-12-17T10:28:51.722Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/107-solidity-scripts.mdc:0-0
Timestamp: 2025-12-17T10:28:51.722Z
Learning: Applies to script/**/Deploy*.s.sol : Deploy scripts should use `DeployScriptBase` pattern with `deploy(type(Contract).creationCode)` and only add `getConstructorArgs()` when needed, reading from JSON via `stdJson`

Applied to files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2025-08-26T15:19:07.800Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 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/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2025-12-17T10:28:03.630Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/101-solidity-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:03.630Z
Learning: Applies to script/deploy/resources/deployRequirements.json : When adding a new deployable contract that has constructor arguments, add/update its entry in `script/deploy/resources/deployRequirements.json` so deploy scripts validate the presence of required constructor args.

Applied to files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2025-09-25T00:04:16.437Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 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/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2025-01-28T14:27:50.689Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 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/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2025-12-17T10:28:51.722Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/107-solidity-scripts.mdc:0-0
Timestamp: 2025-12-17T10:28:51.722Z
Learning: Applies to script/**/{Deploy,Update}*.s.sol : Use Foundry deploy/update script patterns with `Deploy*.s.sol` or `Update*.s.sol` naming and JSON config via `stdJson`

Applied to files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2025-10-02T18:14:45.047Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 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/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2024-09-23T01:42:03.075Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: script/deploy/facets/DeployGasZipFacet.s.sol:22-35
Timestamp: 2024-09-23T01:42:03.075Z
Learning: In deployment scripts like `DeployGasZipFacet.s.sol`, do not report issues suggesting adding error handling for missing configuration files or unexpected JSON structures, as the script will fail if the file is missing.

Applied to files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2025-12-17T10:28:51.722Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/107-solidity-scripts.mdc:0-0
Timestamp: 2025-12-17T10:28:51.722Z
Learning: Applies to script/deploy/**/*.sol : Keep deployment scripts under `script/deploy/` directory structure (and `script/deploy/zksync/` when relevant) and reuse helper/config files like `deployRequirements.json` and `targetState.json` instead of creating new patterns

Applied to files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2024-10-14T00:50:53.603Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: script/deploy/facets/DeployPermit2Proxy.s.sol:17-20
Timestamp: 2024-10-14T00:50:53.603Z
Learning: In `DeployScriptBase`, `getConstructorArgs()` is called and constructor arguments are handled, so child deploy scripts do not need to pass constructor arguments explicitly to the `deploy` function.

Applied to files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2025-08-29T14:05:37.002Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 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/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2025-01-30T02:51:43.006Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 963
File: script/deploy/zksync/DeploySymbiosisFacet.zksync.s.sol:21-34
Timestamp: 2025-01-30T02:51:43.006Z
Learning: Parameter validation for deployment scripts in the LiFi contracts is handled by pre-deployment scripts, making additional validation within individual deployment scripts unnecessary.

Applied to files:

  • script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
📚 Learning: 2025-12-17T10:29:29.239Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/400-solidity-tests.mdc:0-0
Timestamp: 2025-12-17T10:29:29.239Z
Learning: Applies to test/**/*.t.sol : If a facet does not support native tokens, override tests such as `testBase_CanSwapAndBridgeNativeTokens` and `testBase_CanBridgeNativeTokens` with `public override` and include a comment explaining why the test is intentionally skipped

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:29:29.239Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/400-solidity-tests.mdc:0-0
Timestamp: 2025-12-17T10:29:29.239Z
Learning: Applies to test/**/*.t.sol : For facet tests, inherit from `TestBaseFacet` rather than `TestBase`, since standard facet functions need to be overridden

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use modifiers: `nonReentrant`, `refundExcessNative`, `validateBridgeData`, `doesNotContainSourceSwaps`/`doesContainSourceSwaps`, `doesNotContainDestinationCalls`/`doesContainDestinationCalls` on applicable functions

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.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/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets should contain thin, integration-specific logic only; do not move logic across layers without clear architectural reason

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.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/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `{facetName}Data.receiverAddress` field (e.g., `_glacisData.receiverAddress`), validate that it is not `bytes32(0)` for non-EVM chains and revert with `InvalidNonEVMReceiver()` if zero

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.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:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-15T09:02:31.300Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1530
File: test/solidity/Facets/CelerCircleBridgeFacet.t.sol:1-10
Timestamp: 2025-12-15T09:02:31.300Z
Learning: In Solidity test files under test/solidity/Facets (e.g., test/solidity/Facets/CelerCircleBridgeFacet.t.sol), ensure the SPDX license identifier line is immediately followed by the pragma statement with no blank line in between. Apply this formatting to all .sol files in that directory for consistency.

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
🔇 Additional comments (8)
deployments/arbitrum.diamond.staging.json (3)

228-231: LGTM! AcrossV4SwapFacet properly configured for staging.

The AcrossV4SwapFacet entry is correctly added with version 1.0.0, aligning with the PR objectives to integrate Across Protocol's swap-and-bridge functionality.


26-26: Verify intentional version metadata reset.

The versions for WhitelistManagerFacet and NEARIntentsFacet have been cleared to empty strings. While empty metadata is acceptable in staging environments, please confirm this reset is intentional.

Also applies to: 198-198


246-246: LGTM! ReceiverOIF periphery entry added.

The ReceiverOIF entry has been added to the periphery configuration. The empty address value is expected for staging when the contract hasn't been deployed yet on this network.

deployments/arbitrum.staging.json (1)

68-69: Verify deployed contract address and related deployment file updates.

The JSON syntax fix (comma on line 68) and new AcrossV4SwapFacet entry are correctly formatted. However, please verify:

  1. The address 0x2D732A56c10F33292484911C660C2F68F0615a89 corresponds to the deployed AcrossV4SwapFacet v1.0.0 on Arbitrum
  2. The deployment log file (_deployments_log_file.json) has been updated with this entry
  3. Whether other staging network configurations (e.g., optimism.staging.json, polygon.staging.json) require similar updates

Run the following script to verify the address and check for related deployment file updates:

#!/bin/bash
# Verify AcrossV4SwapFacet deployment tracking

echo "=== Checking for AcrossV4SwapFacet in deployment files ==="
rg -n "AcrossV4SwapFacet" deployments/

echo -e "\n=== Checking for address 0x2D732A56c10F33292484911C660C2F68F0615a89 ==="
rg -n "0x2D732A56c10F33292484911C660C2F68F0615a89" deployments/

echo -e "\n=== Listing all staging deployment files ==="
fd -e json "staging" deployments/

echo -e "\n=== Checking config/across-v4-swap.json for Arbitrum configuration ==="
if [ -f config/across-v4-swap.json ]; then
  jq '.arbitrum // .42161' config/across-v4-swap.json
else
  echo "config/across-v4-swap.json not found"
fi
script/deploy/facets/DeployAcrossV4SwapFacet.s.sol (1)

1-41: LGTM!

The deployment script correctly follows the DeployScriptBase pattern. Constructor args are read from config/across-v4-swap.json using the standard helper, and the deploy() method handles arg concatenation internally. Based on learnings, this matches the established deployment script conventions.

test/solidity/Facets/AcrossV4SwapFacet.t.sol (3)

44-127: LGTM!

The test setup correctly initializes the base test infrastructure, deploys the facet stub, registers selectors, and configures the whitelist. The fork block pinning with date comment aids reproducibility, and the "no-op swap" approach using identical input/output tokens is a pragmatic workaround for stale swap calldata.


171-186: LGTM!

The base test overrides correctly skip unsupported functionality (native token bridging and destination call flag validation) with explanatory comments, following the coding guidelines for facets that don't support native tokens.


202-213: LGTM!

Constructor validation tests correctly verify that InvalidConfig is reverted when either address parameter is zero, using the proper vm.expectRevert pattern.

ezynda3 and others added 3 commits December 22, 2025 18:17
- Update incorrect periphery addresses for optimism, polygon, scroll, blast, mode
- Fix linea and zksync periphery addresses to match official docs
- Remove base (no periphery in official docs)
- Add new chains: bsc, ink, lisk, soneium, unichain, zora
- All addresses verified against https://docs.across.to/reference/contract-addresses
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: 6

📜 Review details

Configuration used: Repository 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 b32d8fd and ea87c76.

📒 Files selected for processing (1)
  • script/demoScripts/demoAcrossV4Swap.ts
🧰 Additional context used
📓 Path-based instructions (5)
script/demoScripts/**/*.{ts,js}

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Place TypeScript demo scripts in script/demoScripts/ directory. Reference existing demos for patterns and place helper utilities in script/demoScripts/utils/

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/099-finish.mdc)

After TypeScript changes, run lint/tests with Bun

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
{src,script,test}/**/*.{sol,ts}

📄 CodeRabbit inference engine (.cursor/rules/105-security.mdc)

Validate all external inputs and configuration (including script/env values) explicitly; prefer existing validation helpers (e.g., Validatable, config readers) over ad-hoc checks

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
{script,tasks}/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/200-typescript.mdc)

{script,tasks}/**/*.ts: TS scripts use .eslintrc.cjs rules, bunx tsx, citty, consola, and env validated via helpers (e.g., getEnvVar()).
DO NOT use deprecated ethers-based helpers (getProvider, getWalletFromPrivateKeyInDotEnv, ethers sendTransaction, ensureBalanceAndAllowanceToDiamond).
Obey .eslintrc.cjs; avoid any; use TypeChain types from typechain/ directory (e.g., ILiFi.BridgeDataStruct).
Import organization: Group imports as: external libs (viem, consola, citty, dotenv) → TypeChain types → config files → internal utils/helpers. Use type imports for types-only.
Error handling: Use try/catch with consola.error() for logging; exit with process.exit(1) on fatal errors. Provide meaningful error messages.
CLI: use citty; logging via consola; validate env via getEnvVar(); exit 0/1 appropriately.
New TypeScript helpers must be covered by a colocated *.test.ts file using Bun (describe / it / expect) with 100% coverage. Cover edge cases and error paths.

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
script/demoScripts/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/200-typescript.mdc)

script/demoScripts/**/*.ts: MUST use viem for all contract interactions in demo/operational scripts; ethers.js helpers are deprecated.
Demo scripts follow similar structural patterns (e.g., main() function, setupEnvironment(), helpers from demoScriptHelpers). See demoLidoWrapper.ts, demoUnit.ts, demoEco.ts as reference examples.

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
🧠 Learnings (13)
📓 Common learnings
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must implement required functions: `_startBridge` (internal), `swapAndStartBridgeTokensVia{FacetName}`, and `startBridgeTokensVia{FacetName}`
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.
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)
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: 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.
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: 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.
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: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement a bridge-specific external entry point (e.g., `handleV3AcrossMessage`, `lzCompose`, `cfReceive`) protected by authorization modifier that decodes bridge message to extract `bytes32 transactionId`, `LibSwap.SwapData[] memory swapData`, `address receiver`, and calls internal `_swapAndCompleteBridgeTokens()`
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Periphery/**/*.sol : Periphery contracts handle specialized flows that don't belong directly in the Diamond
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/utils/lib/cowShedSdk.ts:0-0
Timestamp: 2025-06-05T14:50:17.275Z
Learning: For demo scripts and example code, ezynda3 prefers to keep the code simple and focused on demonstrating the core functionality rather than adding extensive input validation or defensive programming measures.
📚 Learning: 2025-12-17T10:29:06.122Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-17T10:29:06.122Z
Learning: Applies to script/demoScripts/**/*.ts : Demo scripts follow similar structural patterns (e.g., `main()` function, `setupEnvironment()`, helpers from `demoScriptHelpers`). See `demoLidoWrapper.ts`, `demoUnit.ts`, `demoEco.ts` as reference examples.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:29:06.121Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-17T10:29:06.121Z
Learning: Applies to script/demoScripts/**/*.ts : MUST use viem for all contract interactions in demo/operational scripts; ethers.js helpers are deprecated.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:27:05.481Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/001-project-structure.mdc:0-0
Timestamp: 2025-12-17T10:27:05.481Z
Learning: Applies to script/demoScripts/**/*.{ts,js} : Place TypeScript demo scripts in `script/demoScripts/` directory. Reference existing demos for patterns and place helper utilities in `script/demoScripts/utils/`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement internal `_swapAndCompleteBridgeTokens()` function that handles native vs ERC20 tokens: use `safeApproveWithRetry()` or `safeIncreaseAllowance()` for ERC20 (reset to 0 after), pass `value: amount` for native tokens, call `executor.swapAndCompleteBridgeTokens()` in try-catch block, and on failure send raw tokens to receiver and emit `LiFiTransferRecovered`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:29:06.121Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-17T10:29:06.121Z
Learning: Always reuse existing helpers and types: Search `script/common/`, `script/utils/`, `script/demoScripts/utils/`, and other helper directories before implementing new functionality. Key helpers: `script/utils/deploymentHelpers.ts` (deployment loading), `script/demoScripts/utils/demoScriptHelpers.ts` (viem-based demo helpers and swap helpers), `script/common/types.ts` (shared types).

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:29:06.121Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-17T10:29:06.121Z
Learning: Applies to {script,tasks}/**/*.ts : DO NOT use deprecated ethers-based helpers (`getProvider`, `getWalletFromPrivateKeyInDotEnv`, ethers `sendTransaction`, `ensureBalanceAndAllowanceToDiamond`).

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
🧬 Code graph analysis (1)
script/demoScripts/demoAcrossV4Swap.ts (1)
script/demoScripts/utils/demoScriptHelpers.ts (6)
  • ADDRESS_WETH_ARB (92-92)
  • ADDRESS_USDC_OPT (81-81)
  • getProvider (185-190)
  • getWalletFromPrivateKeyInDotEnv (192-196)
  • ensureBalanceAndAllowanceToDiamond (232-270)
  • sendTransaction (198-229)

- Set recipient and depositor to user wallet (not Diamond)
- Add skipOriginTxEstimation=true for contract integration
- Extract transferType from API calldata instead of hardcoding
- Add example successful transaction links
- Improve logging with transfer type and decoded addresses
- Migrate demo script from ethers to viem
- Add positive slippage adjustment for minExpectedInputTokenAmount
- Emit LiFiTransferStarted event before external call
- Fix V3 -> V4 version comment in ISpokePoolPeriphery
- Use direct assertEq for address comparisons in tests
- Improve documentation grammar and link descriptions
- Add NatSpec about contract not custodying funds
- Bump AcrossV4SwapFacet version to 1.0.1
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

🧹 Nitpick comments (3)
script/demoScripts/demoAcrossV4Swap.ts (2)

253-253: Consider adding a type definition for decoded swap data.

The as any cast works but reduces type safety. Consider defining a TypeScript interface matching the decoded struct to improve maintainability.

🔎 Suggested type definition
interface DecodedSwapAndDepositData {
  swapToken: `0x${string}`
  exchange: `0x${string}`
  transferType: number
  routerCalldata: `0x${string}`
  minExpectedInputTokenAmount: bigint
  depositData: {
    inputToken: `0x${string}`
    outputToken: `0x${string}`
    outputAmount: bigint
    depositor: `0x${string}`
    recipient: `0x${string}`
    destinationChainId: bigint
    exclusiveRelayer: `0x${string}`
    quoteTimestamp: number
    fillDeadline: number
    exclusivityParameter: number
    message: `0x${string}`
  }
}
// Then use: const swapData = decoded.args[0] as DecodedSwapAndDepositData

533-534: Minor: Step numbering is inconsistent.

Line 534 logs "Step 6" but the variable step "Step 6" follows display summary which had no step number. The actual sequence of numbered steps in the code is: 1→2→3→4→5→(Summary)→6→7. Consider renumbering for clarity.

src/Facets/AcrossV4SwapFacet.sol (1)

144-159: Hardcoded values are appropriate for gasful flow scope.

The submissionFees set to zero (lines 144-147) and nonce set to 0 (line 159) are intentional per the PR scope, which is limited to the gasful flow. The inline comment at line 159 documents this. Consider adding a similar brief comment for submissionFees for consistency.

🔎 Suggested comment
                     submissionFees: ISpokePoolPeriphery.Fees({
-                        amount: 0,
+                        amount: 0, // Not used in gasful flow
                         recipient: address(0)
                     }),
📜 Review details

Configuration used: Repository 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 ab7d2bc and c3a2471.

📒 Files selected for processing (5)
  • docs/AcrossV4SwapFacet.md
  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
  • src/Interfaces/ISpokePoolPeriphery.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
✅ Files skipped from review due to trivial changes (1)
  • docs/AcrossV4SwapFacet.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Interfaces/ISpokePoolPeriphery.sol
🧰 Additional context used
📓 Path-based instructions (15)
script/demoScripts/**/*.{ts,js}

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Place TypeScript demo scripts in script/demoScripts/ directory. Reference existing demos for patterns and place helper utilities in script/demoScripts/utils/

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/099-finish.mdc)

After TypeScript changes, run lint/tests with Bun

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
{src,script,test}/**/*.{sol,ts}

📄 CodeRabbit inference engine (.cursor/rules/105-security.mdc)

Validate all external inputs and configuration (including script/env values) explicitly; prefer existing validation helpers (e.g., Validatable, config readers) over ad-hoc checks

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
{script,tasks}/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/200-typescript.mdc)

{script,tasks}/**/*.ts: TS scripts use .eslintrc.cjs rules, bunx tsx, citty, consola, and env validated via helpers (e.g., getEnvVar()).
DO NOT use deprecated ethers-based helpers (getProvider, getWalletFromPrivateKeyInDotEnv, ethers sendTransaction, ensureBalanceAndAllowanceToDiamond).
Obey .eslintrc.cjs; avoid any; use TypeChain types from typechain/ directory (e.g., ILiFi.BridgeDataStruct).
Import organization: Group imports as: external libs (viem, consola, citty, dotenv) → TypeChain types → config files → internal utils/helpers. Use type imports for types-only.
Error handling: Use try/catch with consola.error() for logging; exit with process.exit(1) on fatal errors. Provide meaningful error messages.
CLI: use citty; logging via consola; validate env via getEnvVar(); exit 0/1 appropriately.
New TypeScript helpers must be covered by a colocated *.test.ts file using Bun (describe / it / expect) with 100% coverage. Cover edge cases and error paths.

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
script/demoScripts/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/200-typescript.mdc)

script/demoScripts/**/*.ts: MUST use viem for all contract interactions in demo/operational scripts; ethers.js helpers are deprecated.
Demo scripts follow similar structural patterns (e.g., main() function, setupEnvironment(), helpers from demoScriptHelpers). See demoLidoWrapper.ts, demoUnit.ts, demoEco.ts as reference examples.

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
src/Facets/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

src/Facets/**/*.sol: Place new facets in the src/Facets/ directory and use plop templates if available for code generation
Keep facets thin and delegate complex logic to libraries. Group imports in order: external libs → interfaces → libraries → contracts

src/Facets/**/*.sol: Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)
Facets should contain thin, integration-specific logic only; do not move logic across layers without clear architectural reason

Files:

  • src/Facets/AcrossV4SwapFacet.sol
**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Use remappings defined in remappings.txt for imports: lifi/src/, test/test/, and external libs like @openzeppelin/, solmate/, solady/, permit2/

**/*.sol: Single Diamond (EIP-2535) as main entrypoint for all protocol interactions
Delegate complex logic to libraries (LibAsset, LibSwap, LibAllowList, SwapperV2, Validatable) and helper contracts

After Solidity changes, run forge test (or note suites remaining)

**/*.sol: Own files must use // SPDX-License-Identifier: LGPL-3.0-only immediately followed by the pragma statement with no blank line in between
All contracts must use pragma solidity ^0.8.17;
Functions and variables use camelCase; constants and immutables are CONSTANT_CASE
Function parameters use leading underscore (e.g., _amount)
Contracts and interfaces must include NatSpec: @title (matching contract/interface name), @author LI.FI (https://li.fi), @notice describing purpose, and @custom:version X.Y.Z
Public and external functions require NatSpec including params and returns documentation
For pure test/script scaffolding keep NatSpec headers minimal but retain SPDX and pragma
Use single blank lines between logical sections and between function declarations
Follow in-function blank-line rules: blank lines before emits/returns; no stray gaps
Use custom errors instead of revert strings; prefer existing errors/helpers before adding new ones
Use generic errors from src/Errors/GenericErrors.sol; bump @custom:version when adding; facet-specific errors stay local
Adhere to rules in .solhint.json
Avoid assembly unless necessary and heavily commented with justification (why assembly is needed); prefer existing helpers over new implementations

Do not mix interface and implementation in the same file

Files:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
**/*Swap*.sol

📄 CodeRabbit inference engine (.cursor/rules/002-architecture.mdc)

Emit GenericSwapCompleted event for same-chain swaps

Files:

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

📄 CodeRabbit inference engine (.cursor/rules/102-facets.mdc)

src/Facets/**/*Facet.sol: Facets must be located in src/Facets/ directory with names containing Facet
Facets must implement required functions: _startBridge (internal), swapAndStartBridgeTokensVia{FacetName}, and startBridgeTokensVia{FacetName}
Facets must use modifiers: nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps/doesContainSourceSwaps, doesNotContainDestinationCalls/doesContainDestinationCalls on applicable functions
In Solidity facets, receiverAddress must be the first parameter in {facetName}Data and must match bridgeData.receiver for EVM chains
In Solidity facets, validate targetChainId against bridgeData.destinationChain for EVM-to-EVM bridges
Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via _depositAndSwap variants when needed
In Solidity facets with minAmountOut or similar bridge parameters, update the bridge's minAmountOut in swapAndStartBridgeTokensVia{FacetName} to account for positive slippage from swaps after _depositAndSwap updates _bridgeData.minAmount, adjusting proportionally for decimal differences if applicable
For non-EVM receivers in Solidity facets, use bytes type; the value must be non-zero
For non-EVM flows in Solidity facets, bridgeData.receiver must equal NON_EVM_ADDRESS
In Solidity facets with {facetName}Data.receiverAddress field (e.g., _glacisData.receiverAddress), validate that it is not bytes32(0) for non-EVM chains and revert with InvalidNonEVMReceiver() if zero

Files:

  • src/Facets/AcrossV4SwapFacet.sol
{src,script}/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/105-security.mdc)

{src,script}/**/*.sol: Do not weaken existing access controls, timelock flows, or Safe multisig protections; any change that touches admin-only functionality must call out its governance impact
Avoid introducing new external call patterns in facets or scripts without checking existing libraries (LibAsset, LibSwap, LibAllowList) for prior art

Files:

  • src/Facets/AcrossV4SwapFacet.sol
src/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/106-gas.mdc)

src/**/*.sol: Follow gas-related best practices in existing facets before introducing new micro-optimizations in Solidity
Prefer using existing optimized libraries already in the repo (e.g., Solady/Solmate utilities) where they are in use, rather than hand-rolled low-level code
Do not sacrifice readability or safety for minor gas wins; explain any non-obvious optimization and justify it with expected impact
Avoid introducing inline assembly unless clearly needed; when used, document assumptions and invariants thoroughly

All contracts in src/ require audits except Interfaces in src/Interfaces/** (type definitions only) and external dependencies in lib/

src/**/*.sol: NatSpec required on contracts/interfaces in src/: @title, @author LI.FI (https://li.fi), @notice, @custom:version X.Y.Z; document all public/external functions with params/returns.
Bug bounty clarity: In contract NatSpec, explicitly document whether the contract is intended to hold/custody funds. If not designed to hold funds, state clearly (e.g., 'This contract is not intended to custody user funds / hold balances; any funds held are incidental'). If designed to hold funds, describe what funds it holds and under what conditions.
Apply Diamond patterns with existing libs (LibAsset/LibSwap/LibAllowList, Validatable/SwapperV2); prefer parameters over msg.sender for refund addresses.
In Solidity 0.8.17, you must not emit events using ContractName.EventName syntax (e.g., emit SomeContract.SomeEvent(...)). Events must be defined in the same contract where they're emitted, or defined in an interface that the contract uses, and then emitted using just the event name (e.g., emit SomeEvent(...)). This prevents compilation errors and ensures 0.8.17 compatibility.

Files:

  • src/Facets/AcrossV4SwapFacet.sol
test/solidity/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Place test files in test/solidity/ mirroring the src/ directory structure for organization

Files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
**/test/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/103-solidity-interfaces.mdc)

Test interfaces may define inline interfaces as needed for testing purposes

Files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
test/**/*.t.sol

📄 CodeRabbit inference engine (.cursor/rules/400-solidity-tests.mdc)

test/**/*.t.sol: Tests under test/solidity/, mirroring src/ structure; require setUp() function; call initTestBase() when inheriting TestBase directly or indirectly; label actors with vm.label
For facet tests, inherit from TestBaseFacet rather than TestBase, since standard facet functions need to be overridden
Import ordering: system libraries first (e.g., forge-std, ds-test), then project files (e.g., lifi/, test/)
Test function names: test_ prefix for success tests, testRevert_ prefix for failure tests, testBase_ prefix for base tests
Test structure: setup → execute → assert; use vm.startPrank / vm.stopPrank, labels, and base inits
Always assert specific revert reasons; use vm.expectRevert with specific reason
Use vm.expectEmit(true, true, true, true, <addr>) for event assertions
Apply blank line conventions: add gap after vm.expectRevert before the call, and gap before assertions/events
For whitelist flows, inherit TestWhitelistManagerBase and use addToWhitelist / setFunctionWhitelistBySelector helpers
If a facet does not support native tokens, override tests such as testBase_CanSwapAndBridgeNativeTokens and testBase_CanBridgeNativeTokens with public override and include a comment explaining why the test is intentionally skipped

Files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
**/*.{test.ts,t.sol}

📄 CodeRabbit inference engine (.cursor/rules/401-testing-patterns.mdc)

**/*.{test.ts,t.sol}: Prefer adding or updating tests alongside logic changes
Keep tests structured as setup → execute → assert
Assert specific failure conditions (avoid overly-broad "catch-all" assertions)

Files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
🧠 Learnings (57)
📓 Common learnings
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must implement required functions: `_startBridge` (internal), `swapAndStartBridgeTokensVia{FacetName}`, and `startBridgeTokensVia{FacetName}`
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.
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed
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.
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: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement internal `_swapAndCompleteBridgeTokens()` function that handles native vs ERC20 tokens: use `safeApproveWithRetry()` or `safeIncreaseAllowance()` for ERC20 (reset to 0 after), pass `value: amount` for native tokens, call `executor.swapAndCompleteBridgeTokens()` in try-catch block, and on failure send raw tokens to receiver and emit `LiFiTransferRecovered`
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: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*Bridge*.sol : LiFiTransferStarted event must be emitted at the end of the internal _startBridge function in facets, after all validations and external bridge calls have completed successfully
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement a bridge-specific external entry point (e.g., `handleV3AcrossMessage`, `lzCompose`, `cfReceive`) protected by authorization modifier that decodes bridge message to extract `bytes32 transactionId`, `LibSwap.SwapData[] memory swapData`, `address receiver`, and calls internal `_swapAndCompleteBridgeTokens()`
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Periphery/**/*.sol : Periphery contracts handle specialized flows that don't belong directly in the Diamond
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.
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: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/001-project-structure.mdc:0-0
Timestamp: 2025-12-17T10:27:05.481Z
Learning: Applies to src/Periphery/**/*.sol : Place new periphery contracts in the `src/Periphery/` directory. These are standalone contracts called by the Diamond but are not facets and can be upgraded independently.
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/utils/lib/cowShedSdk.ts:0-0
Timestamp: 2025-06-05T14:50:17.275Z
Learning: For demo scripts and example code, ezynda3 prefers to keep the code simple and focused on demonstrating the core functionality rather than adding extensive input validation or defensive programming measures.
📚 Learning: 2025-12-17T10:29:06.121Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-17T10:29:06.121Z
Learning: Applies to script/demoScripts/**/*.ts : MUST use viem for all contract interactions in demo/operational scripts; ethers.js helpers are deprecated.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:29:06.122Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-17T10:29:06.122Z
Learning: Applies to script/demoScripts/**/*.ts : Demo scripts follow similar structural patterns (e.g., `main()` function, `setupEnvironment()`, helpers from `demoScriptHelpers`). See `demoLidoWrapper.ts`, `demoUnit.ts`, `demoEco.ts` as reference examples.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:27:05.481Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/001-project-structure.mdc:0-0
Timestamp: 2025-12-17T10:27:05.481Z
Learning: Applies to script/demoScripts/**/*.{ts,js} : Place TypeScript demo scripts in `script/demoScripts/` directory. Reference existing demos for patterns and place helper utilities in `script/demoScripts/utils/`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 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/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:29:06.121Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-17T10:29:06.121Z
Learning: Always reuse existing helpers and types: Search `script/common/`, `script/utils/`, `script/demoScripts/utils/`, and other helper directories before implementing new functionality. Key helpers: `script/utils/deploymentHelpers.ts` (deployment loading), `script/demoScripts/utils/demoScriptHelpers.ts` (viem-based demo helpers and swap helpers), `script/common/types.ts` (shared types).

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement internal `_swapAndCompleteBridgeTokens()` function that handles native vs ERC20 tokens: use `safeApproveWithRetry()` or `safeIncreaseAllowance()` for ERC20 (reset to 0 after), pass `value: amount` for native tokens, call `executor.swapAndCompleteBridgeTokens()` in try-catch block, and on failure send raw tokens to receiver and emit `LiFiTransferRecovered`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:29:06.122Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-17T10:29:06.122Z
Learning: Applies to {script,tasks}/**/*.ts : Obey `.eslintrc.cjs`; avoid `any`; use TypeChain types from `typechain/` directory (e.g., `ILiFi.BridgeDataStruct`).

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:29:06.121Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-17T10:29:06.121Z
Learning: Applies to {script,tasks}/**/*.ts : DO NOT use deprecated ethers-based helpers (`getProvider`, `getWalletFromPrivateKeyInDotEnv`, ethers `sendTransaction`, `ensureBalanceAndAllowanceToDiamond`).

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2024-10-31T09:11:15.238Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 843
File: script/demoScripts/demoRelay.ts:27-89
Timestamp: 2024-10-31T09:11:15.238Z
Learning: When reviewing demo scripts in `script/demoScripts`, avoid refactoring suggestions for code reuse, as they may not be necessary.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2024-11-04T03:47:47.465Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 847
File: script/tasks/fundNewWalletOnAllChains.ts:156-164
Timestamp: 2024-11-04T03:47:47.465Z
Learning: In the `fundNewWalletOnAllChains.ts` script, the gas estimation code involving `publicClient.estimateGas()` is intentionally commented out and should remain that way unless specified otherwise.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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: The CurveFacet in src/Periphery/Lda/Facets/CurveFacet.sol has fundamental issues: it imports a non-existent ICurveLegacy interface, and attempts to send ETH to non-payable exchange functions in both ICurve and ICurveV2 interfaces. All current Curve interfaces are non-payable and cannot accept native ETH.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement a bridge-specific external entry point (e.g., `handleV3AcrossMessage`, `lzCompose`, `cfReceive`) protected by authorization modifier that decodes bridge message to extract `bytes32 transactionId`, `LibSwap.SwapData[] memory swapData`, `address receiver`, and calls internal `_swapAndCompleteBridgeTokens()`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:40.640Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/105-security.mdc:0-0
Timestamp: 2025-12-17T10:28:40.640Z
Learning: Applies to {src,script}/**/*.sol : Avoid introducing new external call patterns in facets or scripts without checking existing libraries (`LibAsset`, `LibSwap`, `LibAllowList`) for prior art

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2024-09-23T02:04:15.621Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: src/Periphery/GasZipPeriphery.sol:64-64
Timestamp: 2024-09-23T02:04:15.621Z
Learning: In the `depositToGasZipERC20` function, checking if `swapOutputAmount` is greater than zero after decoding is not required to avoid unnecessary gas consumption.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-10T17:36:54.412Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1524
File: config/whitelist.json:4358-4366
Timestamp: 2025-12-10T17:36:54.412Z
Learning: Repo lifinance/contracts: In config/whitelist.json, temporary network keys (e.g., "stable") may appear under DEX entries (such as Fly) while deployments are in progress and the corresponding chain configuration PR hasn’t merged yet. This is expected, does not break the workflow, and should not be flagged as an unsupported chain key.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-06-05T14:28:24.620Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/demoPatcher.ts:0-0
Timestamp: 2025-06-05T14:28:24.620Z
Learning: In demo scripts (files in script/demoScripts/ or similar demo contexts), unlimited token approvals using ethers.constants.MaxUint256 or type(uint256).max are acceptable for convenience, even though they would be flagged as security concerns in production code. The team acknowledges this is fine for demonstration purposes.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-01-22T12:40:50.355Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: script/demoScripts/demoGlacisAirlift.ts:42-59
Timestamp: 2025-01-22T12:40:50.355Z
Learning: In TypeScript/JavaScript demo scripts using ethers.js, nonce is automatically managed by the library and doesn't need to be explicitly set. Similarly, the default gas limit is typically sufficient for standard operations like ERC20 approvals.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-10-04T09:21:59.708Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/polygon.json:0-0
Timestamp: 2024-10-04T09:21:59.708Z
Learning: Ensure that scripts used for codebase verification produce valid and accurate results before reporting issues, especially when checking Ethereum address checksums in `deployments/polygon.json`.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-24T08:52:48.545Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/101-solidity-contracts.mdc:0-0
Timestamp: 2025-12-24T08:52:48.545Z
Learning: Applies to src/**/*.sol : Apply Diamond patterns with existing libs (LibAsset/LibSwap/LibAllowList, Validatable/SwapperV2); prefer parameters over `msg.sender` for refund addresses.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must implement required functions: `_startBridge` (internal), `swapAndStartBridgeTokensVia{FacetName}`, and `startBridgeTokensVia{FacetName}`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use modifiers: `nonReentrant`, `refundExcessNative`, `validateBridgeData`, `doesNotContainSourceSwaps`/`doesContainSourceSwaps`, `doesNotContainDestinationCalls`/`doesContainDestinationCalls` on applicable functions

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.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:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 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:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.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:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-08-27T13:16:55.613Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/CoreRouteFacet.sol:0-0
Timestamp: 2025-08-27T13:16:55.613Z
Learning: In LDA (LiFi DEX Aggregator) contracts, using address(this).balance to route all available ETH including dust and deposits from previous calls is intentional design. LDA contracts should not hold any funds and are designed to route any accumulated ETH to prevent fund accumulation. This is a feature, not a security issue.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.sol
📚 Learning: 2025-07-17T04:21:55.549Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1266
File: script/deploy/safe/execute-pending-timelock-tx.ts:334-334
Timestamp: 2025-07-17T04:21:55.549Z
Learning: In the lifinance/contracts repository, 0xDEnYO prefers to keep private key processing simple in scripts like execute-pending-timelock-tx.ts without adding format validation, prioritizing code simplicity over strict validation in controlled environments.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-04-28T07:46:24.084Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1116
File: src/Libraries/LibAsset.sol:102-108
Timestamp: 2025-04-28T07:46:24.084Z
Learning: In the LiFi contracts, the `LibAsset.transferFromERC20` function is intentionally designed to accept arbitrary `from` parameters, with security ensured through a whitelist mechanism that controls which contracts can call this function.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-04-22T09:04:44.244Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1112
File: deployments/soneium.diamond.json:81-81
Timestamp: 2025-04-22T09:04:44.244Z
Learning: In the lifinance/contracts repository, it's normal and expected for periphery contracts to have empty address values in deployment files when they are not deployed on a particular network. This applies to all periphery contracts including ReceiverChainflip, ReceiverStargateV2, and others. PRs should not flag empty periphery contract addresses as issues.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 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:

  • src/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-24T08:52:48.545Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/101-solidity-contracts.mdc:0-0
Timestamp: 2025-12-24T08:52:48.545Z
Learning: Applies to src/**/*.sol : In Solidity 0.8.17, you must not emit events using `ContractName.EventName` syntax (e.g., `emit SomeContract.SomeEvent(...)`). Events must be defined in the same contract where they're emitted, or defined in an interface that the contract uses, and then emitted using just the event name (e.g., `emit SomeEvent(...)`). This prevents compilation errors and ensures 0.8.17 compatibility.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Periphery/Receiver*.sol : LiFiTransferRecovered event should only be emitted in Receiver contracts (src/Periphery/Receiver*.sol)

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must only emit `LiFiTransferRecovered` when swaps fail and raw bridged tokens are sent to receiver, with event signature: `LiFiTransferRecovered(bytes32 indexed transactionId, address receivingAssetId, address receiver, uint256 amount, uint256 timestamp)`

Applied to files:

  • src/Facets/AcrossV4SwapFacet.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:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must use try-catch for executor calls, always have fallback to send raw tokens on failure, and reset approvals to 0 after operations

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to **/*.sol : Delegate complex logic to libraries (LibAsset, LibSwap, LibAllowList, SwapperV2, Validatable) and helper contracts

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-12T11:16:09.236Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1530
File: src/Interfaces/ICircleBridgeProxy.sol:20-29
Timestamp: 2025-12-12T11:16:09.236Z
Learning: In src/Interfaces/ICircleBridgeProxy.sol, ensure the ICircleBridgeProxy interface corresponds to Celer's CircleBridgeProxy contract (not Circle's native TokenMessenger). The depositForBurn signature must be: depositForBurn(uint256 _amount, uint64 _dstChid, bytes32 _mintRecipient, address _burnToken, uint256 _maxFee, uint32 _minFinalityThreshold) external. This change should be scoped specifically to this file; pattern is not needed since it targets a single file. This improves correctness by aligning the interface with the correct contract and parameter types (dst chain id as uint64, no bytes32 destinationCaller parameter).

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:29:29.239Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/400-solidity-tests.mdc:0-0
Timestamp: 2025-12-17T10:29:29.239Z
Learning: Applies to test/**/*.t.sol : If a facet does not support native tokens, override tests such as `testBase_CanSwapAndBridgeNativeTokens` and `testBase_CanBridgeNativeTokens` with `public override` and include a comment explaining why the test is intentionally skipped

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:29:29.239Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/400-solidity-tests.mdc:0-0
Timestamp: 2025-12-17T10:29:29.239Z
Learning: Applies to test/**/*.t.sol : For facet tests, inherit from `TestBaseFacet` rather than `TestBase`, since standard facet functions need to be overridden

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.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/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-15T09:02:31.300Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1530
File: test/solidity/Facets/CelerCircleBridgeFacet.t.sol:1-10
Timestamp: 2025-12-15T09:02:31.300Z
Learning: In Solidity test files under test/solidity/Facets (e.g., test/solidity/Facets/CelerCircleBridgeFacet.t.sol), ensure the SPDX license identifier line is immediately followed by the pragma statement with no blank line in between. Apply this formatting to all .sol files in that directory for consistency.

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `{facetName}Data.receiverAddress` field (e.g., `_glacisData.receiverAddress`), validate that it is not `bytes32(0)` for non-EVM chains and revert with `InvalidNonEVMReceiver()` if zero

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
🧬 Code graph analysis (1)
script/demoScripts/demoAcrossV4Swap.ts (1)
script/demoScripts/utils/demoScriptHelpers.ts (5)
  • ADDRESS_WETH_ARB (92-92)
  • ADDRESS_USDC_OPT (81-81)
  • setupEnvironment (738-792)
  • ensureBalance (931-952)
  • ensureAllowance (957-991)
🪛 GitHub Check: Olympix Integrated Security
src/Facets/AcrossV4SwapFacet.sol

[failure] 20-20:
Contracts that can receive ether but cannot send it may lock value permanently. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/locked-ether

🔇 Additional comments (10)
script/demoScripts/demoAcrossV4Swap.ts (1)

1-31: Good migration to viem-based implementation.

The demo script correctly uses viem for all contract interactions, following the coding guidelines. Imports are properly organized: external libs (crypto, consola, dotenv, viem) → TypeChain types → config files → internal utils. The script uses the recommended setupEnvironment, ensureBalance, ensureAllowance, and executeTransaction helpers from demoScriptHelpers.

src/Facets/AcrossV4SwapFacet.sol (5)

14-20: NatSpec properly documents fund custody status.

The contract correctly documents that it does not custody user funds (lines 17-18), satisfying the bug bounty clarity requirement in the coding guidelines. The refundExcessNative modifier ensures any excess native tokens are returned to the sender.

The static analysis "locked-ether" warning is a false positive — the refundExcessNative modifier on both entry points handles native token refunds.


54-63: Constructor validation is correct.

Zero-address checks for both _spokePoolPeriphery and _spokePool using the existing InvalidConfig error. Immutable state is properly initialized.


70-86: Entry point correctly implements required modifiers and asset handling.

All required modifiers are present: nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps. Asset deposit via LibAsset.depositAsset before bridging follows the standard pattern.


92-122: Positive slippage adjustment correctly implemented.

The swapAndStartBridgeTokensViaAcrossV4Swap function properly adjusts minExpectedInputTokenAmount proportionally when there's positive slippage from the swap (lines 112-119), following the coding guideline for handling positive slippage in swap-and-bridge flows. The formula (original * newAmount) / originalAmount correctly scales the expectation.


162-166: Event emission before external call is intentional but diverges from standard pattern.

The LiFiTransferStarted event is emitted before the external call to SPOKE_POOL_PERIPHERY.swapAndBridge(). While the learnings indicate events should be emitted "at the end of the internal _startBridge function," this placement was intentionally changed per the commit message. The nonReentrant modifier on entry points provides reentrancy protection, making the event order safe.

However, if the external call reverts, the event will have been emitted but the transaction will revert entirely, so this doesn't cause state inconsistency. The static analysis "reentrancy-events" warning can be safely ignored given the nonReentrant protection.

test/solidity/Facets/AcrossV4SwapFacet.t.sol (4)

44-127: Test setup follows established patterns correctly.

The setUp function:

  • Calls initTestBase() as required when inheriting TestBaseFacet
  • Uses customBlockNumberForForking for reproducible forked tests
  • Properly registers facet selectors with the diamond
  • Adds allowed contract selectors for Uniswap router
  • Uses vm.label for actor labeling
  • Configures bridgeData and validAcrossV4SwapData appropriately

The "no-op" swap approach (USDC→USDC) is a pragmatic workaround for testing periphery integration without stale swap calldata issues.


179-186: Native token test overrides correctly documented.

Both testBase_CanBridgeNativeTokens and testBase_CanSwapAndBridgeNativeTokens are overridden with empty bodies and comments explaining the facet doesn't support native asset bridging, following the coding guidelines.


201-212: Constructor validation tests are comprehensive.

Tests cover both zero-address scenarios for _spokePoolPeriphery and _spokePool, using vm.expectRevert with the specific InvalidConfig.selector. Follows the testRevert_ naming convention.


129-149: Bridge transaction initiator correctly handles dynamic amounts.

The override properly synchronizes validAcrossV4SwapData.minExpectedInputTokenAmount with bridgeData.minAmount for fuzz tests, and approximates the output amount with a 0.1% fee reduction. The isNative branch exists for interface completeness but won't be exercised since native token tests are overridden.

ezynda3 and others added 3 commits December 24, 2025 15:42
- Import networks config for chain IDs and explorer URLs
- Use SupportedChain type for type-safe chain names
- Use getConfigElement() for accessing across-v4-swap config
- Add EnvironmentEnum support for environment switching
- Replace hardcoded values with config-driven values
- Add CLI flag --collect-fee to enable fee collection before bridging
- Use swapAndStartBridgeTokensViaAcrossV4Swap with FeeCollector swap data
- Dynamically get FeeCollector address based on environment (staging/production)
- Configure integrator fee (0.0001 WETH) and LiFi fee (0.00005 WETH)
- Add example transaction URLs for fee collection flow
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)
script/demoScripts/demoAcrossV4Swap.ts (1)

678-681: Append transaction hash to explorer URL.

The explorer link outputs only the base URL without the transaction hash, making it incomplete. Capture the return value from executeTransaction and append it:

   if (COLLECT_FEE) {
     // ...
-    await executeTransaction(
+    const txHash = await executeTransaction(
       () =>
         (
           lifiDiamondContract as any
         ).write.swapAndStartBridgeTokensViaAcrossV4Swap([
           bridgeDataWithSwap,
           [feeCollectionSwapData],
           acrossV4SwapData,
         ]),
       'Starting bridge with fee collection via AcrossV4Swap',
       publicClient,
       true
     )
   } else {
-    await executeTransaction(
+    const txHash = await executeTransaction(
       () =>
         (lifiDiamondContract as any).write.startBridgeTokensViaAcrossV4Swap([
           bridgeData,
           acrossV4SwapData,
         ]),
       'Starting bridge tokens via AcrossV4Swap',
       publicClient,
       true
     )
   }

   consola.info('\n==========================================')
   consola.info('  TRANSACTION SUCCESSFUL!')
   consola.info('==========================================')
-  consola.info(`Explorer: ${EXPLORER_BASE_URL}\n`)
+  consola.info(`Explorer: ${EXPLORER_BASE_URL}${txHash}\n`)

Note: You'll need to hoist txHash declaration outside the if/else blocks or restructure to make it accessible.

🧹 Nitpick comments (1)
script/demoScripts/demoAcrossV4Swap.ts (1)

584-613: Minor step numbering mismatch between comments and console output.

The code comments (lines 584, 588, 612) reference "Step 7/8/9" while the console output shows "Step 6/7". The user-facing step numbers (1-7) are internally consistent, but the code comments are out of sync. Consider aligning them for maintainability.

🔎 Suggested alignment
-  // Step 7: Calculate amounts and prepare fee collection if enabled
+  // Step 6: Calculate amounts and prepare fee collection if enabled
   const totalFees = COLLECT_FEE ? INTEGRATOR_FEE + LIFI_FEE : 0n
   const totalAmount = fromAmount + totalFees

-  // Step 8: Check balance and allowance
+  // Step 7: Check balance and allowance
   consola.info('Step 6: Checking balance and allowance...')
+  consola.info('Step 7: Checking balance and allowance...')

...

-  // Step 9: Execute transaction
-  consola.info('Step 7: Executing transaction...')
+  // Step 8: Execute transaction
+  consola.info('Step 8: Executing transaction...')
📜 Review details

Configuration used: Repository 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 f391f84 and 68c8cd4.

📒 Files selected for processing (1)
  • script/demoScripts/demoAcrossV4Swap.ts
🧰 Additional context used
📓 Path-based instructions (5)
script/demoScripts/**/*.{ts,js}

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Place TypeScript demo scripts in script/demoScripts/ directory. Reference existing demos for patterns and place helper utilities in script/demoScripts/utils/

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/099-finish.mdc)

After TypeScript changes, run lint/tests with Bun

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
{src,script,test}/**/*.{sol,ts}

📄 CodeRabbit inference engine (.cursor/rules/105-security.mdc)

Validate all external inputs and configuration (including script/env values) explicitly; prefer existing validation helpers (e.g., Validatable, config readers) over ad-hoc checks

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
{script,tasks}/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/200-typescript.mdc)

{script,tasks}/**/*.ts: TypeScript scripts must use .eslintrc.cjs rules, bunx tsx, citty, consola, and validate environment variables via helpers (e.g., getEnvVar())
MUST use viem for all contract interactions in demo/operational scripts; ethers.js helpers are deprecated
DO NOT use deprecated ethers-based helpers: getProvider, getWalletFromPrivateKeyInDotEnv, ethers sendTransaction, ensureBalanceAndAllowanceToDiamond
Obey .eslintrc.cjs rules; avoid any type; use TypeChain types from typechain/ directory (e.g., ILiFi.BridgeDataStruct)
Always reuse existing helpers and types: Search script/common/, script/utils/, script/demoScripts/utils/ before implementing new functionality. Key helpers include: script/utils/deploymentHelpers.ts, script/demoScripts/utils/demoScriptHelpers.ts, script/common/types.ts
Organize imports in groups: external libs (viem, consola, citty, dotenv) → TypeChain types → config files → internal utils/helpers. Use type imports for types-only
Use try/catch with consola.error() for error logging; exit with process.exit(1) on fatal errors. Provide meaningful error messages
Always check for existing types before defining new ones: Search in order - TypeChain types (typechain/), viem types, script/common/types.ts, domain-specific type files
Shared/cross-cutting types should be placed in script/common/types.ts (e.g., SupportedChain, INetwork, EnvironmentEnum); domain-specific types should be colocated in domain-specific files
Interfaces MUST start with I prefix (e.g., INetwork, ITransferResult, IValidationResults) - this is enforced by ESLint
Type aliases must use PascalCase without prefix (e.g., SupportedChain, HexString)
Enums must use PascalCase with Enum suffix (e.g., EnvironmentEnum)
Use citty for CLI, consola for logging, getEnvVar() for environment validation, and exit with 0/1 appropriately
New TypeScript helpers must be covered by a colocated *.test.ts file using B...

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
script/demoScripts/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/200-typescript.mdc)

Demo scripts follow structural patterns including main() function, setupEnvironment(), and helpers from demoScriptHelpers. Reference examples: demoLidoWrapper.ts, demoUnit.ts, demoEco.ts

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
🧠 Learnings (42)
📓 Common learnings
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must implement required functions: `_startBridge` (internal), `swapAndStartBridgeTokensVia{FacetName}`, and `startBridgeTokensVia{FacetName}`
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.
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)
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.
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: 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: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement internal `_swapAndCompleteBridgeTokens()` function that handles native vs ERC20 tokens: use `safeApproveWithRetry()` or `safeIncreaseAllowance()` for ERC20 (reset to 0 after), pass `value: amount` for native tokens, call `executor.swapAndCompleteBridgeTokens()` in try-catch block, and on failure send raw tokens to receiver and emit `LiFiTransferRecovered`
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: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement a bridge-specific external entry point (e.g., `handleV3AcrossMessage`, `lzCompose`, `cfReceive`) protected by authorization modifier that decodes bridge message to extract `bytes32 transactionId`, `LibSwap.SwapData[] memory swapData`, `address receiver`, and calls internal `_swapAndCompleteBridgeTokens()`
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Periphery/**/*.sol : Periphery contracts handle specialized flows that don't belong directly in the Diamond
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.
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/001-project-structure.mdc:0-0
Timestamp: 2025-12-17T10:27:05.481Z
Learning: Applies to src/Periphery/**/*.sol : Place new periphery contracts in the `src/Periphery/` directory. These are standalone contracts called by the Diamond but are not facets and can be upgraded independently.
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.
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/utils/lib/cowShedSdk.ts:0-0
Timestamp: 2025-06-05T14:50:17.275Z
Learning: For demo scripts and example code, ezynda3 prefers to keep the code simple and focused on demonstrating the core functionality rather than adding extensive input validation or defensive programming measures.
📚 Learning: 2025-12-29T10:09:07.294Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-29T10:09:07.294Z
Learning: Applies to script/demoScripts/**/*.ts : Demo scripts follow structural patterns including `main()` function, `setupEnvironment()`, and helpers from `demoScriptHelpers`. Reference examples: `demoLidoWrapper.ts`, `demoUnit.ts`, `demoEco.ts`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-29T10:09:07.294Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-29T10:09:07.294Z
Learning: Applies to {script,tasks}/**/*.ts : MUST use viem for all contract interactions in demo/operational scripts; ethers.js helpers are deprecated

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:27:05.481Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/001-project-structure.mdc:0-0
Timestamp: 2025-12-17T10:27:05.481Z
Learning: Applies to script/demoScripts/**/*.{ts,js} : Place TypeScript demo scripts in `script/demoScripts/` directory. Reference existing demos for patterns and place helper utilities in `script/demoScripts/utils/`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 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/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement internal `_swapAndCompleteBridgeTokens()` function that handles native vs ERC20 tokens: use `safeApproveWithRetry()` or `safeIncreaseAllowance()` for ERC20 (reset to 0 after), pass `value: amount` for native tokens, call `executor.swapAndCompleteBridgeTokens()` in try-catch block, and on failure send raw tokens to receiver and emit `LiFiTransferRecovered`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement a bridge-specific external entry point (e.g., `handleV3AcrossMessage`, `lzCompose`, `cfReceive`) protected by authorization modifier that decodes bridge message to extract `bytes32 transactionId`, `LibSwap.SwapData[] memory swapData`, `address receiver`, and calls internal `_swapAndCompleteBridgeTokens()`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-29T10:09:07.294Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-29T10:09:07.294Z
Learning: Applies to {script,tasks}/**/*.ts : DO NOT use deprecated ethers-based helpers: `getProvider`, `getWalletFromPrivateKeyInDotEnv`, ethers `sendTransaction`, `ensureBalanceAndAllowanceToDiamond`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-10-31T09:11:15.238Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 843
File: script/demoScripts/demoRelay.ts:27-89
Timestamp: 2024-10-31T09:11:15.238Z
Learning: When reviewing demo scripts in `script/demoScripts`, avoid refactoring suggestions for code reuse, as they may not be necessary.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-11-04T03:47:47.465Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 847
File: script/tasks/fundNewWalletOnAllChains.ts:156-164
Timestamp: 2024-11-04T03:47:47.465Z
Learning: In the `fundNewWalletOnAllChains.ts` script, the gas estimation code involving `publicClient.estimateGas()` is intentionally commented out and should remain that way unless specified otherwise.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2025-06-05T14:28:34.813Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/demoPatcher.ts:0-0
Timestamp: 2025-06-05T14:28:34.813Z
Learning: For demo scripts in the lifinance/contracts repository, simpler validation (like checking for zero address) is acceptable and additional contract code validation is not necessary.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-10-04T09:21:59.708Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/polygon.json:0-0
Timestamp: 2024-10-04T09:21:59.708Z
Learning: Ensure that scripts used for codebase verification produce valid and accurate results before reporting issues, especially when checking Ethereum address checksums in `deployments/polygon.json`.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-29T10:09:07.294Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-29T10:09:07.294Z
Learning: Applies to {script,tasks}/**/*.ts : Interfaces MUST start with `I` prefix (e.g., `INetwork`, `ITransferResult`, `IValidationResults`) - this is enforced by ESLint

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-24T08:52:48.554Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/101-solidity-contracts.mdc:0-0
Timestamp: 2025-12-24T08:52:48.554Z
Learning: Applies to src/**/*.sol : Apply Diamond patterns with existing libs (LibAsset/LibSwap/LibAllowList, Validatable/SwapperV2); prefer parameters over `msg.sender` for refund addresses.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-06-05T14:28:24.620Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/demoPatcher.ts:0-0
Timestamp: 2025-06-05T14:28:24.620Z
Learning: In demo scripts (files in script/demoScripts/ or similar demo contexts), unlimited token approvals using ethers.constants.MaxUint256 or type(uint256).max are acceptable for convenience, even though they would be flagged as security concerns in production code. The team acknowledges this is fine for demonstration purposes.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-01-22T12:40:50.355Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: script/demoScripts/demoGlacisAirlift.ts:42-59
Timestamp: 2025-01-22T12:40:50.355Z
Learning: In TypeScript/JavaScript demo scripts using ethers.js, nonce is automatically managed by the library and doesn't need to be explicitly set. Similarly, the default gas limit is typically sufficient for standard operations like ERC20 approvals.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-11-05T17:16:19.946Z
Learnt from: maxklenk
Repo: lifinance/contracts PR: 782
File: script/demoScripts/demoPermit2.ts:0-0
Timestamp: 2024-11-05T17:16:19.946Z
Learning: In `script/demoScripts/demoPermit2.ts`, the `nextNonce` function should be called on the `PERMIT2_PROXY_ADDRESS` because the nonce is stored in the proxy contract, not in the `Permit2` contract (`PERMIT2_ADDRESS`).

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-10-04T08:50:24.635Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/polygonzkevm.json:33-33
Timestamp: 2024-10-04T08:50:24.635Z
Learning: Ensure that the method used to check contract verification status on block explorers is accurate and reliable; improve it as needed for future analyses.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-29T12:28:41.835Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1555
File: script/playgroundHelpers.sh:60-68
Timestamp: 2025-12-29T12:28:41.835Z
Learning: In script/playgroundHelpers.sh at line 63 within the getContractVerified() function, the field `.CONSTRUCTOR_ARGS` should be updated to `.constructorArgs` (camelCase) to match the MongoDB IDeploymentRecord interface and be consistent with other field names in the same block (address, optimizerRuns, timestamp, salt, verified, solcVersion, evmVersion, zkSolcVersion). This inconsistency causes the field to return null. User mirooon requested this be flagged when playgroundHelpers.sh is modified in future PRs.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-07-17T04:21:55.549Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1266
File: script/deploy/safe/execute-pending-timelock-tx.ts:334-334
Timestamp: 2025-07-17T04:21:55.549Z
Learning: In the lifinance/contracts repository, 0xDEnYO prefers to keep private key processing simple in scripts like execute-pending-timelock-tx.ts without adding format validation, prioritizing code simplicity over strict validation in controlled environments.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-11-04T03:50:06.443Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 847
File: script/tasks/fundNewWalletOnAllChains.ts:179-187
Timestamp: 2024-11-04T03:50:06.443Z
Learning: In the `script/tasks/fundNewWalletOnAllChains.ts` file, adding a timeout to the transaction confirmation wait using `publicClient.waitForTransactionReceipt` is not required.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-08-26T02:20:52.515Z
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.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-10-04T09:17:19.275Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/avalanche.diamond.json:105-105
Timestamp: 2024-10-04T09:17:19.275Z
Learning: In the `lifinance/contracts` repository, contracts may have different addresses across networks. Do not check if contracts have the same addresses across all networks in future reviews.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-07-03T01:44:43.968Z
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.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-01-30T10:38:18.041Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: script/demoScripts/demoGlacis.ts:180-189
Timestamp: 2025-01-30T10:38:18.041Z
Learning: The executeTransaction helper function in the LiFi codebase handles error cases and transaction logging comprehensively, including try/catch structures, transaction receipt validation, and detailed console logging for transaction status tracking.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*Bridge*.sol : LiFiTransferStarted event must be emitted at the end of the internal _startBridge function in facets, after all validations and external bridge calls have completed successfully

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
🔇 Additional comments (4)
script/demoScripts/demoAcrossV4Swap.ts (4)

1-38: LGTM!

Imports are well-organized and correctly use viem for all utilities. The deprecated ethers imports have been properly removed, and helper imports follow the expected patterns from demoScriptHelpers.


87-189: LGTM!

Interface definitions follow the I prefix naming convention and provide comprehensive typing for the Across Swap API request/response structures.


200-236: LGTM!

The API fetch helper correctly constructs query parameters and handles error responses. Minimal error handling is acceptable for demo scripts per established patterns.


303-348: LGTM!

Configuration is well-structured with type-safe chain selection, environment-aware FeeCollector address resolution, and proper use of existing helper functions for config element lookup.

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

🧹 Nitpick comments (3)
src/Facets/AcrossV4SwapFacet.sol (2)

114-121: Consider also adjusting depositData.outputAmount proportionally.

When positive slippage occurs, minExpectedInputTokenAmount is adjusted proportionally, but depositData.outputAmount (the expected amount on the destination chain) remains unchanged. For consistency, consider also adjusting the output amount:

🔎 Proposed enhancement
         // Update minExpectedInputTokenAmount proportionally if there was positive slippage
         AcrossV4SwapData memory updatedAcrossData = _acrossV4SwapData;
         if (_bridgeData.minAmount > originalAmount) {
             updatedAcrossData.minExpectedInputTokenAmount =
                 (_acrossV4SwapData.minExpectedInputTokenAmount *
                     _bridgeData.minAmount) /
                 originalAmount;
+            updatedAcrossData.depositData.outputAmount =
+                (_acrossV4SwapData.depositData.outputAmount *
+                    _bridgeData.minAmount) /
+                originalAmount;
         }

134-140: Consider adding explicit check for native assets.

The facet calls maxApproveERC20 on sendingAssetId, which will fail confusingly if a native asset is passed. Since native bridging is not supported (as confirmed by test overrides), consider adding an explicit check to provide a clear error message:

🔎 Proposed enhancement
 function _startBridge(
     ILiFi.BridgeData memory _bridgeData,
     AcrossV4SwapData memory _acrossV4SwapData
 ) internal {
+    // This facet does not support native assets - use WETH
+    if (LibAsset.isNativeAsset(_bridgeData.sendingAssetId)) {
+        revert NativeAssetNotSupported();
+    }
+
     // Approve the periphery to spend tokens

Add the error to the contract:

error NativeAssetNotSupported();
test/solidity/Facets/AcrossV4SwapFacet.t.sol (1)

138-148: Inconsistent: comment says not supported but code still executes.

The comment states "Not supported for this facet" but the code still attempts the call. Since the base test is overridden, this won't execute in practice, but consider reverting or skipping for clarity:

🔎 Cleaner approach
         if (isNative) {
-            // Not supported for this facet
-            acrossV4SwapFacet.startBridgeTokensViaAcrossV4Swap{
-                value: bridgeData.minAmount
-            }(bridgeData, validAcrossV4SwapData);
+            // Native bridging not supported - this path shouldn't be reached
+            // since testBase_CanBridgeNativeTokens is overridden
+            revert("Native bridging not supported");
         } else {
📜 Review details

Configuration used: Repository 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 68c8cd4 and 76ac3ad.

📒 Files selected for processing (2)
  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
🧰 Additional context used
📓 Path-based instructions (11)
src/Facets/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

src/Facets/**/*.sol: Place new facets in the src/Facets/ directory and use plop templates if available for code generation
Keep facets thin and delegate complex logic to libraries. Group imports in order: external libs → interfaces → libraries → contracts

src/Facets/**/*.sol: Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)
Facets should contain thin, integration-specific logic only; do not move logic across layers without clear architectural reason

Files:

  • src/Facets/AcrossV4SwapFacet.sol
**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Use remappings defined in remappings.txt for imports: lifi/src/, test/test/, and external libs like @openzeppelin/, solmate/, solady/, permit2/

**/*.sol: Single Diamond (EIP-2535) as main entrypoint for all protocol interactions
Delegate complex logic to libraries (LibAsset, LibSwap, LibAllowList, SwapperV2, Validatable) and helper contracts

After Solidity changes, run forge test (or note suites remaining)

**/*.sol: Own files must use // SPDX-License-Identifier: LGPL-3.0-only immediately followed by the pragma statement with no blank line in between
All contracts must use pragma solidity ^0.8.17;
Functions and variables use camelCase; constants and immutables are CONSTANT_CASE
Function parameters use leading underscore (e.g., _amount)
Contracts and interfaces must include NatSpec: @title (matching contract/interface name), @author LI.FI (https://li.fi), @notice describing purpose, and @custom:version X.Y.Z
Public and external functions require NatSpec including params and returns documentation
For pure test/script scaffolding keep NatSpec headers minimal but retain SPDX and pragma
Use single blank lines between logical sections and between function declarations
Follow in-function blank-line rules: blank lines before emits/returns; no stray gaps
Use custom errors instead of revert strings; prefer existing errors/helpers before adding new ones
Use generic errors from src/Errors/GenericErrors.sol; bump @custom:version when adding; facet-specific errors stay local
Adhere to rules in .solhint.json
Avoid assembly unless necessary and heavily commented with justification (why assembly is needed); prefer existing helpers over new implementations

Do not mix interface and implementation in the same file

Files:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
**/*Swap*.sol

📄 CodeRabbit inference engine (.cursor/rules/002-architecture.mdc)

Emit GenericSwapCompleted event for same-chain swaps

Files:

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

📄 CodeRabbit inference engine (.cursor/rules/102-facets.mdc)

src/Facets/**/*Facet.sol: Facets must be located in src/Facets/ directory with names containing Facet
Facets must implement required functions: _startBridge (internal), swapAndStartBridgeTokensVia{FacetName}, and startBridgeTokensVia{FacetName}
Facets must use modifiers: nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps/doesContainSourceSwaps, doesNotContainDestinationCalls/doesContainDestinationCalls on applicable functions
In Solidity facets, receiverAddress must be the first parameter in {facetName}Data and must match bridgeData.receiver for EVM chains
In Solidity facets, validate targetChainId against bridgeData.destinationChain for EVM-to-EVM bridges
Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via _depositAndSwap variants when needed
In Solidity facets with minAmountOut or similar bridge parameters, update the bridge's minAmountOut in swapAndStartBridgeTokensVia{FacetName} to account for positive slippage from swaps after _depositAndSwap updates _bridgeData.minAmount, adjusting proportionally for decimal differences if applicable
For non-EVM receivers in Solidity facets, use bytes type; the value must be non-zero
For non-EVM flows in Solidity facets, bridgeData.receiver must equal NON_EVM_ADDRESS
In Solidity facets with {facetName}Data.receiverAddress field (e.g., _glacisData.receiverAddress), validate that it is not bytes32(0) for non-EVM chains and revert with InvalidNonEVMReceiver() if zero

Files:

  • src/Facets/AcrossV4SwapFacet.sol
{src,script,test}/**/*.{sol,ts}

📄 CodeRabbit inference engine (.cursor/rules/105-security.mdc)

Validate all external inputs and configuration (including script/env values) explicitly; prefer existing validation helpers (e.g., Validatable, config readers) over ad-hoc checks

Files:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
{src,script}/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/105-security.mdc)

{src,script}/**/*.sol: Do not weaken existing access controls, timelock flows, or Safe multisig protections; any change that touches admin-only functionality must call out its governance impact
Avoid introducing new external call patterns in facets or scripts without checking existing libraries (LibAsset, LibSwap, LibAllowList) for prior art

Files:

  • src/Facets/AcrossV4SwapFacet.sol
src/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/106-gas.mdc)

src/**/*.sol: Follow gas-related best practices in existing facets before introducing new micro-optimizations in Solidity
Prefer using existing optimized libraries already in the repo (e.g., Solady/Solmate utilities) where they are in use, rather than hand-rolled low-level code
Do not sacrifice readability or safety for minor gas wins; explain any non-obvious optimization and justify it with expected impact
Avoid introducing inline assembly unless clearly needed; when used, document assumptions and invariants thoroughly

All contracts in src/ require audits except Interfaces in src/Interfaces/** (type definitions only) and external dependencies in lib/

src/**/*.sol: NatSpec required on contracts/interfaces in src/: @title, @author LI.FI (https://li.fi), @notice, @custom:version X.Y.Z; document all public/external functions with params/returns.
Bug bounty clarity: In contract NatSpec, explicitly document whether the contract is intended to hold/custody funds. If not designed to hold funds, state clearly (e.g., 'This contract is not intended to custody user funds / hold balances; any funds held are incidental'). If designed to hold funds, describe what funds it holds and under what conditions.
Apply Diamond patterns with existing libs (LibAsset/LibSwap/LibAllowList, Validatable/SwapperV2); prefer parameters over msg.sender for refund addresses.
In Solidity 0.8.17, you must not emit events using ContractName.EventName syntax (e.g., emit SomeContract.SomeEvent(...)). Events must be defined in the same contract where they're emitted, or defined in an interface that the contract uses, and then emitted using just the event name (e.g., emit SomeEvent(...)). This prevents compilation errors and ensures 0.8.17 compatibility.

Files:

  • src/Facets/AcrossV4SwapFacet.sol
test/solidity/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Place test files in test/solidity/ mirroring the src/ directory structure for organization

Files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
**/test/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/103-solidity-interfaces.mdc)

Test interfaces may define inline interfaces as needed for testing purposes

Files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
test/**/*.t.sol

📄 CodeRabbit inference engine (.cursor/rules/400-solidity-tests.mdc)

test/**/*.t.sol: Tests under test/solidity/, mirroring src/ structure; require setUp() function; call initTestBase() when inheriting TestBase directly or indirectly; label actors with vm.label
For facet tests, inherit from TestBaseFacet rather than TestBase, since standard facet functions need to be overridden
Import ordering: system libraries first (e.g., forge-std, ds-test), then project files (e.g., lifi/, test/)
Test function names: test_ prefix for success tests, testRevert_ prefix for failure tests, testBase_ prefix for base tests
Test structure: setup → execute → assert; use vm.startPrank / vm.stopPrank, labels, and base inits
Always assert specific revert reasons; use vm.expectRevert with specific reason
Use vm.expectEmit(true, true, true, true, <addr>) for event assertions
Apply blank line conventions: add gap after vm.expectRevert before the call, and gap before assertions/events
For whitelist flows, inherit TestWhitelistManagerBase and use addToWhitelist / setFunctionWhitelistBySelector helpers
If a facet does not support native tokens, override tests such as testBase_CanSwapAndBridgeNativeTokens and testBase_CanBridgeNativeTokens with public override and include a comment explaining why the test is intentionally skipped

Files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
**/*.{test.ts,t.sol}

📄 CodeRabbit inference engine (.cursor/rules/401-testing-patterns.mdc)

**/*.{test.ts,t.sol}: Prefer adding or updating tests alongside logic changes
Keep tests structured as setup → execute → assert
Assert specific failure conditions (avoid overly-broad "catch-all" assertions)

Files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
🧠 Learnings (38)
📓 Common learnings
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must implement required functions: `_startBridge` (internal), `swapAndStartBridgeTokensVia{FacetName}`, and `startBridgeTokensVia{FacetName}`
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed
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.
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use modifiers: `nonReentrant`, `refundExcessNative`, `validateBridgeData`, `doesNotContainSourceSwaps`/`doesContainSourceSwaps`, `doesNotContainDestinationCalls`/`doesContainDestinationCalls` on applicable functions
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: 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: 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.
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement a bridge-specific external entry point (e.g., `handleV3AcrossMessage`, `lzCompose`, `cfReceive`) protected by authorization modifier that decodes bridge message to extract `bytes32 transactionId`, `LibSwap.SwapData[] memory swapData`, `address receiver`, and calls internal `_swapAndCompleteBridgeTokens()`
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.
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/001-project-structure.mdc:0-0
Timestamp: 2025-12-17T10:27:05.481Z
Learning: Applies to src/Periphery/**/*.sol : Place new periphery contracts in the `src/Periphery/` directory. These are standalone contracts called by the Diamond but are not facets and can be upgraded independently.
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Periphery/**/*.sol : Periphery contracts handle specialized flows that don't belong directly in the Diamond
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/utils/lib/cowShedSdk.ts:0-0
Timestamp: 2025-06-05T14:50:17.275Z
Learning: For demo scripts and example code, ezynda3 prefers to keep the code simple and focused on demonstrating the core functionality rather than adding extensive input validation or defensive programming measures.
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must implement required functions: `_startBridge` (internal), `swapAndStartBridgeTokensVia{FacetName}`, and `startBridgeTokensVia{FacetName}`

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement a bridge-specific external entry point (e.g., `handleV3AcrossMessage`, `lzCompose`, `cfReceive`) protected by authorization modifier that decodes bridge message to extract `bytes32 transactionId`, `LibSwap.SwapData[] memory swapData`, `address receiver`, and calls internal `_swapAndCompleteBridgeTokens()`

Applied to files:

  • src/Facets/AcrossV4SwapFacet.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:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use modifiers: `nonReentrant`, `refundExcessNative`, `validateBridgeData`, `doesNotContainSourceSwaps`/`doesContainSourceSwaps`, `doesNotContainDestinationCalls`/`doesContainDestinationCalls` on applicable functions

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.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:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 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:

  • src/Facets/AcrossV4SwapFacet.sol
  • test/solidity/Facets/AcrossV4SwapFacet.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:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-08-27T13:16:55.613Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/CoreRouteFacet.sol:0-0
Timestamp: 2025-08-27T13:16:55.613Z
Learning: In LDA (LiFi DEX Aggregator) contracts, using address(this).balance to route all available ETH including dust and deposits from previous calls is intentional design. LDA contracts should not hold any funds and are designed to route any accumulated ETH to prevent fund accumulation. This is a feature, not a security issue.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.sol
📚 Learning: 2025-07-17T04:21:55.549Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1266
File: script/deploy/safe/execute-pending-timelock-tx.ts:334-334
Timestamp: 2025-07-17T04:21:55.549Z
Learning: In the lifinance/contracts repository, 0xDEnYO prefers to keep private key processing simple in scripts like execute-pending-timelock-tx.ts without adding format validation, prioritizing code simplicity over strict validation in controlled environments.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-04-28T07:46:24.084Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1116
File: src/Libraries/LibAsset.sol:102-108
Timestamp: 2025-04-28T07:46:24.084Z
Learning: In the LiFi contracts, the `LibAsset.transferFromERC20` function is intentionally designed to accept arbitrary `from` parameters, with security ensured through a whitelist mechanism that controls which contracts can call this function.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 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:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-04-22T09:04:44.244Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1112
File: deployments/soneium.diamond.json:81-81
Timestamp: 2025-04-22T09:04:44.244Z
Learning: In the lifinance/contracts repository, it's normal and expected for periphery contracts to have empty address values in deployment files when they are not deployed on a particular network. This applies to all periphery contracts including ReceiverChainflip, ReceiverStargateV2, and others. PRs should not flag empty periphery contract addresses as issues.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 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:

  • src/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-24T08:52:48.554Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/101-solidity-contracts.mdc:0-0
Timestamp: 2025-12-24T08:52:48.554Z
Learning: Applies to src/**/*.sol : In Solidity 0.8.17, you must not emit events using `ContractName.EventName` syntax (e.g., `emit SomeContract.SomeEvent(...)`). Events must be defined in the same contract where they're emitted, or defined in an interface that the contract uses, and then emitted using just the event name (e.g., `emit SomeEvent(...)`). This prevents compilation errors and ensures 0.8.17 compatibility.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Periphery/Receiver*.sol : LiFiTransferRecovered event should only be emitted in Receiver contracts (src/Periphery/Receiver*.sol)

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must only emit `LiFiTransferRecovered` when swaps fail and raw bridged tokens are sent to receiver, with event signature: `LiFiTransferRecovered(bytes32 indexed transactionId, address receivingAssetId, address receiver, uint256 amount, uint256 timestamp)`

Applied to files:

  • src/Facets/AcrossV4SwapFacet.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:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must use try-catch for executor calls, always have fallback to send raw tokens on failure, and reset approvals to 0 after operations

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement internal `_swapAndCompleteBridgeTokens()` function that handles native vs ERC20 tokens: use `safeApproveWithRetry()` or `safeIncreaseAllowance()` for ERC20 (reset to 0 after), pass `value: amount` for native tokens, call `executor.swapAndCompleteBridgeTokens()` in try-catch block, and on failure send raw tokens to receiver and emit `LiFiTransferRecovered`

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to **/*.sol : Delegate complex logic to libraries (LibAsset, LibSwap, LibAllowList, SwapperV2, Validatable) and helper contracts

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-12T11:16:09.236Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1530
File: src/Interfaces/ICircleBridgeProxy.sol:20-29
Timestamp: 2025-12-12T11:16:09.236Z
Learning: In src/Interfaces/ICircleBridgeProxy.sol, ensure the ICircleBridgeProxy interface corresponds to Celer's CircleBridgeProxy contract (not Circle's native TokenMessenger). The depositForBurn signature must be: depositForBurn(uint256 _amount, uint64 _dstChid, bytes32 _mintRecipient, address _burnToken, uint256 _maxFee, uint32 _minFinalityThreshold) external. This change should be scoped specifically to this file; pattern is not needed since it targets a single file. This improves correctness by aligning the interface with the correct contract and parameter types (dst chain id as uint64, no bytes32 destinationCaller parameter).

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:29:29.239Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/400-solidity-tests.mdc:0-0
Timestamp: 2025-12-17T10:29:29.239Z
Learning: Applies to test/**/*.t.sol : If a facet does not support native tokens, override tests such as `testBase_CanSwapAndBridgeNativeTokens` and `testBase_CanBridgeNativeTokens` with `public override` and include a comment explaining why the test is intentionally skipped

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:29:29.239Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/400-solidity-tests.mdc:0-0
Timestamp: 2025-12-17T10:29:29.239Z
Learning: Applies to test/**/*.t.sol : For facet tests, inherit from `TestBaseFacet` rather than `TestBase`, since standard facet functions need to be overridden

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.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/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-15T09:02:31.300Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1530
File: test/solidity/Facets/CelerCircleBridgeFacet.t.sol:1-10
Timestamp: 2025-12-15T09:02:31.300Z
Learning: In Solidity test files under test/solidity/Facets (e.g., test/solidity/Facets/CelerCircleBridgeFacet.t.sol), ensure the SPDX license identifier line is immediately followed by the pragma statement with no blank line in between. Apply this formatting to all .sol files in that directory for consistency.

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets, validate `targetChainId` against `bridgeData.destinationChain` for EVM-to-EVM bridges

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-12-17T10:28:40.640Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/105-security.mdc:0-0
Timestamp: 2025-12-17T10:28:40.640Z
Learning: Applies to {src,script}/**/*.sol : Avoid introducing new external call patterns in facets or scripts without checking existing libraries (`LibAsset`, `LibSwap`, `LibAllowList`) for prior art

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
📚 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:

  • test/solidity/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.t.sol
📚 Learning: 2025-05-06T09:09:38.108Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1117
File: test/solidity/Periphery/LiFiDEXAggregator.t.sol:111-127
Timestamp: 2025-05-06T09:09:38.108Z
Learning: The `setupApechain()` function in LiFiDEXAggregator tests intentionally avoids calling `initTestBase()` to prevent needing to define standard contracts (like ADDRESS_USDC_PROXY and Uniswap) that aren't needed for Apechain-specific tests.

Applied to files:

  • test/solidity/Facets/AcrossV4SwapFacet.t.sol
🔇 Additional comments (10)
src/Facets/AcrossV4SwapFacet.sol (4)

1-12: LGTM!

License, pragma, and imports follow project conventions. Import ordering is correct with external libraries first.


14-20: LGTM!

NatSpec is complete with proper title, author, notice, version, and custody disclaimer. Contract correctly inherits the required base contracts (ILiFi, ReentrancyGuard, SwapperV2, Validatable).


49-63: LGTM!

Constructor validates both addresses are non-zero and uses the standard InvalidConfig error. Parameters follow naming conventions.


70-87: LGTM!

All required modifiers are present: nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps, and doesNotContainDestinationCalls. Implementation follows the standard pattern for bridge-only facet functions.

test/solidity/Facets/AcrossV4SwapFacet.t.sol (6)

1-8: LGTM!

License, pragma, and imports follow project conventions.


10-16: LGTM!

Standard test stub pattern combining the facet with whitelist management for testing.


44-127: LGTM!

Setup correctly calls initTestBase(), registers function selectors, configures whitelist entries, and labels addresses. The no-op swap approach for testing periphery integration is a pragmatic workaround for stale API data.


171-178: LGTM!

Native token tests are correctly overridden with empty bodies and explanatory comments, following the guidelines for facets that don't support native bridging.


180-211: LGTM!

Test functions follow naming conventions (test_ and testRevert_ prefixes), use specific revert selectors, and properly verify constructor behavior.


19-33: All hardcoded mainnet addresses in the test file are correct and match the configuration in config/across-v4-swap.json. The SPOKE_POOL_PERIPHERY and SPOKE_POOL addresses are consistent across both test and config files. Standard token addresses (WETH, USDC, USDT) and the Uniswap Universal Router are correctly set.

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)
script/demoScripts/demoAcrossV4Swap.ts (1)

268-301: Consider typing the decoded calldata for better IDE support.

The as any cast works but loses type safety. If you want to improve developer experience, you could define a type for the decoded structure:

interface SwapAndDepositData {
  swapToken: string
  exchange: string
  transferType: number
  routerCalldata: string
  minExpectedInputTokenAmount: bigint
  depositData: {
    inputToken: string
    outputToken: string
    outputAmount: bigint
    depositor: string
    recipient: string
    destinationChainId: bigint
    exclusiveRelayer: string
    quoteTimestamp: number
    fillDeadline: number
    exclusivityParameter: number
    message: string
  }
}

const swapData = decoded.args[0] as SwapAndDepositData

This is optional for demo scripts. Based on learnings, simpler code is acceptable here.

📜 Review details

Configuration used: Repository 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 76ac3ad and 5a77143.

📒 Files selected for processing (1)
  • script/demoScripts/demoAcrossV4Swap.ts
🧰 Additional context used
📓 Path-based instructions (5)
script/demoScripts/**/*.{ts,js}

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Place TypeScript demo scripts in script/demoScripts/ directory. Reference existing demos for patterns and place helper utilities in script/demoScripts/utils/

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/099-finish.mdc)

After TypeScript changes, run lint/tests with Bun

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
{src,script,test}/**/*.{sol,ts}

📄 CodeRabbit inference engine (.cursor/rules/105-security.mdc)

Validate all external inputs and configuration (including script/env values) explicitly; prefer existing validation helpers (e.g., Validatable, config readers) over ad-hoc checks

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
{script,tasks}/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/200-typescript.mdc)

{script,tasks}/**/*.ts: TypeScript scripts must use .eslintrc.cjs rules, bunx tsx, citty, consola, and validate environment variables via helpers (e.g., getEnvVar())
MUST use viem for all contract interactions in demo/operational scripts; ethers.js helpers are deprecated
DO NOT use deprecated ethers-based helpers: getProvider, getWalletFromPrivateKeyInDotEnv, ethers sendTransaction, ensureBalanceAndAllowanceToDiamond
Obey .eslintrc.cjs rules; avoid any type; use TypeChain types from typechain/ directory (e.g., ILiFi.BridgeDataStruct)
Always reuse existing helpers and types: Search script/common/, script/utils/, script/demoScripts/utils/ before implementing new functionality. Key helpers include: script/utils/deploymentHelpers.ts, script/demoScripts/utils/demoScriptHelpers.ts, script/common/types.ts
Organize imports in groups: external libs (viem, consola, citty, dotenv) → TypeChain types → config files → internal utils/helpers. Use type imports for types-only
Use try/catch with consola.error() for error logging; exit with process.exit(1) on fatal errors. Provide meaningful error messages
Always check for existing types before defining new ones: Search in order - TypeChain types (typechain/), viem types, script/common/types.ts, domain-specific type files
Shared/cross-cutting types should be placed in script/common/types.ts (e.g., SupportedChain, INetwork, EnvironmentEnum); domain-specific types should be colocated in domain-specific files
Interfaces MUST start with I prefix (e.g., INetwork, ITransferResult, IValidationResults) - this is enforced by ESLint
Type aliases must use PascalCase without prefix (e.g., SupportedChain, HexString)
Enums must use PascalCase with Enum suffix (e.g., EnvironmentEnum)
Use citty for CLI, consola for logging, getEnvVar() for environment validation, and exit with 0/1 appropriately
New TypeScript helpers must be covered by a colocated *.test.ts file using B...

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
script/demoScripts/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/200-typescript.mdc)

Demo scripts follow structural patterns including main() function, setupEnvironment(), and helpers from demoScriptHelpers. Reference examples: demoLidoWrapper.ts, demoUnit.ts, demoEco.ts

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
🧠 Learnings (40)
📓 Common learnings
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must implement required functions: `_startBridge` (internal), `swapAndStartBridgeTokensVia{FacetName}`, and `startBridgeTokensVia{FacetName}`
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.
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)
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: 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.
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.
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: 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: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/utils/lib/cowShedSdk.ts:0-0
Timestamp: 2025-06-05T14:50:17.275Z
Learning: For demo scripts and example code, ezynda3 prefers to keep the code simple and focused on demonstrating the core functionality rather than adding extensive input validation or defensive programming measures.
📚 Learning: 2025-12-29T10:09:07.294Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-29T10:09:07.294Z
Learning: Applies to script/demoScripts/**/*.ts : Demo scripts follow structural patterns including `main()` function, `setupEnvironment()`, and helpers from `demoScriptHelpers`. Reference examples: `demoLidoWrapper.ts`, `demoUnit.ts`, `demoEco.ts`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-29T10:09:07.294Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-29T10:09:07.294Z
Learning: Applies to {script,tasks}/**/*.ts : MUST use viem for all contract interactions in demo/operational scripts; ethers.js helpers are deprecated

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement internal `_swapAndCompleteBridgeTokens()` function that handles native vs ERC20 tokens: use `safeApproveWithRetry()` or `safeIncreaseAllowance()` for ERC20 (reset to 0 after), pass `value: amount` for native tokens, call `executor.swapAndCompleteBridgeTokens()` in try-catch block, and on failure send raw tokens to receiver and emit `LiFiTransferRecovered`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:27:05.481Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/001-project-structure.mdc:0-0
Timestamp: 2025-12-17T10:27:05.481Z
Learning: Applies to script/demoScripts/**/*.{ts,js} : Place TypeScript demo scripts in `script/demoScripts/` directory. Reference existing demos for patterns and place helper utilities in `script/demoScripts/utils/`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement a bridge-specific external entry point (e.g., `handleV3AcrossMessage`, `lzCompose`, `cfReceive`) protected by authorization modifier that decodes bridge message to extract `bytes32 transactionId`, `LibSwap.SwapData[] memory swapData`, `address receiver`, and calls internal `_swapAndCompleteBridgeTokens()`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-29T10:09:07.294Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-29T10:09:07.294Z
Learning: Applies to {script,tasks}/**/*.ts : DO NOT use deprecated ethers-based helpers: `getProvider`, `getWalletFromPrivateKeyInDotEnv`, ethers `sendTransaction`, `ensureBalanceAndAllowanceToDiamond`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-10-31T09:11:15.238Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 843
File: script/demoScripts/demoRelay.ts:27-89
Timestamp: 2024-10-31T09:11:15.238Z
Learning: When reviewing demo scripts in `script/demoScripts`, avoid refactoring suggestions for code reuse, as they may not be necessary.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-11-04T03:47:47.465Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 847
File: script/tasks/fundNewWalletOnAllChains.ts:156-164
Timestamp: 2024-11-04T03:47:47.465Z
Learning: In the `fundNewWalletOnAllChains.ts` script, the gas estimation code involving `publicClient.estimateGas()` is intentionally commented out and should remain that way unless specified otherwise.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2025-06-05T14:28:34.813Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/demoPatcher.ts:0-0
Timestamp: 2025-06-05T14:28:34.813Z
Learning: For demo scripts in the lifinance/contracts repository, simpler validation (like checking for zero address) is acceptable and additional contract code validation is not necessary.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2024-10-04T09:21:59.708Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/polygon.json:0-0
Timestamp: 2024-10-04T09:21:59.708Z
Learning: Ensure that scripts used for codebase verification produce valid and accurate results before reporting issues, especially when checking Ethereum address checksums in `deployments/polygon.json`.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-09-23T02:04:15.621Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: src/Periphery/GasZipPeriphery.sol:64-64
Timestamp: 2024-09-23T02:04:15.621Z
Learning: In the `depositToGasZipERC20` function, checking if `swapOutputAmount` is greater than zero after decoding is not required to avoid unnecessary gas consumption.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-24T08:52:48.554Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/101-solidity-contracts.mdc:0-0
Timestamp: 2025-12-24T08:52:48.554Z
Learning: Applies to src/**/*.sol : Apply Diamond patterns with existing libs (LibAsset/LibSwap/LibAllowList, Validatable/SwapperV2); prefer parameters over `msg.sender` for refund addresses.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-06-05T14:28:24.620Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/demoPatcher.ts:0-0
Timestamp: 2025-06-05T14:28:24.620Z
Learning: In demo scripts (files in script/demoScripts/ or similar demo contexts), unlimited token approvals using ethers.constants.MaxUint256 or type(uint256).max are acceptable for convenience, even though they would be flagged as security concerns in production code. The team acknowledges this is fine for demonstration purposes.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-01-22T12:40:50.355Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: script/demoScripts/demoGlacisAirlift.ts:42-59
Timestamp: 2025-01-22T12:40:50.355Z
Learning: In TypeScript/JavaScript demo scripts using ethers.js, nonce is automatically managed by the library and doesn't need to be explicitly set. Similarly, the default gas limit is typically sufficient for standard operations like ERC20 approvals.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-11-05T17:16:19.946Z
Learnt from: maxklenk
Repo: lifinance/contracts PR: 782
File: script/demoScripts/demoPermit2.ts:0-0
Timestamp: 2024-11-05T17:16:19.946Z
Learning: In `script/demoScripts/demoPermit2.ts`, the `nextNonce` function should be called on the `PERMIT2_PROXY_ADDRESS` because the nonce is stored in the proxy contract, not in the `Permit2` contract (`PERMIT2_ADDRESS`).

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-10-04T08:50:24.635Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/polygonzkevm.json:33-33
Timestamp: 2024-10-04T08:50:24.635Z
Learning: Ensure that the method used to check contract verification status on block explorers is accurate and reliable; improve it as needed for future analyses.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-29T12:28:41.835Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1555
File: script/playgroundHelpers.sh:60-68
Timestamp: 2025-12-29T12:28:41.835Z
Learning: In script/playgroundHelpers.sh at line 63 within the getContractVerified() function, the field `.CONSTRUCTOR_ARGS` should be updated to `.constructorArgs` (camelCase) to match the MongoDB IDeploymentRecord interface and be consistent with other field names in the same block (address, optimizerRuns, timestamp, salt, verified, solcVersion, evmVersion, zkSolcVersion). This inconsistency causes the field to return null. User mirooon requested this be flagged when playgroundHelpers.sh is modified in future PRs.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-07-17T04:21:55.549Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1266
File: script/deploy/safe/execute-pending-timelock-tx.ts:334-334
Timestamp: 2025-07-17T04:21:55.549Z
Learning: In the lifinance/contracts repository, 0xDEnYO prefers to keep private key processing simple in scripts like execute-pending-timelock-tx.ts without adding format validation, prioritizing code simplicity over strict validation in controlled environments.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-11-04T03:50:06.443Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 847
File: script/tasks/fundNewWalletOnAllChains.ts:179-187
Timestamp: 2024-11-04T03:50:06.443Z
Learning: In the `script/tasks/fundNewWalletOnAllChains.ts` file, adding a timeout to the transaction confirmation wait using `publicClient.waitForTransactionReceipt` is not required.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-08-26T02:20:52.515Z
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.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-10-04T09:17:19.275Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/avalanche.diamond.json:105-105
Timestamp: 2024-10-04T09:17:19.275Z
Learning: In the `lifinance/contracts` repository, contracts may have different addresses across networks. Do not check if contracts have the same addresses across all networks in future reviews.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-07-03T01:44:43.968Z
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.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-01-30T10:38:18.041Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: script/demoScripts/demoGlacis.ts:180-189
Timestamp: 2025-01-30T10:38:18.041Z
Learning: The executeTransaction helper function in the LiFi codebase handles error cases and transaction logging comprehensively, including try/catch structures, transaction receipt validation, and detailed console logging for transaction status tracking.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*Bridge*.sol : LiFiTransferStarted event must be emitted at the end of the internal _startBridge function in facets, after all validations and external bridge calls have completed successfully

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
🔇 Additional comments (5)
script/demoScripts/demoAcrossV4Swap.ts (5)

1-38: LGTM!

Imports are well-organized following the guideline pattern (external libs → config files → TypeChain types → internal helpers) and correctly use viem instead of deprecated ethers.


87-189: LGTM!

Type definitions are well-structured with proper I prefix convention and comprehensive coverage of the Across Swap API request/response shapes.


653-678: LGTM!

Transaction execution correctly uses viem's contract write methods via the executeTransaction helper, handles both fee-collection and direct bridge paths, and properly captures the transaction hash for the explorer URL output.


350-384: LGTM!

The main function correctly follows the demo script structural pattern with setupEnvironment() initialization, proper client/account destructuring, and clear configuration logging.


686-694: LGTM!

Script execution properly handles success/failure with appropriate exit codes and error logging via consola.error().

…wapFacet

- Add destinationChainId mismatch validation between bridgeData and acrossV4SwapData
- Add recipient validation to ensure bridgeData.receiver matches depositData.recipient
- Add _convertAddressToBytes32 helper function
- Fix step number mismatch in demo script console logs
@ezynda3 ezynda3 marked this pull request as ready for review December 30, 2025 14:13
@lifi-action-bot
Copy link
Collaborator

🤖 GitHub Action: Security Alerts Review 🔍

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

🟢 View Alert - File: src/Facets/AcrossV4SwapFacet.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: Won't fix
🔹 Dismiss Comment: This is fine

🟢 View Alert - File: src/Facets/AcrossV4SwapFacet.sol
🔹 Contracts that can receive ether but cannot send it may lock value permanently. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/locked-ether
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: This is a facet contract as part of a diamond proxy which does not not need to be able to receive ETH directly

No unresolved security alerts! 🎉

@lifi-action-bot lifi-action-bot changed the title Add AcrossV4SwapFacet for Across Protocol swap-and-bridge integration [AcrossV4SwapFacet v1.0.0, ISpokePoolPeriphery v1.0.0] Add AcrossV4SwapFacet for Across Protocol swap-and-bridge integration [AcrossV4SwapFacet v1.0.1, ISpokePoolPeriphery v1.0.0] Dec 30, 2025
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

🧹 Nitpick comments (3)
src/Facets/AcrossV4SwapFacet.sol (1)

180-184: Emit LiFiTransferStarted after the external bridge call.

Lines 180-184 emit the LiFiTransferStarted event before calling SPOKE_POOL_PERIPHERY.swapAndBridge(). Per facet guidelines, the event should be emitted at the end of _startBridge after all validations and external calls complete successfully.

🔎 Recommended fix
-    // Emit event before external call for proper event ordering
-    emit LiFiTransferStarted(_bridgeData);
-
     // Call the periphery's swapAndBridge function
     SPOKE_POOL_PERIPHERY.swapAndBridge(swapAndDepositData);
+
+    // Emit event after successful external call
+    emit LiFiTransferStarted(_bridgeData);

Based on learnings, facets should emit LiFiTransferStarted at the end of _startBridge after all operations complete.

script/demoScripts/demoAcrossV4Swap.ts (2)

268-278: Consider typing the decoded args explicitly.

Line 278 uses as any to access decoded arguments. While acceptable for demo scripts, you could define an interface for the decoded structure to improve type safety.

🔎 Optional improvement
interface ISwapAndDepositData {
  swapToken: string
  exchange: string
  transferType: number
  routerCalldata: string
  minExpectedInputTokenAmount: bigint
  depositData: {
    inputToken: string
    outputToken: string
    outputAmount: bigint
    depositor: string
    recipient: string
    destinationChainId: bigint
    exclusiveRelayer: string
    quoteTimestamp: number
    fillDeadline: number
    exclusivityParameter: number
    message: string
  }
}

// Then use:
const swapData = decoded.args[0] as ISwapAndDepositData

Per coding guidelines, avoiding any is preferred, but for demo scripts simplicity is acceptable.


653-677: Consider properly typing the contract for method calls.

Lines 656 and 670 use (lifiDiamondContract as any) to access write methods. While acceptable for demo scripts, the contract could be properly typed using the imported AcrossV4SwapFacet type from TypeChain.

The current approach works but bypasses TypeScript's type checking. For a production script, consider casting lifiDiamondContract to the appropriate TypeChain type to enable autocomplete and type safety.

Per coding guidelines, prefer TypeChain types over any, but for demo scripts simplicity is acceptable.

📜 Review details

Configuration used: Repository 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 5a77143 and 4f39cb8.

📒 Files selected for processing (2)
  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
🧰 Additional context used
📓 Path-based instructions (11)
script/demoScripts/**/*.{ts,js}

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Place TypeScript demo scripts in script/demoScripts/ directory. Reference existing demos for patterns and place helper utilities in script/demoScripts/utils/

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/099-finish.mdc)

After TypeScript changes, run lint/tests with Bun

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
{src,script,test}/**/*.{sol,ts}

📄 CodeRabbit inference engine (.cursor/rules/105-security.mdc)

Validate all external inputs and configuration (including script/env values) explicitly; prefer existing validation helpers (e.g., Validatable, config readers) over ad-hoc checks

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
{script,tasks}/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/200-typescript.mdc)

{script,tasks}/**/*.ts: TypeScript scripts must use .eslintrc.cjs rules, bunx tsx, citty, consola, and validate environment variables via helpers (e.g., getEnvVar())
MUST use viem for all contract interactions in demo/operational scripts; ethers.js helpers are deprecated
DO NOT use deprecated ethers-based helpers: getProvider, getWalletFromPrivateKeyInDotEnv, ethers sendTransaction, ensureBalanceAndAllowanceToDiamond
Obey .eslintrc.cjs rules; avoid any type; use TypeChain types from typechain/ directory (e.g., ILiFi.BridgeDataStruct)
Always reuse existing helpers and types: Search script/common/, script/utils/, script/demoScripts/utils/ before implementing new functionality. Key helpers include: script/utils/deploymentHelpers.ts, script/demoScripts/utils/demoScriptHelpers.ts, script/common/types.ts
Organize imports in groups: external libs (viem, consola, citty, dotenv) → TypeChain types → config files → internal utils/helpers. Use type imports for types-only
Use try/catch with consola.error() for error logging; exit with process.exit(1) on fatal errors. Provide meaningful error messages
Always check for existing types before defining new ones: Search in order - TypeChain types (typechain/), viem types, script/common/types.ts, domain-specific type files
Shared/cross-cutting types should be placed in script/common/types.ts (e.g., SupportedChain, INetwork, EnvironmentEnum); domain-specific types should be colocated in domain-specific files
Interfaces MUST start with I prefix (e.g., INetwork, ITransferResult, IValidationResults) - this is enforced by ESLint
Type aliases must use PascalCase without prefix (e.g., SupportedChain, HexString)
Enums must use PascalCase with Enum suffix (e.g., EnvironmentEnum)
Use citty for CLI, consola for logging, getEnvVar() for environment validation, and exit with 0/1 appropriately
New TypeScript helpers must be covered by a colocated *.test.ts file using B...

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
script/demoScripts/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/200-typescript.mdc)

Demo scripts follow structural patterns including main() function, setupEnvironment(), and helpers from demoScriptHelpers. Reference examples: demoLidoWrapper.ts, demoUnit.ts, demoEco.ts

Files:

  • script/demoScripts/demoAcrossV4Swap.ts
src/Facets/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

src/Facets/**/*.sol: Place new facets in the src/Facets/ directory and use plop templates if available for code generation
Keep facets thin and delegate complex logic to libraries. Group imports in order: external libs → interfaces → libraries → contracts

src/Facets/**/*.sol: Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)
Facets should contain thin, integration-specific logic only; do not move logic across layers without clear architectural reason

Files:

  • src/Facets/AcrossV4SwapFacet.sol
**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)

Use remappings defined in remappings.txt for imports: lifi/src/, test/test/, and external libs like @openzeppelin/, solmate/, solady/, permit2/

**/*.sol: Single Diamond (EIP-2535) as main entrypoint for all protocol interactions
Delegate complex logic to libraries (LibAsset, LibSwap, LibAllowList, SwapperV2, Validatable) and helper contracts

After Solidity changes, run forge test (or note suites remaining)

**/*.sol: Own files must use // SPDX-License-Identifier: LGPL-3.0-only immediately followed by the pragma statement with no blank line in between
All contracts must use pragma solidity ^0.8.17;
Functions and variables use camelCase; constants and immutables are CONSTANT_CASE
Function parameters use leading underscore (e.g., _amount)
Contracts and interfaces must include NatSpec: @title (matching contract/interface name), @author LI.FI (https://li.fi), @notice describing purpose, and @custom:version X.Y.Z
Public and external functions require NatSpec including params and returns documentation
For pure test/script scaffolding keep NatSpec headers minimal but retain SPDX and pragma
Use single blank lines between logical sections and between function declarations
Follow in-function blank-line rules: blank lines before emits/returns; no stray gaps
Use custom errors instead of revert strings; prefer existing errors/helpers before adding new ones
Use generic errors from src/Errors/GenericErrors.sol; bump @custom:version when adding; facet-specific errors stay local
Adhere to rules in .solhint.json
Avoid assembly unless necessary and heavily commented with justification (why assembly is needed); prefer existing helpers over new implementations

Do not mix interface and implementation in the same file

Files:

  • src/Facets/AcrossV4SwapFacet.sol
**/*Swap*.sol

📄 CodeRabbit inference engine (.cursor/rules/002-architecture.mdc)

Emit GenericSwapCompleted event for same-chain swaps

Files:

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

📄 CodeRabbit inference engine (.cursor/rules/102-facets.mdc)

src/Facets/**/*Facet.sol: Facets must be located in src/Facets/ directory with names containing Facet
Facets must implement required functions: _startBridge (internal), swapAndStartBridgeTokensVia{FacetName}, and startBridgeTokensVia{FacetName}
Facets must use modifiers: nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps/doesContainSourceSwaps, doesNotContainDestinationCalls/doesContainDestinationCalls on applicable functions
In Solidity facets, receiverAddress must be the first parameter in {facetName}Data and must match bridgeData.receiver for EVM chains
In Solidity facets, validate targetChainId against bridgeData.destinationChain for EVM-to-EVM bridges
Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via _depositAndSwap variants when needed
In Solidity facets with minAmountOut or similar bridge parameters, update the bridge's minAmountOut in swapAndStartBridgeTokensVia{FacetName} to account for positive slippage from swaps after _depositAndSwap updates _bridgeData.minAmount, adjusting proportionally for decimal differences if applicable
For non-EVM receivers in Solidity facets, use bytes type; the value must be non-zero
For non-EVM flows in Solidity facets, bridgeData.receiver must equal NON_EVM_ADDRESS
In Solidity facets with {facetName}Data.receiverAddress field (e.g., _glacisData.receiverAddress), validate that it is not bytes32(0) for non-EVM chains and revert with InvalidNonEVMReceiver() if zero

Files:

  • src/Facets/AcrossV4SwapFacet.sol
{src,script}/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/105-security.mdc)

{src,script}/**/*.sol: Do not weaken existing access controls, timelock flows, or Safe multisig protections; any change that touches admin-only functionality must call out its governance impact
Avoid introducing new external call patterns in facets or scripts without checking existing libraries (LibAsset, LibSwap, LibAllowList) for prior art

Files:

  • src/Facets/AcrossV4SwapFacet.sol
src/**/*.sol

📄 CodeRabbit inference engine (.cursor/rules/106-gas.mdc)

src/**/*.sol: Follow gas-related best practices in existing facets before introducing new micro-optimizations in Solidity
Prefer using existing optimized libraries already in the repo (e.g., Solady/Solmate utilities) where they are in use, rather than hand-rolled low-level code
Do not sacrifice readability or safety for minor gas wins; explain any non-obvious optimization and justify it with expected impact
Avoid introducing inline assembly unless clearly needed; when used, document assumptions and invariants thoroughly

All contracts in src/ require audits except Interfaces in src/Interfaces/** (type definitions only) and external dependencies in lib/

src/**/*.sol: NatSpec required on contracts/interfaces in src/: @title, @author LI.FI (https://li.fi), @notice, @custom:version X.Y.Z; document all public/external functions with params/returns.
Bug bounty clarity: In contract NatSpec, explicitly document whether the contract is intended to hold/custody funds. If not designed to hold funds, state clearly (e.g., 'This contract is not intended to custody user funds / hold balances; any funds held are incidental'). If designed to hold funds, describe what funds it holds and under what conditions.
Apply Diamond patterns with existing libs (LibAsset/LibSwap/LibAllowList, Validatable/SwapperV2); prefer parameters over msg.sender for refund addresses.
In Solidity 0.8.17, you must not emit events using ContractName.EventName syntax (e.g., emit SomeContract.SomeEvent(...)). Events must be defined in the same contract where they're emitted, or defined in an interface that the contract uses, and then emitted using just the event name (e.g., emit SomeEvent(...)). This prevents compilation errors and ensures 0.8.17 compatibility.

Files:

  • src/Facets/AcrossV4SwapFacet.sol
🧠 Learnings (71)
📓 Common learnings
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must implement required functions: `_startBridge` (internal), `swapAndStartBridgeTokensVia{FacetName}`, and `startBridgeTokensVia{FacetName}`
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed
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.
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)
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: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets, validate `targetChainId` against `bridgeData.destinationChain` for EVM-to-EVM bridges
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: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement a bridge-specific external entry point (e.g., `handleV3AcrossMessage`, `lzCompose`, `cfReceive`) protected by authorization modifier that decodes bridge message to extract `bytes32 transactionId`, `LibSwap.SwapData[] memory swapData`, `address receiver`, and calls internal `_swapAndCompleteBridgeTokens()`
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.
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.
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/utils/lib/cowShedSdk.ts:0-0
Timestamp: 2025-06-05T14:50:17.275Z
Learning: For demo scripts and example code, ezynda3 prefers to keep the code simple and focused on demonstrating the core functionality rather than adding extensive input validation or defensive programming measures.
📚 Learning: 2025-12-29T10:09:07.294Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-29T10:09:07.294Z
Learning: Applies to script/demoScripts/**/*.ts : Demo scripts follow structural patterns including `main()` function, `setupEnvironment()`, and helpers from `demoScriptHelpers`. Reference examples: `demoLidoWrapper.ts`, `demoUnit.ts`, `demoEco.ts`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-29T10:09:07.294Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-29T10:09:07.294Z
Learning: Applies to {script,tasks}/**/*.ts : MUST use viem for all contract interactions in demo/operational scripts; ethers.js helpers are deprecated

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:27:05.481Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/001-project-structure.mdc:0-0
Timestamp: 2025-12-17T10:27:05.481Z
Learning: Applies to script/demoScripts/**/*.{ts,js} : Place TypeScript demo scripts in `script/demoScripts/` directory. Reference existing demos for patterns and place helper utilities in `script/demoScripts/utils/`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement internal `_swapAndCompleteBridgeTokens()` function that handles native vs ERC20 tokens: use `safeApproveWithRetry()` or `safeIncreaseAllowance()` for ERC20 (reset to 0 after), pass `value: amount` for native tokens, call `executor.swapAndCompleteBridgeTokens()` in try-catch block, and on failure send raw tokens to receiver and emit `LiFiTransferRecovered`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-29T10:09:07.294Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-29T10:09:07.294Z
Learning: Applies to {script,tasks}/**/*.ts : Obey `.eslintrc.cjs` rules; avoid `any` type; use TypeChain types from `typechain/` directory (e.g., `ILiFi.BridgeDataStruct`)

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:40.640Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/105-security.mdc:0-0
Timestamp: 2025-12-17T10:28:40.640Z
Learning: Applies to {src,script}/**/*.sol : Avoid introducing new external call patterns in facets or scripts without checking existing libraries (`LibAsset`, `LibSwap`, `LibAllowList`) for prior art

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2025-12-29T10:09:07.294Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/200-typescript.mdc:0-0
Timestamp: 2025-12-29T10:09:07.294Z
Learning: Applies to {script,tasks}/**/*.ts : DO NOT use deprecated ethers-based helpers: `getProvider`, `getWalletFromPrivateKeyInDotEnv`, ethers `sendTransaction`, `ensureBalanceAndAllowanceToDiamond`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-10-31T09:11:15.238Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 843
File: script/demoScripts/demoRelay.ts:27-89
Timestamp: 2024-10-31T09:11:15.238Z
Learning: When reviewing demo scripts in `script/demoScripts`, avoid refactoring suggestions for code reuse, as they may not be necessary.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-11-04T03:47:47.465Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 847
File: script/tasks/fundNewWalletOnAllChains.ts:156-164
Timestamp: 2024-11-04T03:47:47.465Z
Learning: In the `fundNewWalletOnAllChains.ts` script, the gas estimation code involving `publicClient.estimateGas()` is intentionally commented out and should remain that way unless specified otherwise.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2025-06-05T14:28:34.813Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/demoPatcher.ts:0-0
Timestamp: 2025-06-05T14:28:34.813Z
Learning: For demo scripts in the lifinance/contracts repository, simpler validation (like checking for zero address) is acceptable and additional contract code validation is not necessary.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.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/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must implement a bridge-specific external entry point (e.g., `handleV3AcrossMessage`, `lzCompose`, `cfReceive`) protected by authorization modifier that decodes bridge message to extract `bytes32 transactionId`, `LibSwap.SwapData[] memory swapData`, `address receiver`, and calls internal `_swapAndCompleteBridgeTokens()`

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2024-10-04T09:21:59.708Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/polygon.json:0-0
Timestamp: 2024-10-04T09:21:59.708Z
Learning: Ensure that scripts used for codebase verification produce valid and accurate results before reporting issues, especially when checking Ethereum address checksums in `deployments/polygon.json`.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-09-23T02:04:15.621Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 807
File: src/Periphery/GasZipPeriphery.sol:64-64
Timestamp: 2024-09-23T02:04:15.621Z
Learning: In the `depositToGasZipERC20` function, checking if `swapOutputAmount` is greater than zero after decoding is not required to avoid unnecessary gas consumption.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-24T08:52:48.554Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/101-solidity-contracts.mdc:0-0
Timestamp: 2025-12-24T08:52:48.554Z
Learning: Applies to src/**/*.sol : Apply Diamond patterns with existing libs (LibAsset/LibSwap/LibAllowList, Validatable/SwapperV2); prefer parameters over `msg.sender` for refund addresses.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-06-05T14:28:24.620Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1124
File: script/demoScripts/demoPatcher.ts:0-0
Timestamp: 2025-06-05T14:28:24.620Z
Learning: In demo scripts (files in script/demoScripts/ or similar demo contexts), unlimited token approvals using ethers.constants.MaxUint256 or type(uint256).max are acceptable for convenience, even though they would be flagged as security concerns in production code. The team acknowledges this is fine for demonstration purposes.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-01-22T12:40:50.355Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: script/demoScripts/demoGlacisAirlift.ts:42-59
Timestamp: 2025-01-22T12:40:50.355Z
Learning: In TypeScript/JavaScript demo scripts using ethers.js, nonce is automatically managed by the library and doesn't need to be explicitly set. Similarly, the default gas limit is typically sufficient for standard operations like ERC20 approvals.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-11-05T17:16:19.946Z
Learnt from: maxklenk
Repo: lifinance/contracts PR: 782
File: script/demoScripts/demoPermit2.ts:0-0
Timestamp: 2024-11-05T17:16:19.946Z
Learning: In `script/demoScripts/demoPermit2.ts`, the `nextNonce` function should be called on the `PERMIT2_PROXY_ADDRESS` because the nonce is stored in the proxy contract, not in the `Permit2` contract (`PERMIT2_ADDRESS`).

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.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:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2024-10-04T08:50:24.635Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/polygonzkevm.json:33-33
Timestamp: 2024-10-04T08:50:24.635Z
Learning: Ensure that the method used to check contract verification status on block explorers is accurate and reliable; improve it as needed for future analyses.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-07-17T04:21:55.549Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1266
File: script/deploy/safe/execute-pending-timelock-tx.ts:334-334
Timestamp: 2025-07-17T04:21:55.549Z
Learning: In the lifinance/contracts repository, 0xDEnYO prefers to keep private key processing simple in scripts like execute-pending-timelock-tx.ts without adding format validation, prioritizing code simplicity over strict validation in controlled environments.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-11-04T03:50:06.443Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 847
File: script/tasks/fundNewWalletOnAllChains.ts:179-187
Timestamp: 2024-11-04T03:50:06.443Z
Learning: In the `script/tasks/fundNewWalletOnAllChains.ts` file, adding a timeout to the transaction confirmation wait using `publicClient.waitForTransactionReceipt` is not required.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-07-17T04:21:50.790Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1266
File: script/deploy/safe/execute-pending-timelock-tx.ts:129-129
Timestamp: 2025-07-17T04:21:50.790Z
Learning: In the lifinance/contracts repository, 0xDEnYO prefers not to add private key format validation in deployment scripts like execute-pending-timelock-tx.ts, prioritizing code simplicity over strict validation in their controlled environment.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2024-10-04T09:17:19.275Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: deployments/avalanche.diamond.json:105-105
Timestamp: 2024-10-04T09:17:19.275Z
Learning: In the `lifinance/contracts` repository, contracts may have different addresses across networks. Do not check if contracts have the same addresses across all networks in future reviews.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-08-26T02:20:52.515Z
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.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-07-03T01:44:43.968Z
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.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 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:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-01-30T10:38:18.041Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 945
File: script/demoScripts/demoGlacis.ts:180-189
Timestamp: 2025-01-30T10:38:18.041Z
Learning: The executeTransaction helper function in the LiFi codebase handles error cases and transaction logging comprehensively, including try/catch structures, transaction receipt validation, and detailed console logging for transaction status tracking.

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*Bridge*.sol : LiFiTransferStarted event must be emitted at the end of the internal _startBridge function in facets, after all validations and external bridge calls have completed successfully

Applied to files:

  • script/demoScripts/demoAcrossV4Swap.ts
  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must implement required functions: `_startBridge` (internal), `swapAndStartBridgeTokensVia{FacetName}`, and `startBridgeTokensVia{FacetName}`

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use modifiers: `nonReentrant`, `refundExcessNative`, `validateBridgeData`, `doesNotContainSourceSwaps`/`doesContainSourceSwaps`, `doesNotContainDestinationCalls`/`doesContainDestinationCalls` on applicable functions

Applied to files:

  • src/Facets/AcrossV4SwapFacet.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:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets, validate `targetChainId` against `bridgeData.destinationChain` for EVM-to-EVM bridges

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 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:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-08-27T13:16:55.613Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1328
File: src/Periphery/Lda/Facets/CoreRouteFacet.sol:0-0
Timestamp: 2025-08-27T13:16:55.613Z
Learning: In LDA (LiFi DEX Aggregator) contracts, using address(this).balance to route all available ETH including dust and deposits from previous calls is intentional design. LDA contracts should not hold any funds and are designed to route any accumulated ETH to prevent fund accumulation. This is a feature, not a security issue.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.sol
📚 Learning: 2025-04-28T07:46:24.084Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 1116
File: src/Libraries/LibAsset.sol:102-108
Timestamp: 2025-04-28T07:46:24.084Z
Learning: In the LiFi contracts, the `LibAsset.transferFromERC20` function is intentionally designed to accept arbitrary `from` parameters, with security ensured through a whitelist mechanism that controls which contracts can call this function.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-04-22T09:04:44.244Z
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1112
File: deployments/soneium.diamond.json:81-81
Timestamp: 2025-04-22T09:04:44.244Z
Learning: In the lifinance/contracts repository, it's normal and expected for periphery contracts to have empty address values in deployment files when they are not deployed on a particular network. This applies to all periphery contracts including ReceiverChainflip, ReceiverStargateV2, and others. PRs should not flag empty periphery contract addresses as issues.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 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:

  • src/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-24T08:52:48.554Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/101-solidity-contracts.mdc:0-0
Timestamp: 2025-12-24T08:52:48.554Z
Learning: Applies to src/**/*.sol : In Solidity 0.8.17, you must not emit events using `ContractName.EventName` syntax (e.g., `emit SomeContract.SomeEvent(...)`). Events must be defined in the same contract where they're emitted, or defined in an interface that the contract uses, and then emitted using just the event name (e.g., `emit SomeEvent(...)`). This prevents compilation errors and ensures 0.8.17 compatibility.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Periphery/Receiver*.sol : LiFiTransferRecovered event should only be emitted in Receiver contracts (src/Periphery/Receiver*.sol)

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must only emit `LiFiTransferRecovered` when swaps fail and raw bridged tokens are sent to receiver, with event signature: `LiFiTransferRecovered(bytes32 indexed transactionId, address receivingAssetId, address receiver, uint256 amount, uint256 timestamp)`

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:34.379Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/104-receiver-contracts.mdc:0-0
Timestamp: 2025-12-17T10:28:34.379Z
Learning: Applies to src/Periphery/Receiver*.sol : Receiver contracts must use try-catch for executor calls, always have fallback to send raw tokens on failure, and reset approvals to 0 after operations

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets, `receiverAddress` must be the first parameter in `{facetName}Data` and must match `bridgeData.receiver` for EVM chains

Applied to files:

  • src/Facets/AcrossV4SwapFacet.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:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `{facetName}Data.receiverAddress` field (e.g., `_glacisData.receiverAddress`), validate that it is not `bytes32(0)` for non-EVM chains and revert with `InvalidNonEVMReceiver()` if zero

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:28:13.904Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : For non-EVM flows in Solidity facets, `bridgeData.receiver` must equal `NON_EVM_ADDRESS`

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*Bridge*.sol : For non-EVM chains (bridgeData.receiver == NON_EVM_ADDRESS), emit BridgeToNonEVMChainBytes32 with transactionId, destinationChainId, and non-EVM receiver (bytes32)

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-02-21T09:00:28.226Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 984
File: src/Facets/ChainflipFacet.sol:127-146
Timestamp: 2025-02-21T09:00:28.226Z
Learning: The `validateBridgeData` modifier in `Validatable.sol` already validates that the receiver address is not zero, making additional zero-address checks redundant in functions using this modifier.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-02-21T09:00:28.226Z
Learnt from: ezynda3
Repo: lifinance/contracts PR: 984
File: src/Facets/ChainflipFacet.sol:127-146
Timestamp: 2025-02-21T09:00:28.226Z
Learning: The `validateBridgeData` modifier in `Validatable.sol` validates that the receiver address is not zero using `LibUtil.isZeroAddress`, making additional zero-address checks redundant in functions using this modifier.

Applied to files:

  • src/Facets/AcrossV4SwapFacet.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:

  • src/Facets/AcrossV4SwapFacet.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/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-17T10:27:21.083Z
Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to **/*.sol : Delegate complex logic to libraries (LibAsset, LibSwap, LibAllowList, SwapperV2, Validatable) and helper contracts

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
📚 Learning: 2025-12-12T11:16:09.236Z
Learnt from: mirooon
Repo: lifinance/contracts PR: 1530
File: src/Interfaces/ICircleBridgeProxy.sol:20-29
Timestamp: 2025-12-12T11:16:09.236Z
Learning: In src/Interfaces/ICircleBridgeProxy.sol, ensure the ICircleBridgeProxy interface corresponds to Celer's CircleBridgeProxy contract (not Circle's native TokenMessenger). The depositForBurn signature must be: depositForBurn(uint256 _amount, uint64 _dstChid, bytes32 _mintRecipient, address _burnToken, uint256 _maxFee, uint32 _minFinalityThreshold) external. This change should be scoped specifically to this file; pattern is not needed since it targets a single file. This improves correctness by aligning the interface with the correct contract and parameter types (dst chain id as uint64, no bytes32 destinationCaller parameter).

Applied to files:

  • src/Facets/AcrossV4SwapFacet.sol
🪛 GitHub Check: Olympix Integrated Security
src/Facets/AcrossV4SwapFacet.sol

[notice] 193-193:
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

🔇 Additional comments (9)
src/Facets/AcrossV4SwapFacet.sol (5)

14-19: LGTM: Comprehensive contract documentation.

The NatSpec header correctly identifies the contract purpose, explicitly states it does not custody funds (important for bug bounty program), and includes version information. Well done!


54-63: LGTM: Proper constructor validation.

The constructor correctly validates both addresses are non-zero and uses the appropriate InvalidConfig() custom error. This prevents deployment with misconfigured addresses.


70-87: LGTM: Correctly implements required facet entry point.

The startBridgeTokensViaAcrossV4Swap function properly implements the required pattern with all necessary modifiers (nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps, doesNotContainDestinationCalls) and delegates to the internal _startBridge function.


93-124: LGTM: Excellent implementation of proportional slippage adjustment.

The function correctly implements the required pattern for handling positive slippage from swaps. Lines 114-121 proportionally update minExpectedInputTokenAmount based on the actual amount received from _depositAndSwap, which aligns perfectly with facet guidelines for updating bridge parameters after swaps.

Based on learnings, this is the correct approach for facets with minAmountOut parameters.


135-149: LGTM: Validations correctly implemented.

The destination chain ID validation (lines 135-141) and recipient validation (lines 143-149) are now present and use appropriate custom errors. This addresses the concerns raised in past review comments.

script/demoScripts/demoAcrossV4Swap.ts (4)

1-42: LGTM: Clean viem-based imports.

The script correctly uses viem for blockchain interactions and imports appropriate helpers from demoScriptHelpers. No deprecated ethers.js dependencies. Import organization follows guidelines.


350-398: LGTM: Proper environment setup and API configuration.

The main() function correctly uses setupEnvironment() from demoScriptHelpers to initialize viem clients. The API request preparation properly sets skipOriginTxEstimation: true, which is required when the depositor is a contract.


500-546: LGTM: Correct viem usage and TypeChain types.

Lines 500-546 properly use viem utilities (zeroAddress, crypto's randomBytes) and TypeChain-generated struct types (ILiFi.BridgeDataStruct, ISpokePoolPeriphery.BaseDepositDataStruct, AcrossV4SwapFacet.AcrossV4SwapDataStruct). This demonstrates correct migration from ethers.js.


680-694: LGTM: Complete transaction reporting and error handling.

The script correctly appends the transaction hash to the explorer URL (line 683) and implements proper error handling with appropriate exit codes. This addresses the concern from past review comments.

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

🤖 Fix all issues with AI agents
In `@script/helperFunctions.sh`:
- Around line 830-841: The fresh-structure branch creates a diamond with
Periphery: {} which can wipe existing periphery data; change the logic in this
block so when the merge fails you preserve any existing Periphery for
$DIAMOND_NAME instead of hardcoding {}. Use jq (or the same source you attempted
to merge) to extract the current Periphery value if present and inject it into
the new object (referencing DIAMOND_NAME and FACETS_JSON), or merge an empty
fallback only when no existing Periphery exists, so the created structure uses
the existing periphery when available.
- Around line 1062-1073: The current fresh-structure fallback unconditionally
sets Facets to {} (in the block that assigns result using jq with $DIAMOND_NAME
and $PERIPHERY_JSON), which can erase existing facet data if only the periphery
merge failed; update that branch to first attempt to read the existing diamond
JSON (e.g., load into a shell var like existing_json), extract existing Facets
(with jq) and use that value if present, otherwise default to {}, then build
result with that preserved Facets and $PERIPHERY_JSON; likewise, in the
saveDiamondFacets fallback (the other block that creates a fresh structure with
Periphery: {}), preserve existing Periphery by reading the current diamond JSON
and reusing its Periphery object when present instead of overwriting it with {}.

Comment on lines 1062 to 1073
# if merge failed, create fresh structure
if [[ $? -ne 0 || -z "$result" ]]; then
warning "[$NETWORK] Merge failed, creating fresh diamond structure with periphery"
result=$(jq -n --arg diamond_name "$DIAMOND_NAME" --argjson periphery_obj "$PERIPHERY_JSON" '
{
($diamond_name): {
Facets: {},
Periphery: $periphery_obj
}
}
' 2>/dev/null)
fi
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 3, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential data loss: Fresh structure creation overwrites existing Facets data.

When the merge fails and a fresh structure is created (lines 1065-1072), Facets is set to an empty object {}. This could overwrite any existing facet data in the diamond file if only the periphery merge failed.

Consider preserving existing Facets data when creating the fresh structure:

🛡️ Proposed fix to preserve existing Facets
       # if merge failed, create fresh structure
       if [[ $? -ne 0 || -z "$result" ]]; then
         warning "[$NETWORK] Merge failed, creating fresh diamond structure with periphery"
-        result=$(jq -n --arg diamond_name "$DIAMOND_NAME" --argjson periphery_obj "$PERIPHERY_JSON" '
+        # Try to preserve existing Facets from the diamond file
+        local existing_facets='{}'
+        if [[ -f "$DIAMOND_FILE" ]]; then
+          existing_facets=$(jq -r --arg dn "$DIAMOND_NAME" '.[$dn].Facets // {}' "$DIAMOND_FILE" 2>/dev/null) || existing_facets='{}'
+        fi
+        result=$(jq -n --arg diamond_name "$DIAMOND_NAME" --argjson facets_obj "$existing_facets" --argjson periphery_obj "$PERIPHERY_JSON" '
           {
             ($diamond_name): {
-              Facets: {},
+              Facets: $facets_obj,
               Periphery: $periphery_obj
             }
           }
         ' 2>/dev/null)
       fi

The same issue exists in saveDiamondFacets at lines 833-840 where the fresh structure sets Periphery: {}, potentially overwriting existing periphery data.

🤖 Prompt for AI Agents
In `@script/helperFunctions.sh` around lines 1062 - 1073, The current
fresh-structure fallback unconditionally sets Facets to {} (in the block that
assigns result using jq with $DIAMOND_NAME and $PERIPHERY_JSON), which can erase
existing facet data if only the periphery merge failed; update that branch to
first attempt to read the existing diamond JSON (e.g., load into a shell var
like existing_json), extract existing Facets (with jq) and use that value if
present, otherwise default to {}, then build result with that preserved Facets
and $PERIPHERY_JSON; likewise, in the saveDiamondFacets fallback (the other
block that creates a fresh structure with Periphery: {}), preserve existing
Periphery by reading the current diamond JSON and reusing its Periphery object
when present instead of overwriting it with {}.

Copy link
Contributor

Choose a reason for hiding this comment

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

outdated? pls confirm

Copy link
Contributor

Choose a reason for hiding this comment

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

@0xDEnYO Not outdated - the issue is still present in saveDiamondPeriphery.

Looking at the current code:

In saveDiamondPeriphery (lines 1065-1072 in the diff):

result=$(jq -n --arg diamond_name "$DIAMOND_NAME" --argjson periphery_obj "$PERIPHERY_JSON" '
  {
    ($diamond_name): {
      Facets: {},                    # ⚠️ Unconditionally empty - data loss risk
      Periphery: $periphery_obj
    }
  }
' 2>/dev/null)

In saveDiamondFacets (lines 935-941 in the file):

EXISTING_PERIPHERY=$(jq -c --arg dn "$DIAMOND_NAME" '.[$dn].Periphery // {}' "$DIAMOND_FILE" 2>/dev/null) || EXISTING_PERIPHERY='{}'
result=$(jq -n --arg diamond_name "$DIAMOND_NAME" --argjson facets_obj "$FACETS_JSON" --argjson periphery_obj "$EXISTING_PERIPHERY" '
  {
    ($diamond_name): {
      Facets: $facets_obj,
      Periphery: $periphery_obj      # ✅ Preserves existing Periphery
    }
  }
' 2>/dev/null)

The fix pattern has been applied to saveDiamondFacets (preserves existing Periphery), but the same pattern needs to be applied to saveDiamondPeriphery to preserve existing Facets. This would maintain symmetry and prevent data loss if only the periphery merge fails but facets exist.


🧠 Learnings used
Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: script/tasks/diamondUpdatePeriphery.sh:194-194
Timestamp: 2024-10-09T03:47:21.269Z
Learning: In `script/tasks/diamondUpdatePeriphery.sh`, the team prefers to use `echo` statements without escaping inner quotes, even if Shellcheck warns about SC2027 regarding unintentional unquoting.

Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 819
File: script/tasks/diamondUpdatePeriphery.sh:194-194
Timestamp: 2024-10-04T08:53:12.628Z
Learning: In `script/tasks/diamondUpdatePeriphery.sh`, the team prefers to use `echo` statements without escaping inner quotes, even if Shellcheck warns about SC2027 regarding unintentional unquoting.

Learnt from: mirooon
Repo: lifinance/contracts PR: 1625
File: script/utils/diamondEMERGENCYPauseStagingGitHub.sh:86-96
Timestamp: 2026-02-10T22:58:29.649Z
Learning: In script/utils/diamondEMERGENCYPauseStagingGitHub.sh, the file logic should be kept identical to the production emergency pause script (diamondEMERGENCYPauseGitHub.sh) with minimal changes. This consistency is preferred for easier maintenance and comparison between environments, even if some error handling could be improved.

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.

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: ezynda3
Repo: lifinance/contracts PR: 924
File: script/deploy/zksync/utils/UpdateScriptBase.sol:112-178
Timestamp: 2025-01-28T14:29:00.823Z
Learning: The suggestion to modify `buildDiamondCut` function in `UpdateScriptBase.sol` to handle selectors from multiple old facets differently was deemed unnecessary by the maintainer.

Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 782
File: deployments/worldchain.diamond.json:5-63
Timestamp: 2024-11-26T01:14:58.163Z
Learning: When facet versions are set to empty strings in `deployments/*.diamond.json` files, do not report this issue, as it is already known and will be addressed separately.

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

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: mirooon
Repo: lifinance/contracts PR: 1193
File: script/tasks/diamondSyncWhitelistedAddresses.sh:128-128
Timestamp: 2025-06-06T16:09:58.692Z
Learning: In script/tasks/diamondSyncWhitelistedAddresses.sh at line 128, there is an unquoted command substitution `$(getPrivateKey "$NETWORK" "$ENVIRONMENT")` that should be quoted as `"$(getPrivateKey "$NETWORK" "$ENVIRONMENT")"` to prevent word splitting issues. The user mirooon wants to be reminded about this issue in future PRs when this file is touched.

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.

Learnt from: mirooon
Repo: lifinance/contracts PR: 1193
File: script/tasks/diamondSyncSelectors.sh:112-117
Timestamp: 2025-06-15T11:05:21.990Z
Learning: In script/tasks/diamondSyncSelectors.sh (line 112), there is a shell array assignment using command substitution that should be fixed using mapfile instead: `CFG_SELECTORS=($(jq -r '.[] | sh' "./config/whitelistedSelectors.json" | tr -d \' | tr '[:upper:]' '[:lower:]'))` should be `mapfile -t CFG_SELECTORS < <(jq -r '.[]' "./config/whitelistedSelectors.json" | tr '[:upper:]' '[:lower:]')`. User mirooon requested to be reminded of this issue in future PRs when this file is modified.

Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1325
File: script/tasks/diamondSyncDEXs.sh:116-116
Timestamp: 2025-08-27T08:45:59.606Z
Learning: In script/tasks/diamondSyncDEXs.sh, user 0xDEnYO has chosen to selectively apply ShellCheck fixes, keeping array assignments using $() construct and other patterns as-is in their controlled deployment environment, prioritizing functionality over strict ShellCheck compliance.

Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1196
File: script/helperFunctions.sh:1447-1462
Timestamp: 2025-06-19T06:23:47.848Z
Learning: 0xDEnYO prefers to keep eval usage in local bash scripts when the security risk is acceptable in their controlled environment, prioritizing simplicity over security hardening for local tooling.

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.

Learnt from: 0xDEnYO
Repo: lifinance/contracts PR: 1212
File: .github/workflows/convertForkedPRsToInternal.yml:81-106
Timestamp: 2025-07-16T06:18:02.682Z
Learning: 0xDEnYO prefers to use printf "%q" for shell escaping in GitHub workflows to increase security and protection from potential injections, even when it might cause formatting issues, prioritizing security over convenience.

Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : In Solidity facets with `minAmountOut` or similar bridge parameters, update the bridge's minAmountOut in `swapAndStartBridgeTokensVia{FacetName}` to account for positive slippage from swaps after `_depositAndSwap` updates `_bridgeData.minAmount`, adjusting proportionally for decimal differences if applicable

Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must implement required functions: `_startBridge` (internal), `swapAndStartBridgeTokensVia{FacetName}`, and `startBridgeTokensVia{FacetName}`

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.

Learnt from: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/102-facets.mdc:0-0
Timestamp: 2025-12-17T10:28:13.904Z
Learning: Applies to src/Facets/**/*Facet.sol : Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via `_depositAndSwap` variants when needed

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: CR
Repo: lifinance/contracts PR: 0
File: .cursor/rules/002-architecture.mdc:0-0
Timestamp: 2025-12-17T10:27:21.083Z
Learning: Applies to src/Facets/**/*.sol : Facets provide modular functionality grouped by concern (bridges, swaps, receivers, admin, etc.)

Learnt from: reednaa
Repo: lifinance/contracts PR: 1588
File: src/Facets/LiFiIntentEscrowFacet.sol:144-169
Timestamp: 2026-01-19T09:43:25.866Z
Learning: In src/Facets/LiFiIntentEscrowFacet.sol, non-EVM destination calls (dstCallSwapData with NON_EVM_ADDRESS receiver) are not a concern for the current implementation and do not require validation guards.

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.

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

🤖 Fix all issues with AI agents
In `@src/Facets/AcrossV4SwapFacet.sol`:
- Around line 199-218: Add an explicit config guard that checks the configured
periphery/contract address for the selected swapApiTarget before invoking any of
the _call... functions so we fail fast with InvalidConfig() instead of a
low‑level revert; for example, when swapApiTarget ==
SwapApiTarget.SpokePoolPeriphery validate the SpokePoolPeriphery address is
nonzero (and similarly for SponsoredOFTSrcPeriphery / SponsoredCCTPSrcPeriphery)
using the project’s existing validation helper (or add a small helper like
_requireConfigured(address, "InvalidConfig")) and revert InvalidConfig() if
unset, then proceed to call _callSpokePoolPeripherySwapAndBridge,
_callSponsoredOftDeposit or _callSponsoredCctpDepositForBurn as appropriate.

In `@test/solidity/Facets/Across/SwapAPI/AcrossV4SwapFacet.t.sol`:
- Around line 4-8: The tests in AcrossV4SwapFacet.t.sol are inheriting TestBase
but should inherit TestBaseFacet so facet-specific overrides and helpers are
available; update the contract base class references from TestBase to
TestBaseFacet (and adjust any imports to bring in TestBaseFacet if missing),
ensure TestWhitelistManagerBase/TestHelpers usage remains compatible, and update
all test contracts in this file (including the ones referenced around the 70-74
region) to extend TestBaseFacet instead of TestBase so the standard facet
override wiring is applied.
🧹 Nitpick comments (1)
script/helperFunctions.sh (1)

4392-4399: Consider separating variable declaration and assignment for ShellCheck compliance.

The local VAR=$(...) pattern can mask command return values (ShellCheck SC2155). While the code correctly handles empty results with [[ -n "$var" ]] checks, separating declaration and assignment would be more robust.

♻️ Optional fix for ShellCheck SC2155
-  local TMP_RAW_RETURN_DATA=$(echo "$RAW_RETURN_DATA" | grep -o '{"logs":.*}' | head -1)
+  local TMP_RAW_RETURN_DATA
+  TMP_RAW_RETURN_DATA=$(echo "$RAW_RETURN_DATA" | grep -o '{"logs":.*}' | head -1)
   if [[ -n "$TMP_RAW_RETURN_DATA" ]] && echo "$TMP_RAW_RETURN_DATA" | jq empty 2>/dev/null; then
     echo "$TMP_RAW_RETURN_DATA"
     return 0
   fi

   # Fallback: try jq extraction on original data
-  local EXTRACTED=$(echo "$ORIGINAL_RAW_RETURN_DATA" | jq -c 'if type=="object" and has("logs") then . else empty end' 2>/dev/null | head -1)
+  local EXTRACTED
+  EXTRACTED=$(echo "$ORIGINAL_RAW_RETURN_DATA" | jq -c 'if type=="object" and has("logs") then . else empty end' 2>/dev/null | head -1)

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

🤖 Fix all issues with AI agents
In `@script/helperFunctions.sh`:
- Around line 961-963: The periphery-only branch writes PERIPHERY_JSON to
OUTPUT_PATH but skips the existing cleanup, leaking TEMP_DIR; update the code so
TEMP_DIR is always removed after writing in the periphery-only case (either call
the same cleanup code or rm -rf "$TEMP_DIR" before exiting that branch), or
better, invoke the common cleanup function (or shared rm -rf "$TEMP_DIR" line)
from the periphery-only branch; ensure this change references OUTPUT_MODE,
"periphery-only", OUTPUT_PATH, PERIPHERY_JSON and TEMP_DIR so the temp dir is
deleted regardless of which branch runs.
🧹 Nitpick comments (2)
script/helperFunctions.sh (2)

757-759: trap on EXIT overwrites any caller-set EXIT trap, risking cleanup leaks.

saveDiamondFacets is sourced into many scripts. Setting trap ... EXIT here unconditionally replaces whatever EXIT trap the caller (or a prior call) registered. Contrast this with executeAndCapture (line 4406–4442), which correctly saves and restores the previous EXIT trap. Consider applying the same pattern here, or use a local cleanup approach (e.g., clean up explicitly before returning and remove the trap).

🛡️ Suggested fix
   local TEMP_DIR
   TEMP_DIR=$(mktemp -d)
-  trap 'rm -rf "$TEMP_DIR" 2>/dev/null' EXIT
+  local _OLD_EXIT_TRAP
+  _OLD_EXIT_TRAP="$(trap -p EXIT 2>/dev/null || true)"
+  trap 'rm -rf "$TEMP_DIR" 2>/dev/null' EXIT

And at the end of the function (before each return / fall-through), restore:

  rm -rf "$TEMP_DIR" 2>/dev/null
  if [[ -n "$_OLD_EXIT_TRAP" ]]; then
    eval "$_OLD_EXIT_TRAP"
  else
    trap - EXIT
  fi

4350-4416: ShellCheck SC2155: local + command substitution masks return values.

Static analysis flags four instances where local VAR=$(...) masks the exit code. This is a minor concern since the code uses || echo "" fallbacks, but splitting declaration and assignment is the safer pattern.

♻️ Example fix for lines 4415–4416
-  local RAW_RETURN_DATA=$(cat "$STDOUT_LOG" 2>/dev/null || echo "")
-  local STDERR_CONTENT=$(cat "$STDERR_LOG" 2>/dev/null || echo "")
+  local RAW_RETURN_DATA
+  RAW_RETURN_DATA=$(cat "$STDOUT_LOG" 2>/dev/null || echo "")
+  local STDERR_CONTENT
+  STDERR_CONTENT=$(cat "$STDERR_LOG" 2>/dev/null || echo "")

Same pattern applies to lines 4361 and 4368 in extractJsonFromForgeOutput.

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

🤖 Fix all issues with AI agents
In `@script/demoScripts/demoAcrossV4Swap.ts`:
- Around line 632-634: The transactionId value built at the top-level (the const
transactionId from arg('--transactionId')) must be validated as a bytes32 hex
(32 bytes / 64 hex chars, 66 chars with "0x"); add a check after construction
that accepts either "0x"-prefixed or raw hex, normalizes to a "0x"-prefixed
lowercase string, verifies length == 66 and that all chars are valid hex, and if
invalid throw a clear error or process.exit(1); keep the existing randomBytes
fallback but validate it the same way so any provided or generated transactionId
always meets the bytes32 requirement.

In `@test/solidity/Facets/Across/SwapAPI/AcrossV4SwapFacet.Sponsored.t.sol`:
- Around line 351-362: The test should insert a blank line after the
vm.expectRevert(InvalidCallData.selector) call before invoking the function
under test; update the call-site where vm.expectRevert is followed by
acrossV4SwapFacet.startBridgeTokensViaAcrossV4Swap(...) so there is an empty
line between vm.expectRevert and the startBridgeTokensViaAcrossV4Swap invocation
(apply the same blank-line change for other occurrences that follow the same
pattern in this test file), leaving the existing arguments and
AcrossV4SwapFacet.AcrossV4SwapFacetData structure unchanged.
🧹 Nitpick comments (3)
script/helperFunctions.sh (2)

4352-4378: Shellcheck SC2155: local masks return values of command substitutions.

Lines 4363 and 4370 combine local declaration with command substitution, which masks the exit code. Not a functional bug here since the code checks the variable contents rather than $?, but it's flagged by static analysis.

♻️ Proposed fix
-  local TMP_RAW_RETURN_DATA=$(echo "$RAW_RETURN_DATA" | grep -o '{"logs":.*}' | head -1)
+  local TMP_RAW_RETURN_DATA
+  TMP_RAW_RETURN_DATA=$(echo "$RAW_RETURN_DATA" | grep -o '{"logs":.*}' | head -1)
   if [[ -n "$TMP_RAW_RETURN_DATA" ]] && echo "$TMP_RAW_RETURN_DATA" | jq empty 2>/dev/null; then
...
-  local EXTRACTED=$(echo "$ORIGINAL_RAW_RETURN_DATA" | jq -c 'if type=="object" and has("logs") then . else empty end' 2>/dev/null | head -1)
+  local EXTRACTED
+  EXTRACTED=$(echo "$ORIGINAL_RAW_RETURN_DATA" | jq -c 'if type=="object" and has("logs") then . else empty end' 2>/dev/null | head -1)

4416-4419: Shellcheck SC2155: same local + assignment pattern.

Lines 4417–4418 mask return values. Same optional fix as above — declare first, then assign.

♻️ Proposed fix
-  local RAW_RETURN_DATA=$(cat "$STDOUT_LOG" 2>/dev/null || echo "")
-  local STDERR_CONTENT=$(cat "$STDERR_LOG" 2>/dev/null || echo "")
+  local RAW_RETURN_DATA
+  local STDERR_CONTENT
+  RAW_RETURN_DATA=$(cat "$STDOUT_LOG" 2>/dev/null || echo "")
+  STDERR_CONTENT=$(cat "$STDERR_LOG" 2>/dev/null || echo "")
script/demoScripts/demoAcrossV4Swap.ts (1)

217-245: Prefer TypeChain structs over ad-hoc interfaces.

This script defines IBridgeData, ISwapData, and facet data locally; guidelines require using TypeChain types (e.g., ILiFi.BridgeDataStruct, LibSwap.SwapDataStruct, facet data struct) to keep ABI alignment and ESLint compliance.
As per coding guidelines, “use TypeChain types from typechain/ directory.”

mirooon
mirooon previously approved these changes Feb 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants