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
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds 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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
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. Comment |
There was a problem hiding this comment.
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_ABIis undefined; useAcrossV4SwapFacet.abifrom the imported factory- Lines 103-105:
AcrossV4SwapDataStructfields are empty placeholder comments; populate with actual structure matching the facet'sAcrossV4SwapData(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 depositssrc/Facets/AcrossV4SwapFacet.sol (3)
90-110: Consider updating minExpectedInputTokenAmount after swap to reflect positive slippage.After
_depositAndSwapupdates_bridgeData.minAmountwith the actual post-swap amount (line 102-107), the_acrossV4SwapData.minExpectedInputTokenAmountstill 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
minAmountOutparameters 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.outputAmountalso needs proportional adjustment, apply similar logic to that field.
117-154: Event emission after external call may cause ordering issues.Line 153 emits
LiFiTransferStartedafter the external call toSPOKE_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. WhilenonReentrantprevents reentrancy attacks, event listeners might observe the periphery's events before LiFi's event.Consider emitting
LiFiTransferStartedbefore 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
refundExcessNativemodifier that returns excess native tokens tomsg.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
There was a problem hiding this comment.
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.
📒 Files selected for processing (5)
config/across-v4-swap.jsondeployments/arbitrum.diamond.staging.jsondeployments/arbitrum.staging.jsonscript/deploy/facets/DeployAcrossV4SwapFacet.s.soltest/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 orscript/deploy/for other contracts. Use Foundry'sScriptcontract pattern.
Files:
script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
**/*.sol
📄 CodeRabbit inference engine (.cursor/rules/001-project-structure.mdc)
Use remappings defined in
remappings.txtfor 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 contractsAfter Solidity changes, run
forge test(or note suites remaining)
**/*.sol: Own files must use// SPDX-License-Identifier: LGPL-3.0-onlyimmediately followed by the pragma statement with no blank line in between
All contracts must usepragma 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),@noticedescribing 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 fromsrc/Errors/GenericErrors.sol; bump@custom:versionwhen 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 implementationsDo not mix interface and implementation in the same file
Files:
script/deploy/facets/DeployAcrossV4SwapFacet.s.soltest/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.soltest/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.soltest/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.solorUpdate*.s.solnaming and JSON config viastdJson
Files:
script/deploy/facets/DeployAcrossV4SwapFacet.s.sol
script/**/Deploy*.s.sol
📄 CodeRabbit inference engine (.cursor/rules/107-solidity-scripts.mdc)
Deploy scripts should use
DeployScriptBasepattern withdeploy(type(Contract).creationCode)and only addgetConstructorArgs()when needed, reading from JSON viastdJson
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 (andscript/deploy/zksync/when relevant) and reuse helper/config files likedeployRequirements.jsonandtargetState.jsoninstead 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 thesrc/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 undertest/solidity/, mirroringsrc/structure; requiresetUp()function; callinitTestBase()when inheritingTestBasedirectly or indirectly; label actors withvm.label
For facet tests, inherit fromTestBaseFacetrather thanTestBase, 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; usevm.startPrank/vm.stopPrank, labels, and base inits
Always assert specific revert reasons; usevm.expectRevertwith specific reason
Usevm.expectEmit(true, true, true, true, <addr>)for event assertions
Apply blank line conventions: add gap aftervm.expectRevertbefore the call, and gap before assertions/events
For whitelist flows, inheritTestWhitelistManagerBaseand useaddToWhitelist/setFunctionWhitelistBySelectorhelpers
If a facet does not support native tokens, override tests such astestBase_CanSwapAndBridgeNativeTokensandtestBase_CanBridgeNativeTokenswithpublic overrideand 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.jsondeployments/arbitrum.diamond.staging.jsonscript/deploy/facets/DeployAcrossV4SwapFacet.s.soltest/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.jsondeployments/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.jsondeployments/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.jsondeployments/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.jsondeployments/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.jsondeployments/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.jsondeployments/arbitrum.diamond.staging.jsontest/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.jsondeployments/arbitrum.diamond.staging.jsontest/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.jsontest/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.jsontest/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:
- The address
0x2D732A56c10F33292484911C660C2F68F0615a89corresponds to the deployed AcrossV4SwapFacet v1.0.0 on Arbitrum- The deployment log file (
_deployments_log_file.json) has been updated with this entry- Whether other staging network configurations (e.g.,
optimism.staging.json,polygon.staging.json) require similar updatesRun 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" fiscript/deploy/facets/DeployAcrossV4SwapFacet.s.sol (1)
1-41: LGTM!The deployment script correctly follows the
DeployScriptBasepattern. Constructor args are read fromconfig/across-v4-swap.jsonusing the standard helper, and thedeploy()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
InvalidConfigis reverted when either address parameter is zero, using the propervm.expectRevertpattern.
- 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
There was a problem hiding this comment.
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.
📒 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 inscript/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.cjsrules,bunx tsx,citty,consola, and env validated via helpers (e.g.,getEnvVar()).
DO NOT use deprecated ethers-based helpers (getProvider,getWalletFromPrivateKeyInDotEnv, etherssendTransaction,ensureBalanceAndAllowanceToDiamond).
Obey.eslintrc.cjs; avoidany; use TypeChain types fromtypechain/directory (e.g.,ILiFi.BridgeDataStruct).
Import organization: Group imports as: external libs (viem, consola, citty, dotenv) → TypeChain types → config files → internal utils/helpers. Usetypeimports for types-only.
Error handling: Use try/catch withconsola.error()for logging; exit withprocess.exit(1)on fatal errors. Provide meaningful error messages.
CLI: usecitty; logging viaconsola; validate env viagetEnvVar(); exit 0/1 appropriately.
New TypeScript helpers must be covered by a colocated*.test.tsfile 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 fromdemoScriptHelpers). SeedemoLidoWrapper.ts,demoUnit.ts,demoEco.tsas 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
There was a problem hiding this comment.
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 anycast 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
submissionFeesset to zero (lines 144-147) andnonceset 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 forsubmissionFeesfor 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.
📒 Files selected for processing (5)
docs/AcrossV4SwapFacet.mdscript/demoScripts/demoAcrossV4Swap.tssrc/Facets/AcrossV4SwapFacet.solsrc/Interfaces/ISpokePoolPeriphery.soltest/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 inscript/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.tssrc/Facets/AcrossV4SwapFacet.soltest/solidity/Facets/AcrossV4SwapFacet.t.sol
{script,tasks}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/200-typescript.mdc)
{script,tasks}/**/*.ts: TS scripts use.eslintrc.cjsrules,bunx tsx,citty,consola, and env validated via helpers (e.g.,getEnvVar()).
DO NOT use deprecated ethers-based helpers (getProvider,getWalletFromPrivateKeyInDotEnv, etherssendTransaction,ensureBalanceAndAllowanceToDiamond).
Obey.eslintrc.cjs; avoidany; use TypeChain types fromtypechain/directory (e.g.,ILiFi.BridgeDataStruct).
Import organization: Group imports as: external libs (viem, consola, citty, dotenv) → TypeChain types → config files → internal utils/helpers. Usetypeimports for types-only.
Error handling: Use try/catch withconsola.error()for logging; exit withprocess.exit(1)on fatal errors. Provide meaningful error messages.
CLI: usecitty; logging viaconsola; validate env viagetEnvVar(); exit 0/1 appropriately.
New TypeScript helpers must be covered by a colocated*.test.tsfile 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 fromdemoScriptHelpers). SeedemoLidoWrapper.ts,demoUnit.ts,demoEco.tsas 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 thesrc/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.txtfor 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 contractsAfter Solidity changes, run
forge test(or note suites remaining)
**/*.sol: Own files must use// SPDX-License-Identifier: LGPL-3.0-onlyimmediately followed by the pragma statement with no blank line in between
All contracts must usepragma 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),@noticedescribing 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 fromsrc/Errors/GenericErrors.sol; bump@custom:versionwhen 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 implementationsDo not mix interface and implementation in the same file
Files:
src/Facets/AcrossV4SwapFacet.soltest/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.soltest/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 insrc/Facets/directory with names containingFacet
Facets must implement required functions:_startBridge(internal),swapAndStartBridgeTokensVia{FacetName}, andstartBridgeTokensVia{FacetName}
Facets must use modifiers:nonReentrant,refundExcessNative,validateBridgeData,doesNotContainSourceSwaps/doesContainSourceSwaps,doesNotContainDestinationCalls/doesContainDestinationCallson applicable functions
In Solidity facets,receiverAddressmust be the first parameter in{facetName}Dataand must matchbridgeData.receiverfor EVM chains
In Solidity facets, validatetargetChainIdagainstbridgeData.destinationChainfor EVM-to-EVM bridges
Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via_depositAndSwapvariants when needed
In Solidity facets withminAmountOutor similar bridge parameters, update the bridge's minAmountOut inswapAndStartBridgeTokensVia{FacetName}to account for positive slippage from swaps after_depositAndSwapupdates_bridgeData.minAmount, adjusting proportionally for decimal differences if applicable
For non-EVM receivers in Solidity facets, usebytestype; the value must be non-zero
For non-EVM flows in Solidity facets,bridgeData.receivermust equalNON_EVM_ADDRESS
In Solidity facets with{facetName}Data.receiverAddressfield (e.g.,_glacisData.receiverAddress), validate that it is notbytes32(0)for non-EVM chains and revert withInvalidNonEVMReceiver()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 thoroughlyAll contracts in
src/require audits except Interfaces insrc/Interfaces/**(type definitions only) and external dependencies inlib/
src/**/*.sol: NatSpec required on contracts/interfaces insrc/:@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 overmsg.senderfor refund addresses.
In Solidity 0.8.17, you must not emit events usingContractName.EventNamesyntax (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 thesrc/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 undertest/solidity/, mirroringsrc/structure; requiresetUp()function; callinitTestBase()when inheritingTestBasedirectly or indirectly; label actors withvm.label
For facet tests, inherit fromTestBaseFacetrather thanTestBase, 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; usevm.startPrank/vm.stopPrank, labels, and base inits
Always assert specific revert reasons; usevm.expectRevertwith specific reason
Usevm.expectEmit(true, true, true, true, <addr>)for event assertions
Apply blank line conventions: add gap aftervm.expectRevertbefore the call, and gap before assertions/events
For whitelist flows, inheritTestWhitelistManagerBaseand useaddToWhitelist/setFunctionWhitelistBySelectorhelpers
If a facet does not support native tokens, override tests such astestBase_CanSwapAndBridgeNativeTokensandtestBase_CanBridgeNativeTokenswithpublic overrideand 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.tssrc/Facets/AcrossV4SwapFacet.soltest/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.tssrc/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.tssrc/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.tssrc/Facets/AcrossV4SwapFacet.soltest/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.tssrc/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.tssrc/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.tssrc/Facets/AcrossV4SwapFacet.soltest/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.soltest/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.soltest/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.soltest/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.soltest/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.soltest/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, andexecuteTransactionhelpers 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
refundExcessNativemodifier ensures any excess native tokens are returned to the sender.The static analysis "locked-ether" warning is a false positive — the
refundExcessNativemodifier on both entry points handles native token refunds.
54-63: Constructor validation is correct.Zero-address checks for both
_spokePoolPeripheryand_spokePoolusing the existingInvalidConfigerror. 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 viaLibAsset.depositAssetbefore bridging follows the standard pattern.
92-122: Positive slippage adjustment correctly implemented.The
swapAndStartBridgeTokensViaAcrossV4Swapfunction properly adjustsminExpectedInputTokenAmountproportionally 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) / originalAmountcorrectly scales the expectation.
162-166: Event emission before external call is intentional but diverges from standard pattern.The
LiFiTransferStartedevent is emitted before the external call toSPOKE_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. ThenonReentrantmodifier 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
nonReentrantprotection.test/solidity/Facets/AcrossV4SwapFacet.t.sol (4)
44-127: Test setup follows established patterns correctly.The
setUpfunction:
- Calls
initTestBase()as required when inheritingTestBaseFacet- Uses
customBlockNumberForForkingfor reproducible forked tests- Properly registers facet selectors with the diamond
- Adds allowed contract selectors for Uniswap router
- Uses
vm.labelfor actor labeling- Configures
bridgeDataandvalidAcrossV4SwapDataappropriatelyThe "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_CanBridgeNativeTokensandtestBase_CanSwapAndBridgeNativeTokensare 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
_spokePoolPeripheryand_spokePool, usingvm.expectRevertwith the specificInvalidConfig.selector. Follows thetestRevert_naming convention.
129-149: Bridge transaction initiator correctly handles dynamic amounts.The override properly synchronizes
validAcrossV4SwapData.minExpectedInputTokenAmountwithbridgeData.minAmountfor fuzz tests, and approximates the output amount with a 0.1% fee reduction. TheisNativebranch exists for interface completeness but won't be exercised since native token tests are overridden.
- 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
There was a problem hiding this comment.
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
executeTransactionand 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
txHashdeclaration 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.
📒 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 inscript/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.cjsrules,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, etherssendTransaction,ensureBalanceAndAllowanceToDiamond
Obey.eslintrc.cjsrules; avoidanytype; use TypeChain types fromtypechain/directory (e.g.,ILiFi.BridgeDataStruct)
Always reuse existing helpers and types: Searchscript/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. Usetypeimports for types-only
Use try/catch withconsola.error()for error logging; exit withprocess.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 inscript/common/types.ts(e.g.,SupportedChain,INetwork,EnvironmentEnum); domain-specific types should be colocated in domain-specific files
Interfaces MUST start withIprefix (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 withEnumsuffix (e.g.,EnvironmentEnum)
Usecittyfor CLI,consolafor logging,getEnvVar()for environment validation, and exit with 0/1 appropriately
New TypeScript helpers must be covered by a colocated*.test.tsfile 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 fromdemoScriptHelpers. 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
Iprefix 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.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/Facets/AcrossV4SwapFacet.sol (2)
114-121: Consider also adjustingdepositData.outputAmountproportionally.When positive slippage occurs,
minExpectedInputTokenAmountis adjusted proportionally, butdepositData.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
maxApproveERC20onsendingAssetId, 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 tokensAdd 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.
📒 Files selected for processing (2)
src/Facets/AcrossV4SwapFacet.soltest/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 thesrc/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.txtfor 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 contractsAfter Solidity changes, run
forge test(or note suites remaining)
**/*.sol: Own files must use// SPDX-License-Identifier: LGPL-3.0-onlyimmediately followed by the pragma statement with no blank line in between
All contracts must usepragma 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),@noticedescribing 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 fromsrc/Errors/GenericErrors.sol; bump@custom:versionwhen 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 implementationsDo not mix interface and implementation in the same file
Files:
src/Facets/AcrossV4SwapFacet.soltest/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.soltest/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 insrc/Facets/directory with names containingFacet
Facets must implement required functions:_startBridge(internal),swapAndStartBridgeTokensVia{FacetName}, andstartBridgeTokensVia{FacetName}
Facets must use modifiers:nonReentrant,refundExcessNative,validateBridgeData,doesNotContainSourceSwaps/doesContainSourceSwaps,doesNotContainDestinationCalls/doesContainDestinationCallson applicable functions
In Solidity facets,receiverAddressmust be the first parameter in{facetName}Dataand must matchbridgeData.receiverfor EVM chains
In Solidity facets, validatetargetChainIdagainstbridgeData.destinationChainfor EVM-to-EVM bridges
Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via_depositAndSwapvariants when needed
In Solidity facets withminAmountOutor similar bridge parameters, update the bridge's minAmountOut inswapAndStartBridgeTokensVia{FacetName}to account for positive slippage from swaps after_depositAndSwapupdates_bridgeData.minAmount, adjusting proportionally for decimal differences if applicable
For non-EVM receivers in Solidity facets, usebytestype; the value must be non-zero
For non-EVM flows in Solidity facets,bridgeData.receivermust equalNON_EVM_ADDRESS
In Solidity facets with{facetName}Data.receiverAddressfield (e.g.,_glacisData.receiverAddress), validate that it is notbytes32(0)for non-EVM chains and revert withInvalidNonEVMReceiver()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.soltest/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 thoroughlyAll contracts in
src/require audits except Interfaces insrc/Interfaces/**(type definitions only) and external dependencies inlib/
src/**/*.sol: NatSpec required on contracts/interfaces insrc/:@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 overmsg.senderfor refund addresses.
In Solidity 0.8.17, you must not emit events usingContractName.EventNamesyntax (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 thesrc/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 undertest/solidity/, mirroringsrc/structure; requiresetUp()function; callinitTestBase()when inheritingTestBasedirectly or indirectly; label actors withvm.label
For facet tests, inherit fromTestBaseFacetrather thanTestBase, 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; usevm.startPrank/vm.stopPrank, labels, and base inits
Always assert specific revert reasons; usevm.expectRevertwith specific reason
Usevm.expectEmit(true, true, true, true, <addr>)for event assertions
Apply blank line conventions: add gap aftervm.expectRevertbefore the call, and gap before assertions/events
For whitelist flows, inheritTestWhitelistManagerBaseand useaddToWhitelist/setFunctionWhitelistBySelectorhelpers
If a facet does not support native tokens, override tests such astestBase_CanSwapAndBridgeNativeTokensandtestBase_CanBridgeNativeTokenswithpublic overrideand 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.soltest/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.soltest/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.soltest/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.soltest/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.soltest/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.soltest/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.soltest/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
InvalidConfigerror. Parameters follow naming conventions.
70-87: LGTM!All required modifiers are present:
nonReentrant,refundExcessNative,validateBridgeData,doesNotContainSourceSwaps, anddoesNotContainDestinationCalls. 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_andtestRevert_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 inconfig/across-v4-swap.json. TheSPOKE_POOL_PERIPHERYandSPOKE_POOLaddresses are consistent across both test and config files. Standard token addresses (WETH, USDC, USDT) and the Uniswap Universal Router are correctly set.
There was a problem hiding this comment.
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 anycast 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 SwapAndDepositDataThis 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.
📒 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 inscript/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.cjsrules,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, etherssendTransaction,ensureBalanceAndAllowanceToDiamond
Obey.eslintrc.cjsrules; avoidanytype; use TypeChain types fromtypechain/directory (e.g.,ILiFi.BridgeDataStruct)
Always reuse existing helpers and types: Searchscript/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. Usetypeimports for types-only
Use try/catch withconsola.error()for error logging; exit withprocess.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 inscript/common/types.ts(e.g.,SupportedChain,INetwork,EnvironmentEnum); domain-specific types should be colocated in domain-specific files
Interfaces MUST start withIprefix (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 withEnumsuffix (e.g.,EnvironmentEnum)
Usecittyfor CLI,consolafor logging,getEnvVar()for environment validation, and exit with 0/1 appropriately
New TypeScript helpers must be covered by a colocated*.test.tsfile 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 fromdemoScriptHelpers. 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
Iprefix 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
executeTransactionhelper, 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
🤖 GitHub Action: Security Alerts Review 🔍🟢 Dismissed Security Alerts with Comments 🟢 View Alert - File: 🟢 View Alert - File: ✅ No unresolved security alerts! 🎉 |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/Facets/AcrossV4SwapFacet.sol (1)
180-184: EmitLiFiTransferStartedafter the external bridge call.Lines 180-184 emit the
LiFiTransferStartedevent before callingSPOKE_POOL_PERIPHERY.swapAndBridge(). Per facet guidelines, the event should be emitted at the end of_startBridgeafter 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
LiFiTransferStartedat the end of_startBridgeafter all operations complete.script/demoScripts/demoAcrossV4Swap.ts (2)
268-278: Consider typing the decoded args explicitly.Line 278 uses
as anyto 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 ISwapAndDepositDataPer coding guidelines, avoiding
anyis 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 importedAcrossV4SwapFacettype from TypeChain.The current approach works but bypasses TypeScript's type checking. For a production script, consider casting
lifiDiamondContractto 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.
📒 Files selected for processing (2)
script/demoScripts/demoAcrossV4Swap.tssrc/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 inscript/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.tssrc/Facets/AcrossV4SwapFacet.sol
{script,tasks}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/200-typescript.mdc)
{script,tasks}/**/*.ts: TypeScript scripts must use.eslintrc.cjsrules,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, etherssendTransaction,ensureBalanceAndAllowanceToDiamond
Obey.eslintrc.cjsrules; avoidanytype; use TypeChain types fromtypechain/directory (e.g.,ILiFi.BridgeDataStruct)
Always reuse existing helpers and types: Searchscript/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. Usetypeimports for types-only
Use try/catch withconsola.error()for error logging; exit withprocess.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 inscript/common/types.ts(e.g.,SupportedChain,INetwork,EnvironmentEnum); domain-specific types should be colocated in domain-specific files
Interfaces MUST start withIprefix (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 withEnumsuffix (e.g.,EnvironmentEnum)
Usecittyfor CLI,consolafor logging,getEnvVar()for environment validation, and exit with 0/1 appropriately
New TypeScript helpers must be covered by a colocated*.test.tsfile 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 fromdemoScriptHelpers. 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 thesrc/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.txtfor 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 contractsAfter Solidity changes, run
forge test(or note suites remaining)
**/*.sol: Own files must use// SPDX-License-Identifier: LGPL-3.0-onlyimmediately followed by the pragma statement with no blank line in between
All contracts must usepragma 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),@noticedescribing 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 fromsrc/Errors/GenericErrors.sol; bump@custom:versionwhen 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 implementationsDo 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 insrc/Facets/directory with names containingFacet
Facets must implement required functions:_startBridge(internal),swapAndStartBridgeTokensVia{FacetName}, andstartBridgeTokensVia{FacetName}
Facets must use modifiers:nonReentrant,refundExcessNative,validateBridgeData,doesNotContainSourceSwaps/doesContainSourceSwaps,doesNotContainDestinationCalls/doesContainDestinationCallson applicable functions
In Solidity facets,receiverAddressmust be the first parameter in{facetName}Dataand must matchbridgeData.receiverfor EVM chains
In Solidity facets, validatetargetChainIdagainstbridgeData.destinationChainfor EVM-to-EVM bridges
Facets must use LibAsset, LibSwap, and LibAllowList utilities along with Validatable and SwapperV2 interfaces; reserve native fees via_depositAndSwapvariants when needed
In Solidity facets withminAmountOutor similar bridge parameters, update the bridge's minAmountOut inswapAndStartBridgeTokensVia{FacetName}to account for positive slippage from swaps after_depositAndSwapupdates_bridgeData.minAmount, adjusting proportionally for decimal differences if applicable
For non-EVM receivers in Solidity facets, usebytestype; the value must be non-zero
For non-EVM flows in Solidity facets,bridgeData.receivermust equalNON_EVM_ADDRESS
In Solidity facets with{facetName}Data.receiverAddressfield (e.g.,_glacisData.receiverAddress), validate that it is notbytes32(0)for non-EVM chains and revert withInvalidNonEVMReceiver()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 thoroughlyAll contracts in
src/require audits except Interfaces insrc/Interfaces/**(type definitions only) and external dependencies inlib/
src/**/*.sol: NatSpec required on contracts/interfaces insrc/:@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 overmsg.senderfor refund addresses.
In Solidity 0.8.17, you must not emit events usingContractName.EventNamesyntax (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.tssrc/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.tssrc/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.tssrc/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.tssrc/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.tssrc/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.tssrc/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.tssrc/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.tssrc/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.tssrc/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
startBridgeTokensViaAcrossV4Swapfunction properly implements the required pattern with all necessary modifiers (nonReentrant, refundExcessNative, validateBridgeData, doesNotContainSourceSwaps, doesNotContainDestinationCalls) and delegates to the internal_startBridgefunction.
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
minExpectedInputTokenAmountbased 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 usessetupEnvironment()fromdemoScriptHelpersto initialize viem clients. The API request preparation properly setsskipOriginTxEstimation: 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'srandomBytes) 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.
…across-swap-facet
There was a problem hiding this comment.
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 {}.
script/helperFunctions.sh
Outdated
| # 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 |
There was a problem hiding this comment.
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)
fiThe 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 {}.
There was a problem hiding this comment.
@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.
There was a problem hiding this comment.
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)
…across-swap-facet
There was a problem hiding this comment.
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:trapon EXIT overwrites any caller-set EXIT trap, risking cleanup leaks.
saveDiamondFacetsis sourced into many scripts. Settingtrap ... EXIThere unconditionally replaces whatever EXIT trap the caller (or a prior call) registered. Contrast this withexecuteAndCapture(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' EXITAnd 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.
There was a problem hiding this comment.
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:localmasks return values of command substitutions.Lines 4363 and 4370 combine
localdeclaration 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: samelocal+ 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 fromtypechain/directory.”
Which Jira task belongs to this PR?
N/A - Implementation based on technical planning in
scratch/across-plan.mdWhy 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:The periphery contract provides:
Implementation Details
7 Phase Implementation:
startBridgeTokensViaAcrossV4Swap()(bridge only) andswapAndStartBridgeTokensViaAcrossV4Swap()(LiFi swap + bridge)Scope Limitations (Gasful Flow Only):
Files Changed:
src/Interfaces/ISpokePoolPeriphery.sol(NEW) - Periphery contract interfacesrc/Facets/AcrossV4SwapFacet.sol(NEW) - Main facet implementationconfig/across-v4-swap.json(NEW) - Network configurationscript/deploy/facets/DeployAcrossV4SwapFacet.s.sol(NEW) - Deployment scriptscript/deploy/facets/UpdateAcrossV4SwapFacet.s.sol(NEW) - Update scripttest/solidity/Facets/AcrossV4SwapFacet.t.sol(NEW) - Test suitedocs/AcrossV4SwapFacet.md(NEW) - Complete documentationscript/demoScripts/demoAcrossV4Swap.ts(NEW) - Demo script templateChecklist before requesting a review
Notes on Test Failures:
4 tests fail with expected behavior:
testBase_CanBridgeTokenstestBase_CanBridgeTokens_fuzzedtestBase_CanSwapAndBridgeTokenstestBase_Revert_BridgeWithInvalidDestinationCallFlagReason: 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!!!)
Next Steps Before Mainnet:
0x649C790f02B7e04a5A2e60b6EE6e7d5B2E6B29A5on all networks