-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement ChainflipFacet [ChainflipFacet v1.0.0,IChainflip v1.0.0,ReceiverChainflip v1.0.0] #984
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThese changes introduce new functionality for Chainflip bridging across multiple networks. A JSON configuration file for vault addresses is added, along with updated documentation for the Chainflip Facet. New smart contracts are implemented, including ChainflipFacet, ReceiverChainflip, and IChainflipVault. Deployment scripts are enhanced, and demo scripts for swapping exact ETH for ERC20 tokens are introduced. Extensive unit tests for the new contracts are included. Additionally, deployment configuration JSON files are modified to reflect new facet entries, version updates, and other relevant changes. Changes
Suggested labels
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (5)
src/Facets/ChainflipFacet.sol (2)
13-13
: Remove debug import in production.It seems you're importing the
console
utility (line 13) for debugging. Consider removing or wrapping it with conditional compilation for production to avoid unnecessary overhead or inadvertent log leakage.-import { console } from "forge-std/console.sol";
100-159
: Future-proof chain ID mappings.The chain ID checks and consistent reverts for unsupported chains are well-defined. To accommodate future expansions, consider a more flexible mechanism (whitelisting, mapping, or dynamic registry) to reduce the need to modify contract code for additional chains.
script/deploy/facets/UpdateChainflipFacet.s.sol (1)
1-1
: License compatibility check.Currently the file is marked as
UNLICENSED
, while other contracts useMIT
. This is typically fine for a deployment script, but confirm it aligns with your project’s licensing policy.test/solidity/Facets/ChainflipFacet.t.sol (1)
74-78
: Add test cases for invalid ChainflipData parameters.The validChainflipData setup uses hardcoded values. Consider adding test cases for invalid parameters.
+ function testRevert_InvalidChainflipData() public { + ChainflipFacet.ChainflipData memory invalidData = ChainflipFacet.ChainflipData({ + dstToken: 0, + cfParameters: "" + }); + vm.expectRevert("Invalid destination token"); + chainflipFacet.startBridgeTokensViaChainflip(bridgeData, invalidData); + }docs/ChainflipFacet.md (1)
35-35
: Fix typo in swap documentation.The sentence has a grammatical error.
-Swapping is performed by a swap specific library that expects an array of calldata to can be run on various DEXs +Swapping is performed by a swap-specific library that expects an array of calldata that can be run on various DEXs🧰 Tools
🪛 LanguageTool
[uncategorized] ~35-~35: When ‘swap-specific’ is used as a modifier, it is usually spelled with a hyphen.
Context: ... parameter. Swapping is performed by a swap specific library that expects an array of callda...(SPECIFIC_HYPHEN)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
config/chainflip.json
(1 hunks)docs/ChainflipFacet.md
(1 hunks)script/demoScripts/demoChainflip.ts
(1 hunks)script/deploy/facets/DeployChainflipFacet.s.sol
(1 hunks)script/deploy/facets/UpdateChainflipFacet.s.sol
(1 hunks)src/Facets/ChainflipFacet.sol
(1 hunks)src/Interfaces/IChainflip.sol
(1 hunks)test/solidity/Facets/ChainflipFacet.t.sol
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- config/chainflip.json
🧰 Additional context used
🪛 LanguageTool
docs/ChainflipFacet.md
[uncategorized] ~35-~35: When ‘swap-specific’ is used as a modifier, it is usually spelled with a hyphen.
Context: ... parameter. Swapping is performed by a swap specific library that expects an array of callda...
(SPECIFIC_HYPHEN)
[uncategorized] ~47-~47: Possible missing comma found.
Context: ...alls to interact with the Facet In the following some sample calls are shown that allow ...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~88-~88: Possible missing comma found.
Context: ...er from 30 USDT on Avalanche to USDC on Binance you can execute the following request: ...
(AI_HYDRA_LEO_MISSING_COMMA)
🪛 GitHub Actions: VersionControlAndAuditVerification
src/Interfaces/IChainflip.sol
[error] 1-1: File does not contain a version tag. Every version-controlled contract needs to have a custom:version tag in its code.
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: run-unit-tests
- GitHub Check: enforce-min-test-coverage
🔇 Additional comments (3)
src/Facets/ChainflipFacet.sol (2)
52-72
: Implementation of direct bridging logic looks consistent.The logic for depositing assets and then calling
_startBridge
appears sound. Good use of existing modifiers such asnonReentrant
,refundExcessNative
, and the validation checks.
74-98
: Implementation of swap-then-bridge flow is clear.The approach of performing swaps first with
_depositAndSwap
before calling_startBridge
is well-structured. The finalminAmount
assignment ensures correct bridging amounts. Nicely done.script/deploy/facets/DeployChainflipFacet.s.sol (1)
24-30
: Verify configuration path handling.The path construction assumes a specific directory structure. Consider adding validation to ensure the config file exists.
✅ Verification successful
🏁 Script executed:
#!/bin/bash # Check if the chainflip config file exists if [ ! -f "config/chainflip.json" ]; then echo "Error: chainflip.json configuration file not found" exit 1 fi # Validate JSON structure jq -e '.mainnet.chainflipVault, .arbitrum.chainflipVault' config/chainflip.json > /dev/nullLength of output: 120
Configuration path handling verified.
The shell script confirms that the expected configuration file (config/chainflip.json
) exists and contains valid JSON entries for bothmainnet.chainflipVault
andarbitrum.chainflipVault
. No issues were detected with the configuration path, so additional validation in this area appears unnecessary.
Test Coverage ReportLine Coverage: 79.00% (2104 / 2663 lines) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (5)
script/demoScripts/demoChainflip.ts (2)
40-41
: Consider using environment variables for token addresses.The USDC token address is hardcoded. For better flexibility and to prevent accidental deployments with incorrect addresses, consider using environment variables.
-const SRC_TOKEN_ADDRESS = - '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as `0x${string}` +if (!process.env.SRC_TOKEN_ADDRESS) { + throw new Error('SRC_TOKEN_ADDRESS environment variable is required') +} +const SRC_TOKEN_ADDRESS = process.env.SRC_TOKEN_ADDRESS as `0x${string}`
92-101
: Consider adding error handling for bridge failures.The bridge transaction could fail for various reasons (e.g., insufficient liquidity, network issues). Consider adding specific error handling and retry logic.
await executeTransaction( () => lifiDiamondContract.write.startBridgeTokensViaChainflip([ bridgeData, chainflipData, ]), 'Starting bridge tokens via Chainflip', publicClient, true + // Add retry options + { + maxRetries: 3, + retryDelay: 1000, + onError: (error) => { + console.error('Bridge failed:', error) + // Add specific error handling based on error type + } + } )src/Facets/ChainflipFacet.sol (1)
31-39
: Consider using an enum or mapping for chain IDs.The current implementation uses constants for chain IDs. Consider using an enum or mapping for better maintainability and to prevent magic numbers.
- uint256 private constant CHAIN_ID_ETHEREUM = 1; - uint256 private constant CHAIN_ID_ARBITRUM = 42161; - uint256 private constant CHAIN_ID_SOLANA = 1151111081099710; - uint256 private constant CHAIN_ID_BITCOIN = 20000000000001; - - uint32 private constant CHAINFLIP_ID_ETHEREUM = 1; - uint32 private constant CHAINFLIP_ID_ARBITRUM = 4; - uint32 private constant CHAINFLIP_ID_SOLANA = 5; - uint32 private constant CHAINFLIP_ID_BITCOIN = 3; + enum ChainId { + ETHEREUM = 1, + ARBITRUM = 42161, + SOLANA = 1151111081099710, + BITCOIN = 20000000000001 + } + + mapping(ChainId => uint32) private chainflipIds = { + ChainId.ETHEREUM: 1, + ChainId.ARBITRUM: 4, + ChainId.SOLANA: 5, + ChainId.BITCOIN: 3 + };test/solidity/Facets/ChainflipFacet.t.sol (2)
81-85
: Add test cases for different destination token IDs.The test suite uses a fixed destination token ID of 6. Consider adding test cases for different token IDs to ensure the contract handles various scenarios correctly.
+ function test_CanBridgeTokensWithDifferentDestinationTokens() public { + uint32[] memory tokenIds = new uint32[](3); + tokenIds[0] = 6; // USDC + tokenIds[1] = 1; // Example token + tokenIds[2] = 2; // Example token + + for (uint256 i = 0; i < tokenIds.length; i++) { + validChainflipData.dstToken = tokenIds[i]; + vm.startPrank(USER_SENDER); + usdc.approve(_facetTestContractAddress, bridgeData.minAmount); + initiateBridgeTxWithFacet(false); + vm.stopPrank(); + } + }
219-236
: Add more edge cases for address validation.The test only checks for empty addresses. Consider adding tests for invalid address formats and other edge cases.
+ function testRevert_WhenUsingInvalidSolanaAddress() public { + bridgeData.receiver = LibAsset.NON_EVM_ADDRESS; + bridgeData.destinationChainId = CHAIN_ID_SOLANA; + validChainflipData = ChainflipFacet.ChainflipData({ + dstToken: 6, + nonEvmAddress: bytes32("invalid_solana_address"), + cfParameters: "" + }); + + vm.startPrank(USER_SENDER); + usdc.approve(_facetTestContractAddress, bridgeData.minAmount); + vm.expectRevert("Invalid Solana address format"); + initiateBridgeTxWithFacet(false); + vm.stopPrank(); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
script/demoScripts/demoChainflip.ts
(1 hunks)script/deploy/facets/UpdateChainflipFacet.s.sol
(1 hunks)src/Facets/ChainflipFacet.sol
(1 hunks)test/solidity/Facets/ChainflipFacet.t.sol
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- script/deploy/facets/UpdateChainflipFacet.s.sol
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: generate-tag
🔇 Additional comments (3)
script/demoScripts/demoChainflip.ts (1)
84-89
: Verify the destination token ID.The destination token ID is hardcoded to
6
. Ensure this is the correct token ID for the destination chain.✅ Verification successful
🏁 Script executed:
#!/bin/bash # Search for any references to token IDs in the codebase to verify the correct value rg -A 5 "dstToken: 6" .Length of output: 2304
Destination Token ID Verification Confirmed
The codebase consistently sets
dstToken
to6
in both the demo script and the test cases, implying that this value is intended for the destination chain. No discrepancies were found.src/Facets/ChainflipFacet.sol (1)
153-181
: Add reentrancy protection for token transfers.While the contract inherits from
ReentrancyGuard
, ensure that thenonReentrant
modifier is applied to all external methods that handle token transfers.❌ Verification inconclusive
🏁 Script executed:
#!/bin/bash # Search for external methods that handle token transfers ast-grep --pattern 'function $name($_) external $_ { $$$ transfer($_) $$$ }'Length of output: 84
Action Required: Manually Verify NonReentrant Usage on External Token Transfer Methods
The initial automated search for a direct call to thetransfer
function did not produce any output. This suggests that token transfers may be performed indirectly (e.g., via the helperLibAsset.maxApproveERC20
or through external vault calls likexSwapNative
andxSwapToken
) rather than via explicit in-linetransfer
calls. However, the review comment raises a valid concern about ensuring that all externally callable methods that trigger token transfers are properly protected with thenonReentrant
modifier.To ensure that the contract is secure:
- Manually inspect the external functions in
src/Facets/ChainflipFacet.sol
that perform token operations (such as those invokingLibAsset.maxApproveERC20
,xSwapNative
, orxSwapToken
).- Confirm that each such function is indeed decorated with the
nonReentrant
modifier.- If any token transfer–handling function lacks this protection, add the modifier to mitigate potential reentrancy issues.
Since our automated search did not yield definitive evidence (likely due to abstraction of token transfers), please manually review the relevant functions to ensure robust reentrancy protection.
test/solidity/Facets/ChainflipFacet.t.sol (1)
149-183
: Add validation for Solana address format.The test uses a hardcoded Solana address. Consider adding validation to ensure the address follows the correct format.
❌ Verification inconclusive
🏁 Script executed:
#!/bin/bash # Search for Solana address validation in the codebase rg -A 5 "Solana.*address.*validation" .Length of output: 41
Issue: Missing Validation for Solana Address Format
Our search confirms that there is no dedicated Solana address format validation logic anywhere in the codebase. The test in
test/solidity/Facets/ChainflipFacet.t.sol
is using a hardcoded Solana address without an accompanying check to ensure that the provided address conforms to expected Solana formatting guidelines. It is recommended that you add validation logic—either within the facet or before initiating the bridge transaction—to enforce the correct format for Solana addresses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/Periphery/ReceiverChainflip.sol (1)
82-111
: Catch block discards revert reason.The
try ... catch {}
without capturing the revert reason helps automatically recover tokens but obscures debugging. If clarity is desired, considercatch Error(string memory reason)
to log or emit the reason for easier troubleshooting.Example:
} catch (bytes memory reason) { + // Optionally, decode or log the revert reason assetId.safeTransfer(receiver, amount); emit LiFiTransferRecovered( _transactionId, assetId, receiver, amount, block.timestamp ); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/Periphery/ReceiverChainflip.sol
(1 hunks)test/solidity/Periphery/ReceiverChainflip.t.sol
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: generate-tag
🔇 Additional comments (7)
src/Periphery/ReceiverChainflip.sol (3)
19-21
: Validate non-zero addresses for immutables.Consider adding a check in the constructor to ensure that both
_executor
and_chainflipVault
are non-zero addresses to prevent misconfiguration or accidental deployment with a null address.Possible improvement example:
constructor( address _owner, address _executor, address _chainflipVault ) WithdrawablePeriphery(_owner) { + require(_executor != address(0), "Executor address cannot be zero"); + require(_chainflipVault != address(0), "Chainflip vault address cannot be zero"); executor = IExecutor(_executor); chainflipVault = _chainflipVault; }
22-29
: Modifier ensures restricted access.The
onlyChainflipVault
modifier is concise and securely enforces access restrictions tocfReceive
. This is a good approach to limit privileged calls solely to the designated Chainflip vault.
113-115
: Empty fallback is acceptable.The fallback function is correctly defined to receive native tokens. No further changes are required here.
test/solidity/Periphery/ReceiverChainflip.t.sol (4)
25-48
: Initialization covers essential paths.The
setUp()
function covers adequate setup steps, including reading configuration JSON files, labeling addresses for clarity, and deploying required contracts. This is well-structured and thorough.
50-59
: Constructor test is simple and effective.
test_contractIsSetUpCorrectly()
verifies key contract invariants (executor address, vault address). Spelling out these checks is a solid way to confirm proper deployment parameters.
112-139
: Ensures privileged function is restricted.
test_revert_OnlyChainflipVaultCanCallCfReceive()
properly checks that unauthorized entities cannot invokecfReceive
. This adds robust coverage for permission logic.
173-216
: Recovery flow verified.
test_willReturnFundsToUserIfDstCallFails()
demonstrates correct handling when a destination swap fails, ensuring user funds are returned. This thoroughly verifies error-handling and token recovery.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (7)
docs/ChainflipFacet.md (6)
13-19
: Clarify Public Methods Documentation
The public methods are clearly listed along with concise descriptions. To further improve clarity, consider adding parameter-specific details or linking to corresponding implementation sections so that readers can easily cross-reference the information.
32-32
: Enhance Guidance on Non-EVM Destinations
The note on setting thereceiver
inBridgeData
for non-EVM destinations is useful. It might help to include a brief example or clarification on edge cases to further support developers using this configuration.
43-49
: Improve Terminology: Use "swap-specific"
On line 47, the phrase "swap specific library" is used. For clarity and consistency with common terminology, consider using a hyphen to form "swap-specific library."-Swapping is performed by a swap specific library that expects an array of calldata... +Swapping is performed by a swap-specific library that expects an array of calldata...🧰 Tools
🪛 LanguageTool
[uncategorized] ~47-~47: When ‘swap-specific’ is used as a modifier, it is usually spelled with a hyphen.
Context: ... parameter. Swapping is performed by a swap specific library that expects an array of callda...(SPECIFIC_HYPHEN)
86-88
: Enhance In-Text Explanation for the /quote Endpoint
The link to detailed documentation is helpful. To aid quick understanding, consider including a short inline summary of the key steps involved in using the/quote
endpoint.
90-97
: Punctuation Improvement in "Cross Only" Section
For improved readability, add a comma after "Arbitrum" in line 92.-To get a transaction for a transfer from USDC on Ethereum to USDC on Arbitrum you can execute the following request: +To get a transaction for a transfer from USDC on Ethereum to USDC on Arbitrum, you can execute the following request:🧰 Tools
🪛 LanguageTool
[uncategorized] ~92-~92: Possible missing comma found.
Context: ...ansfer from USDC on Ethereum to USDC on Arbitrum you can execute the following request: ...(AI_HYDRA_LEO_MISSING_COMMA)
98-104
: Punctuation Improvement in "Swap & Cross" Section
Similarly, in line 100, consider inserting a comma after "Arbitrum" to enhance clarity.-To get a transaction for a transfer from USDT on Ethereum to USDC on Arbitrum you can execute the following request: +To get a transaction for a transfer from USDT on Ethereum to USDC on Arbitrum, you can execute the following request:🧰 Tools
🪛 LanguageTool
[uncategorized] ~100-~100: Possible missing comma found.
Context: ...ansfer from USDT on Ethereum to USDC on Arbitrum you can execute the following request: ...(AI_HYDRA_LEO_MISSING_COMMA)
script/deploy/facets/DeployReceiverChainflip.s.sol (1)
24-59
: Configuration parsing is appropriate—consider validating missing or zero addresses.
The code properly reads from multiple JSON config files and returns addresses viaabi.encode
. Ensure the final constructor argument order matches theReceiverChainflip
contract requirements. It may be wise to guard against zero addresses if configurations are missing.function getConstructorArgs() internal override returns (bytes memory) { ... + require(refundWalletAddress != address(0), "Invalid refund wallet"); + require(chainflipVault != address(0), "Invalid vault address"); + require(executor != address(0), "Invalid executor address"); return abi.encode(refundWalletAddress, executor, chainflipVault); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
docs/ChainflipFacet.md
(1 hunks)script/deploy/facets/DeployReceiverChainflip.s.sol
(1 hunks)script/deploy/resources/deployRequirements.json
(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
script/deploy/facets/DeployReceiverChainflip.s.sol (1)
Learnt from: ezynda3
PR: lifinance/contracts#924
File: script/deploy/zksync/DeployReceiverStargateV2.s.sol:19-21
Timestamp: 2025-01-28T14:27:50.689Z
Learning: In LiFi's deployment scripts, the `deploy` method in `DeployScriptBase` handles the concatenation of constructor arguments with the contract's creation code, so child contracts don't need to concatenate the arguments explicitly.
🪛 LanguageTool
docs/ChainflipFacet.md
[uncategorized] ~47-~47: When ‘swap-specific’ is used as a modifier, it is usually spelled with a hyphen.
Context: ... parameter. Swapping is performed by a swap specific library that expects an array of callda...
(SPECIFIC_HYPHEN)
[uncategorized] ~92-~92: Possible missing comma found.
Context: ...ansfer from USDC on Ethereum to USDC on Arbitrum you can execute the following request: ...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~100-~100: Possible missing comma found.
Context: ...ansfer from USDT on Ethereum to USDC on Arbitrum you can execute the following request: ...
(AI_HYDRA_LEO_MISSING_COMMA)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: generate-tag
🔇 Additional comments (14)
script/deploy/resources/deployRequirements.json (2)
572-581
: ChainflipFacet Configuration AdditionThe new
"ChainflipFacet"
entry follows the same structure as the existing entries. The use of"configData"
with the_chainflipVault
key, along with the provided"configFileName"
,"keyInConfigFile"
, and"allowToDeployWithZeroAddress": "false"
, is consistent with the project's configuration conventions.
Please verify that the"chainflip.json"
file is properly set up and that the placeholder<NETWORK>
is used consistently with other facets.
582-600
: ReceiverChainflip Configuration AdditionThe
"ReceiverChainflip"
configuration is well-formed. It correctly defines its"configData"
with both the_owner
(using"global.json"
and".refundWallet"
) and_chainflipVault
keys (mirroring the settings of"ChainflipFacet"
). In addition, the inclusion of the"contractAddresses"
section for"Executor"
with"allowToDeployWithZeroAddress": "false"
aligns with the structure seen in other receiver configurations.
Ensure that these settings correctly map to the deployed contracts and that external calls to these addresses are properly validated per security best practices.docs/ChainflipFacet.md (7)
1-6
: Expand the "How it works" Section for Greater Clarity
The introduction is clear but could benefit from additional technical details. Consider elaborating on how the ChainflipFacet interacts with the ChainflipVault using DELEGATECALL and outlining the token transfer flow in more depth.
7-11
: Effective Use of Mermaid Diagram
The Mermaid diagram visually explains the relationship between LiFiDiamond, ChainflipFacet, and Chainflip Vault well. As a suggestion, you might add labels or a brief legend if the diagram expands in complexity in the future.
20-30
: Accurate and Informative ChainflipData Struct Documentation
TheChainflipData
struct is well documented and clearly explains the purpose of each parameter. Ensure that any future changes to the contract implementation are also reflected here to maintain consistency.
34-42
: Clear Overview of Supported Chains
The section on supported chains is informative. For added clarity, consider linking to external references or documentation that verifies these chain IDs.
51-55
: Solid Explanation of LiFi Data Usage
The explanation regarding theBridgeData
parameter and its role for analytics is clear and sufficient.
57-62
: Clear Introduction to Sample Calls
The introductory text for sample calls sets the context well. It might be helpful to mention any prerequisites or assumptions briefly for developers new to the API.
63-84
: Well-Structured JavaScript Example for Quote Result
The JavaScript snippet illustrating thequoteResult
object is both clear and illustrative. Please ensure that if any field names change in the future, the example is updated accordingly.script/deploy/facets/DeployReceiverChainflip.s.sol (5)
1-3
: License and compiler version look fine.
These lines indicate a non-open source license and a modern Solidity compiler version, which are acceptable choices.
4-7
: Imports are concise and well-structured.
All imports are relevant and appear to be aligned with the contract's deployment logic. No issues found.
8-10
: Contract declaration and library usage look good.
ThestdJson
library is correctly applied to handle JSON parsing. No concerns here.
11-12
: Constructor usage is consistent with the base class.
Passing"ReceiverChainflip"
to the parent constructor follows the known pattern forDeployScriptBase
.
13-22
: Deploy logic appears correct but verify constructor argument handling.
Callingdeploy(type(ReceiverChainflip).creationCode)
without manual argument concatenation is correct becauseDeployScriptBase
handles appending the constructor arguments internally. Confirm that theReceiverChainflip
constructor satisfies this approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
test/solidity/Facets/ChainflipFacet.t.sol (3)
34-86
: Add error handling for config file operations.The setup process could be more robust with proper error handling for file operations and JSON parsing.
Consider adding checks:
string memory path = string.concat( vm.projectRoot(), "/config/chainflip.json" ); +require(vm.isFile(path), "Config file not found"); string memory json = vm.readFile(path); +require(bytes(json).length > 0, "Config file is empty"); CHAINFLIP_VAULT = json.readAddress(".mainnet.chainflipVault"); +require(CHAINFLIP_VAULT != address(0), "Invalid vault address in config");
120-147
: Add documentation for the override methods.While the implementation is correct, adding documentation would improve maintainability.
Consider adding NatSpec documentation:
+/// @notice Initiates a bridge transaction using the ChainflipFacet +/// @param isNative Boolean indicating if the transaction involves native tokens +/// @dev This is an override of the TestBaseFacet method function initiateBridgeTxWithFacet(bool isNative) internal override {
149-217
: Consider adding more edge cases to the bridging tests.While the current tests cover the basic functionality, consider adding tests for:
- Invalid destination token IDs
- Malformed non-EVM addresses
- Maximum and minimum amount boundaries
script/demoScripts/demoChainflip.ts (1)
86-91
: Consider making ChainflipData values configurable.The current implementation uses hardcoded values which could limit the script's flexibility:
dstToken
is hardcoded to 3 (USDC)nonEvmAddress
is hardcoded to zero addresscfParameters
is hardcoded to empty bytesConsider making these values configurable through environment variables or command-line arguments for better reusability:
+const DST_TOKEN = process.env.DST_TOKEN || 3 +const NON_EVM_ADDRESS = process.env.NON_EVM_ADDRESS || '0x0000000000000000000000000000000000000000000000000000000000000000' +const CF_PARAMETERS = process.env.CF_PARAMETERS || '0x' const chainflipData: ChainflipFacet.ChainflipDataStruct = { - dstToken: 3, // USDC - nonEvmAddress: - '0x0000000000000000000000000000000000000000000000000000000000000000', - cfParameters: '0x', // Empty parameters as per implementation + dstToken: DST_TOKEN, + nonEvmAddress: NON_EVM_ADDRESS, + cfParameters: CF_PARAMETERS, }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
deployments/_deployments_log_file.json
(1 hunks)script/demoScripts/demoChainflip.ts
(1 hunks)script/demoScripts/utils/demoScriptHelpers.ts
(2 hunks)test/solidity/Facets/ChainflipFacet.t.sol
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- deployments/_deployments_log_file.json
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: generate-tag
🔇 Additional comments (9)
test/solidity/Facets/ChainflipFacet.t.sol (3)
1-10
: LGTM! Well-structured imports and declarations.The file uses an appropriate Solidity version and imports all necessary dependencies.
11-22
: LGTM! Well-designed test stub contract.The TestChainflipFacet provides appropriate helper methods for testing while maintaining the core functionality of ChainflipFacet.
219-236
: LGTM! Good negative test case.The test properly verifies the contract's behavior with an empty non-EVM address.
script/demoScripts/demoChainflip.ts (4)
1-28
: LGTM!The imports and setup are well-organized with proper type safety using
Narrow
.
94-135
: LGTM!The swap implementation is well-structured with proper slippage handling and error checking.
137-146
: LGTM!The direct bridging implementation is clean and straightforward.
150-155
: LGTM!The error handling is appropriate with proper process exit codes.
script/demoScripts/utils/demoScriptHelpers.ts (2)
183-195
: LGTM!The refactored minAmountOut calculation is more readable and maintainable. The 1% slippage tolerance is a reasonable default.
312-312
: Verify the increased slippage tolerance.The slippage tolerance has been increased from 5% to 10%. While this provides more flexibility in volatile markets, it also increases the risk of unfavorable trades.
Please confirm if this increase is intentional and aligns with the project's risk tolerance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
script/demoScripts/demoChainflip.ts (4)
28-34
: Use constants for chain IDs and validate token addresses.Consider these improvements:
- Define chain IDs as constants or enums for better maintainability
- Add validation for token addresses
+const MAINNET_CHAIN_ID = 1 +const ARBITRUM_CHAIN_ID = 42161 async function main() { const withSwap = process.argv.includes('--with-swap') const srcTokenAddress = withSwap ? ADDRESS_USDT_ARB : ADDRESS_USDC_ARB + if (srcTokenAddress === undefined) { + throw new Error('Source token address is undefined') + } // === Set up environment === const srcChain: SupportedChain = 'arbitrum' - const destinationChainId = 1 // Mainnet + const destinationChainId = MAINNET_CHAIN_ID
78-83
: Improve ChainflipData configuration.
- Define constants for Chainflip token designators
- Document the purpose of cfParameters
- Use constants for zero address values
+// Chainflip token designators +const CF_TOKEN_DESIGNATORS = { + USDC_ETH: 3, +} as const +// Constants +const ZERO_BYTES32 = '0x' + '0'.repeat(64) const chainflipData: ChainflipFacet.ChainflipDataStruct = { - dstToken: 3, // Chainflip designator for USDC on ETH + dstToken: CF_TOKEN_DESIGNATORS.USDC_ETH, nonEvmAddress: - '0x0000000000000000000000000000000000000000000000000000000000000000', + ZERO_BYTES32, + // cfParameters is left empty as per Chainflip's implementation + // It may be used for future protocol upgrades cfParameters: '0x', // Empty parameters as per implementation }
85-137
: Enhance error handling and transaction monitoring.Consider these improvements:
- Add try-catch blocks for better error handling
- Enhance transaction status logging
- Extract swap data generation to a separate function
+async function generateSwapData( + amount: bigint, + lifiDiamondAddress: string +): Promise<any> { + return getUniswapDataERC20toExactERC20( + ADDRESS_UNISWAP_ARB, + 42161, + ADDRESS_USDT_ARB, + ADDRESS_USDC_ARB, + amount, + lifiDiamondAddress, + true + ) +} if (withSwap) { + try { - const swapData = await getUniswapDataERC20toExactERC20( - ADDRESS_UNISWAP_ARB, - 42161, - ADDRESS_USDT_ARB, - ADDRESS_USDC_ARB, - amount, - lifiDiamondAddress, - true - ) + const swapData = await generateSwapData(amount, lifiDiamondAddress) // ... rest of the code + } catch (error) { + console.error('Failed to generate swap data:', error) + throw error + } }
139-144
: Improve error handling in the main execution.Enhance error handling to provide more context and structured error information.
main() .then(() => process.exit(0)) .catch((error) => { - console.error(error) + console.error('Script execution failed:') + if (error instanceof Error) { + console.error('Error message:', error.message) + console.error('Stack trace:', error.stack) + } else { + console.error('Unknown error:', error) + } process.exit(1) })
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
deployments/_deployments_log_file.json
(1 hunks)script/demoScripts/demoChainflip.ts
(1 hunks)script/demoScripts/utils/demoScriptHelpers.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- script/demoScripts/utils/demoScriptHelpers.ts
- deployments/_deployments_log_file.json
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: protect_audit_labels
🔇 Additional comments (1)
script/demoScripts/demoChainflip.ts (1)
1-27
: LGTM!The imports and setup are well-organized with proper type safety using Narrow.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/Interfaces/IChainflip.sol
(1 hunks)
🧰 Additional context used
🪛 GitHub Actions: Enforce Min Test Coverage
src/Interfaces/IChainflip.sol
[error] 12-12: Expected '(' but got identifier.
[warning] 12-12: --ir-minimum
enables viaIR with minimum optimization, which can result in inaccurate source mappings.
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: run-unit-tests
🔇 Additional comments (1)
src/Interfaces/IChainflip.sol (1)
9-27
: Well-structured interface design!The interface is well-designed with:
- Clear parameter naming
- Appropriate use of the
payable
modifier for native token swaps- Consistent parameter ordering between methods
🧰 Tools
🪛 GitHub Actions: Enforce Min Test Coverage
[error] 12-12: Expected '(' but got identifier.
[warning] 12-12:
--ir-minimum
enables viaIR with minimum optimization, which can result in inaccurate source mappings.
…nto LF-12192-chainflip
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/Periphery/ReceiverChainflip.sol (2)
28-29
: Document the source of CHAINFLIP_NATIVE_ADDRESS.Add a comment explaining why this specific address was chosen and its significance in the Chainflip protocol.
/// @notice Chainflip's native token address representation + /// @dev This address is used by Chainflip protocol to represent native tokens + /// @dev Reference: <add_chainflip_documentation_link> address internal constant CHAINFLIP_NATIVE_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
107-165
: Optimize token handling logic.The function can be optimized by:
- Reducing redundant native token checks
- Consolidating the try-catch blocks
- Moving the approval reset inside the catch block
function _swapAndCompleteBridgeTokens( bytes32 _transactionId, LibSwap.SwapData[] memory _swapData, address assetId, address payable receiver, uint256 amount ) private { - address actualAssetId = assetId == CHAINFLIP_NATIVE_ADDRESS - ? LibAsset.NATIVE_ASSETID - : assetId; - bool isNative = actualAssetId == LibAsset.NATIVE_ASSETID; + bool isNative = assetId == CHAINFLIP_NATIVE_ADDRESS; + address actualAssetId = isNative ? LibAsset.NATIVE_ASSETID : assetId; - if (!isNative) { - actualAssetId.safeApproveWithRetry(address(executor), amount); - try - executor.swapAndCompleteBridgeTokens( - _transactionId, - _swapData, - actualAssetId, - receiver - ) - { - return; - } catch { - actualAssetId.safeTransfer(receiver, amount); - emit LiFiTransferRecovered( - _transactionId, - actualAssetId, - receiver, - amount, - block.timestamp - ); - } - actualAssetId.safeApprove(address(executor), 0); - } else { - try - executor.swapAndCompleteBridgeTokens{ value: amount }( - _transactionId, - _swapData, - actualAssetId, - receiver - ) - { - return; - } catch { - receiver.safeTransferETH(amount); - emit LiFiTransferRecovered( - _transactionId, - actualAssetId, - receiver, - amount, - block.timestamp - ); - } - } + if (!isNative) { + actualAssetId.safeApproveWithRetry(address(executor), amount); + } + + try + executor.swapAndCompleteBridgeTokens{ value: isNative ? amount : 0 }( + _transactionId, + _swapData, + actualAssetId, + receiver + ) + { + if (!isNative) { + actualAssetId.safeApprove(address(executor), 0); + } + return; + } catch { + if (isNative) { + receiver.safeTransferETH(amount); + } else { + actualAssetId.safeTransfer(receiver, amount); + actualAssetId.safeApprove(address(executor), 0); + } + emit LiFiTransferRecovered( + _transactionId, + actualAssetId, + receiver, + amount, + block.timestamp + ); + } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/Periphery/ReceiverChainflip.sol
(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/Periphery/ReceiverChainflip.sol (2)
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Periphery/ReceiverChainflip.sol:49-71
Timestamp: 2025-02-13T08:56:27.487Z
Learning: The executor contract in ReceiverChainflip and other periphery contracts is a trusted component of the system, and therefore does not require additional reentrancy protection.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Periphery/ReceiverChainflip.sol:162-162
Timestamp: 2025-02-24T06:51:03.551Z
Learning: In periphery contracts like ReceiverChainflip, the receive function can be left open without access control as it's part of the intended design.
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: enforce-min-test-coverage
🔇 Additional comments (3)
src/Periphery/ReceiverChainflip.sol (3)
35-40
: LGTM!The modifier is well-implemented with proper access control and error handling.
73-95
: LGTM!The function is well-documented, properly restricted with the onlyChainflipVault modifier, and correctly handles unused parameters.
170-170
: LGTM!The empty payable receive function is part of the intended design for periphery contracts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/Periphery/ReceiverChainflip.sol (1)
106-164
: Consider optimizing gas usage.The function could be optimized by:
- Consolidating the native token checks into a single block
- Moving the approval reset outside the try-catch block
- Combining the duplicate event emission code
Here's a suggested optimization:
function _swapAndCompleteBridgeTokens( bytes32 _transactionId, LibSwap.SwapData[] memory _swapData, address assetId, address payable receiver, uint256 amount ) private { address actualAssetId = assetId == CHAINFLIP_NATIVE_ADDRESS ? LibAsset.NATIVE_ASSETID : assetId; bool isNative = actualAssetId == LibAsset.NATIVE_ASSETID; + bool success; if (!isNative) { - // ERC20 token operations actualAssetId.safeApproveWithRetry(address(executor), amount); - try - executor.swapAndCompleteBridgeTokens( - _transactionId, - _swapData, - actualAssetId, - receiver - ) - { - return; - } catch { - actualAssetId.safeTransfer(receiver, amount); - emit LiFiTransferRecovered( - _transactionId, - actualAssetId, - receiver, - amount, - block.timestamp - ); - } - actualAssetId.safeApprove(address(executor), 0); - } else { - // Native token operations - try - executor.swapAndCompleteBridgeTokens{ value: amount }( - _transactionId, - _swapData, - actualAssetId, - receiver - ) - { - return; - } catch { - receiver.safeTransferETH(amount); - emit LiFiTransferRecovered( - _transactionId, - actualAssetId, - receiver, - amount, - block.timestamp - ); - } } + + try + executor.swapAndCompleteBridgeTokens{ value: isNative ? amount : 0 }( + _transactionId, + _swapData, + actualAssetId, + receiver + ) + { + success = true; + } catch { + if (isNative) { + receiver.safeTransferETH(amount); + } else { + actualAssetId.safeTransfer(receiver, amount); + } + emit LiFiTransferRecovered( + _transactionId, + actualAssetId, + receiver, + amount, + block.timestamp + ); + } + + if (!isNative && !success) { + actualAssetId.safeApprove(address(executor), 0); + } }test/solidity/Periphery/ReceiverChainflip.t.sol (1)
106-246
: Add more balance assertions.Consider adding these balance checks to strengthen the tests:
- Verify executor balance before and after swaps
- Verify contract's token balance is 0 after failed swaps
- For native token tests, verify contract's ETH balance
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/Periphery/ReceiverChainflip.sol
(1 hunks)test/solidity/Periphery/ReceiverChainflip.t.sol
(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
test/solidity/Periphery/ReceiverChainflip.t.sol (1)
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Periphery/ReceiverChainflip.sol:48-62
Timestamp: 2025-02-24T09:35:34.908Z
Learning: Contract address validations for periphery contracts like ReceiverChainflip are handled in deployment scripts rather than in the constructor.
src/Periphery/ReceiverChainflip.sol (3)
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Periphery/ReceiverChainflip.sol:49-71
Timestamp: 2025-02-13T08:56:27.487Z
Learning: The executor contract in ReceiverChainflip and other periphery contracts is a trusted component of the system, and therefore does not require additional reentrancy protection.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Periphery/ReceiverChainflip.sol:48-62
Timestamp: 2025-02-24T09:35:34.908Z
Learning: Contract address validations for periphery contracts like ReceiverChainflip are handled in deployment scripts rather than in the constructor.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Periphery/ReceiverChainflip.sol:162-162
Timestamp: 2025-02-24T06:51:03.551Z
Learning: In periphery contracts like ReceiverChainflip, the receive function can be left open without access control as it's part of the intended design.
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: enforce-min-test-coverage
- GitHub Check: run-unit-tests
- GitHub Check: generate-tag
🔇 Additional comments (7)
src/Periphery/ReceiverChainflip.sol (3)
1-11
: LGTM!The contract structure and imports are well-organized. The use of SafeTransferLib for token transfers is a good security practice.
Also applies to: 16-19
20-61
: LGTM!The storage variables are correctly marked as immutable and the constructor includes appropriate zero address validations. As per the learnings, additional contract address validations are handled in deployment scripts.
72-94
: LGTM!The function is well-implemented with proper access control and message decoding. The execution flow is clear and follows the expected pattern.
test/solidity/Periphery/ReceiverChainflip.t.sol (4)
1-50
: LGTM!The test setup is comprehensive and well-organized, with proper initialization of all required contracts and clear labeling for debugging.
52-75
: LGTM!The constructor validation tests thoroughly check all zero address cases.
77-104
: Add event parameter checks.The test should verify event parameters using
vm.expectEmit(true, true, true, true, address(receiver))
for consistency with other tests.
342-409
: LGTM!The helper functions are well-implemented and properly documented, making the tests more maintainable.
🤖 GitHub Action: Security Alerts Review 🔍🚨 Unresolved Security Alerts Found! 🚨 🔴 View Alert - File: 🔴 View Alert - File: 🟢 Dismissed Security Alerts with Comments 🟢 View Alert - File: 🟢 View Alert - File: 🟢 View Alert - File: 🟢 View Alert - File: 🟢 View Alert - File: 🟢 View Alert - File: 🟢 View Alert - File: 🟢 View Alert - File: 🟢 View Alert - File: |
/// @custom:version 1.0.0 | ||
contract ChainflipFacet is ILiFi, ReentrancyGuard, SwapperV2, Validatable { | ||
/// Events /// | ||
event BridgeToNonEVMChain( |
Check warning
Code scanning / Olympix Integrated Security
Test functions fail to assert the emission of expected events, potentially missing critical contract behaviors. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/missing-events-assertion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
script/demoScripts/demoChainflip.ts (1)
80-80
:⚠️ Potential issueFix scope error for
lifiDiamondAddress
.The variable
lifiDiamondAddress
is declared withinmain()
(line 139) and doesn’t exist in the scope ofexecuteWithSourceSwap()
at line 80. This will lead to aReferenceError
. PasslifiDiamondAddress
explicitly as a parameter or define it in a shared scope.- amount, - lifiDiamondAddress, - true + amount, + lifiDiamondAddressParam, // define or pass as argument + true
🧹 Nitpick comments (8)
docs/ChainflipFacet.md (1)
45-45
: Use a hyphen for “swap-specific”.According to the static analysis tool and standard writing conventions, “swap specific” should be spelled with a hyphen. This improves clarity and professionalism.
- Swapping is performed by a swap specific library ... + Swapping is performed by a swap-specific library ...test/solidity/Facets/ChainflipFacet.t.sol (1)
467-486
: Rename function to reflect actual behavior.The test name
testRevert_WhenNonEVMAddressWithEVMReceiver
implies a revert, but the comment clearly states it should proceed normally for an EVM address, ignoring thenonEVMReceiver
. Rename this function to accurately describe the scenario:-function testRevert_WhenNonEVMAddressWithEVMReceiver() public { +function test_SucceedsWithNonEVMReceiverAndEVMAddress() public {src/Facets/ChainflipFacet.sol (6)
20-24
: Add unit tests to cover theBridgeToNonEVMChain
event emission.
While the event helps to identify non-EVM chain transfers, static analysis indicates that test functions may not assert its emission. Ensure your tests verify that the event is emitted with the correct parameters.🧰 Tools
🪛 GitHub Check: Olympix Integrated Security
[warning] 20-20:
Test functions fail to assert the emission of expected events, potentially missing critical contract behaviors. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/missing-events-assertion
65-69
: Validate that_chainflipVault
is an actual deployed contract.
Even though you ensure_chainflipVault
is non-zero, consider using a check (e.g.,Address.isContract
) to reduce the risk of deployment mistakes.
110-117
: Consider requiring_bridgeData.minAmount
to be above zero for bridging.
Although not strictly necessary, adding arequire
statement can help prevent pointless or accidental zero-amount bridges and enhance clarity for end users.
129-146
: Refactor to eliminate redundant zero-address checks for EVM vs. non-EVM.
Since_bridgeData.receiver == LibAsset.NON_EVM_ADDRESS
already funnels to a distinct code path, you might simplify the logic by merging repeated checks or using a small helper function to handle address encoding.
183-227
: Consolidate xCall / xSwap logic to reduce duplication.
Both EVM and non-EVM bridging code paths share almost identical logic for native vs. token-based calls. Consider extracting these into a single internal function parameterized by a boolean for native, which can streamline maintainability.
241-250
: Future-proof chain mapping to accommodate additional chains.
If more chains are integrated down the line, large if-else blocks may become cumbersome. Though mappings can’t be declared constant or immutable in Solidity, consider creating a separate registry contract with a reference to reduce potential code bloat.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
docs/ChainflipFacet.md
(1 hunks)script/demoScripts/demoChainflip.ts
(1 hunks)src/Facets/ChainflipFacet.sol
(1 hunks)test/solidity/Facets/ChainflipFacet.t.sol
(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
script/demoScripts/demoChainflip.ts (1)
Learnt from: ezynda3
PR: lifinance/contracts#984
File: script/demoScripts/demoChainflip.ts:89-97
Timestamp: 2025-02-17T07:35:27.790Z
Learning: Demo and test scripts can omit production safeguards like slippage protection to maintain simplicity and focus on demonstrating core functionality.
src/Facets/ChainflipFacet.sol (3)
Learnt from: ezynda3
PR: lifinance/contracts#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.
Learnt from: ezynda3
PR: lifinance/contracts#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.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Facets/ChainflipFacet.sol:157-179
Timestamp: 2025-02-17T07:34:42.595Z
Learning: In the Chainflip protocol, there is no way to verify or validate the gas budget for cross-chain calls at the smart contract level.
test/solidity/Facets/ChainflipFacet.t.sol (3)
Learnt from: ezynda3
PR: lifinance/contracts#984
File: test/solidity/Facets/ChainflipFacet.t.sol:81-87
Timestamp: 2025-02-21T09:09:15.973Z
Learning: The `cfParameters` field in ChainflipFacet's ChainflipData struct is not used in the current implementation and serves as a placeholder.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: test/solidity/Facets/ChainflipFacet.t.sol:269-269
Timestamp: 2025-02-21T09:05:22.118Z
Learning: Fixed gas amounts in test files (e.g., ChainflipFacet.t.sol) don't require extensive documentation or configuration as they are only used for testing purposes.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: test/solidity/Facets/ChainflipFacet.t.sol:154-156
Timestamp: 2025-02-21T11:39:07.847Z
Learning: Bitcoin address validation is not required in Chainflip test cases as the validation is handled elsewhere.
docs/ChainflipFacet.md (1)
Learnt from: ezynda3
PR: lifinance/contracts#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
🪛 GitHub Check: Olympix Integrated Security
src/Facets/ChainflipFacet.sol
[warning] 20-20:
Test functions fail to assert the emission of expected events, potentially missing critical contract behaviors. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/missing-events-assertion
🪛 LanguageTool
docs/ChainflipFacet.md
[uncategorized] ~47-~47: When ‘swap-specific’ is used as a modifier, it is usually spelled with a hyphen.
Context: ... parameter. Swapping is performed by a swap specific library that expects an array of callda...
(SPECIFIC_HYPHEN)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/Periphery/ReceiverChainflip.sol (1)
63-95
: Consider emitting a success event incfReceive
.
Currently, there is only an event emitted when the swap fails (LiFiTransferRecovered
). For greater traceability, consider emitting an event indicating successful bridging to help off-chain services or logs track normal process completion.function cfReceive( ... ) external payable onlyChainflipVault { ... _swapAndCompleteBridgeTokens(...); + emit LiFiTransferCompleted(transactionId, token, receiver, amount, block.timestamp); }
src/Facets/ChainflipFacet.sol (2)
45-50
: Consider clarifying or removing thecfParameters
field.
SincecfParameters
is described as "Additional parameters for future features," it may be beneficial to add a short inline comment or docstring elaborating on planned usage, or remove this field if it’s not going to be used soon.
174-182
: Consider reducing repeated ERC20 approvals.
UsingLibAsset.maxApproveERC20
provides simplicity. However, for security and gas optimization, consider zeroing out allowances first or approving only the required amount. Proactively managing allowance can reduce risk if vault permissions ever become compromised.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/Facets/ChainflipFacet.sol
(1 hunks)src/Periphery/ReceiverChainflip.sol
(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
src/Periphery/ReceiverChainflip.sol (3)
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Periphery/ReceiverChainflip.sol:49-71
Timestamp: 2025-02-13T08:56:27.487Z
Learning: The executor contract in ReceiverChainflip and other periphery contracts is a trusted component of the system, and therefore does not require additional reentrancy protection.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Periphery/ReceiverChainflip.sol:48-62
Timestamp: 2025-02-24T09:35:34.908Z
Learning: Contract address validations for periphery contracts like ReceiverChainflip are handled in deployment scripts rather than in the constructor.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Periphery/ReceiverChainflip.sol:162-162
Timestamp: 2025-02-24T06:51:03.551Z
Learning: In periphery contracts like ReceiverChainflip, the receive function can be left open without access control as it's part of the intended design.
src/Facets/ChainflipFacet.sol (3)
Learnt from: ezynda3
PR: lifinance/contracts#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.
Learnt from: ezynda3
PR: lifinance/contracts#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.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Facets/ChainflipFacet.sol:157-179
Timestamp: 2025-02-17T07:34:42.595Z
Learning: In the Chainflip protocol, there is no way to verify or validate the gas budget for cross-chain calls at the smart contract level.
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: generate-tag
🔇 Additional comments (7)
src/Periphery/ReceiverChainflip.sol (3)
1-61
: Solid constructor and storage design.
The constructor correctly validates non-zero addresses, and the storage fields are well-structured with clear naming. Overall, these lines accurately implement initialization logic and immutability where needed.
98-164
: Robust swap execution flow.
Using try-catch to fall back on sending tokens directly to the receiver is a practical recovery solution that minimizes user funds lock-up. Moreover, resetting approvals to zero helps prevent unintended spending on external contracts. This pattern aligns well with recognized safety best practices.
166-169
: Receive function intentionally left open.
Per your retrieved learnings, this fallback pattern is purposeful and does not require additional access control. The approach is consistent with your design logic.src/Facets/ChainflipFacet.sol (4)
60-69
: Good job validating the_chainflipVault
parameter.
Reverting on a zero address prevents accidental misconfiguration and aligns with best practices for secure contract setup.
134-146
: Robust mismatch checks for destination calls.
The logic properly enforces consistency between_bridgeData.hasDestinationCall
and_chainflipData.dstCallSwapData.length
, preventing accidental or malicious misuse.
148-172
: Well-structured EVM vs. non-EVM address handling.
Applying different logic for_chainflipData.nonEVMReceiver
vs. EVM-based addresses is clean and straightforward. The validation for zero addresses is already enforced byvalidateBridgeData
(and an explicit revert for_chainflipData.dstCallReceiver
) ensuring safe usage.
240-251
: Approach for mapping chain IDs is appropriate.
Using an if-else chain for compile-time constants is a known pattern in Solidity, since mappings cannot be declared as constant or immutable. The implementation is clear and avoids maintaining separate storage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/Facets/ChainflipFacet.sol (2)
45-58
: Clarify the use ofcfParameters
in the NatSpec.Although flagged as "Additional parameters for future features," consider providing an example or more explicit guidance in the NatSpec comments on when or how this field might be used. This helps other developers and auditors better understand its purpose and potential expansion.
183-224
: Consider reducing code duplication for bridging calls.Both the "destination call" block (lines 183–206) and the "no destination call" block (lines 207–224) branch into native vs. token-based calls. Extracting these repeated patterns into a helper function could reduce boilerplate and improve maintainability.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/Facets/ChainflipFacet.sol
(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/Facets/ChainflipFacet.sol (3)
Learnt from: ezynda3
PR: lifinance/contracts#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.
Learnt from: ezynda3
PR: lifinance/contracts#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.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Facets/ChainflipFacet.sol:157-179
Timestamp: 2025-02-17T07:34:42.595Z
Learning: In the Chainflip protocol, there is no way to verify or validate the gas budget for cross-chain calls at the smart contract level.
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: generate-tag
🔇 Additional comments (3)
src/Facets/ChainflipFacet.sol (3)
77-92
: Looks good and straightforward.The function’s flow—depositing assets before calling
_startBridge
—is clear and respects security best practices by validating the bridge data first.
94-117
: Clean swap-then-bridge flow.The logic here neatly updates
_bridgeData.minAmount
after the source swaps, ensuring an accurate bridged asset amount. No issues found with ordering or security checks.
229-247
:✅ Verification successful
Confirm test coverage for unsupported chains.
The
_getChainflipChainId
function reverts ifdestinationChainId
does not match any known chain. Verify that there's at least one test case covering this revert scenario to ensure consistent behavior and maintain coverage.You can confirm coverage by searching for “UnsupportedChainflipChainId” in the tests:
🏁 Script executed:
#!/bin/bash rg -A 5 "UnsupportedChainflipChainId"Length of output: 1390
Test Coverage for Unsupported Chains Confirmed!
The tests in
test/solidity/Facets/ChainflipFacet.t.sol
already cover the revert scenario usingvm.expectRevert(ChainflipFacet.UnsupportedChainflipChainId.selector)
. This confirms that passing an unsupporteddestinationChainId
correctly triggers the revert in_getChainflipChainId
. No further changes are needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
test/solidity/Facets/ChainflipFacet.t.sol (3)
37-49
: Use a helper method to fetch multiple config values.
The approach of individually retrieving the vault address from"chainflip.json"
works well for a single value. However, if more configuration values are needed in the future, consider creating a reusable helper method to fetch all relevant addresses or parameters from the JSON file in one go, helping reduce potential code duplication.
81-83
: Optional validation ofdstToken
.
Currently,validChainflipData.dstToken = 7
is set without validating if token ID 7 is a recognized Chainflip token. Although this may be intentional for flexibility, adding a quick check or a comment explaining that arbitrary token IDs are acceptable might prevent confusion for other contributors.
223-262
: Consolidate duplicate assertion logic.
Multiple tests follow a similar pattern (e.g., setting up the environment, approving tokens, expecting events, etc.). Consider extracting this preparation into a shared helper method to minimize repetition and enhance readability.src/Facets/ChainflipFacet.sol (1)
160-167
: Consider resetting allowances post-bridge.
LibAsset.maxApproveERC20(...)
grants the vault a large allowance to pull tokens. To minimize the attack surface after bridging completes, consider resetting the allowance to zero or using a minimal allowance pattern, if this aligns with the broader architecture.- LibAsset.maxApproveERC20( - IERC20(_bridgeData.sendingAssetId), - address(chainflipVault), - _bridgeData.minAmount - ); + // Approve just for bridging and reset allowance + uint256 amount = _bridgeData.minAmount; + IERC20 token = IERC20(_bridgeData.sendingAssetId); + LibAsset.maxApproveERC20(token, address(chainflipVault), amount); + // ... + // After bridging, reset: + LibAsset.approveERC20(token, address(chainflipVault), 0);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/Facets/ChainflipFacet.sol
(1 hunks)test/solidity/Facets/ChainflipFacet.t.sol
(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
test/solidity/Facets/ChainflipFacet.t.sol (3)
Learnt from: ezynda3
PR: lifinance/contracts#984
File: test/solidity/Facets/ChainflipFacet.t.sol:81-87
Timestamp: 2025-02-21T09:09:15.973Z
Learning: The `cfParameters` field in ChainflipFacet's ChainflipData struct is not used in the current implementation and serves as a placeholder.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: test/solidity/Facets/ChainflipFacet.t.sol:269-269
Timestamp: 2025-02-21T09:05:22.118Z
Learning: Fixed gas amounts in test files (e.g., ChainflipFacet.t.sol) don't require extensive documentation or configuration as they are only used for testing purposes.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: test/solidity/Facets/ChainflipFacet.t.sol:154-156
Timestamp: 2025-02-21T11:39:07.847Z
Learning: Bitcoin address validation is not required in Chainflip test cases as the validation is handled elsewhere.
src/Facets/ChainflipFacet.sol (3)
Learnt from: ezynda3
PR: lifinance/contracts#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.
Learnt from: ezynda3
PR: lifinance/contracts#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.
Learnt from: ezynda3
PR: lifinance/contracts#984
File: src/Facets/ChainflipFacet.sol:157-179
Timestamp: 2025-02-17T07:34:42.595Z
Learning: In the Chainflip protocol, there is no way to verify or validate the gas budget for cross-chain calls at the smart contract level.
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: generate-tag
🔇 Additional comments (5)
test/solidity/Facets/ChainflipFacet.t.sol (2)
85-88
: Good coverage of constructor revert condition.
This test ensures the contract reverts when_chainflipVault
is a zero address, satisfying security checks for constructor parameters.
316-348
: Comprehensive mismatch coverage.
These tests thoroughly verify the mismatch between_bridgeData.hasDestinationCall
and_chainflipData.dstCallSwapData
, ensuring robust input validation. No issues found here.src/Facets/ChainflipFacet.sol (3)
32-40
: Consistent chain ID definitions.
Defining both EVM and non-EVM chain IDs as constants avoids magic numbers in the code. Ensure all referencing tests or external scripts are updated accordingly if these constants ever change.
64-69
: Validating zero-address vault.
Reverting on a zero vault address in the constructor prevents accidental misconfiguration. This matches best practices for constructor parameter validation.
229-247
: Readable chain ID mapping.
This straightforward if-else approach is preferable in Solidity when mapping to compile-time constants, ensuring clarity about supported networks. No further suggestion here.
Which Jira task belongs to this PR?
LF-12192
Why did I implement it this way?
Checklist before requesting a review
Checklist for reviewer (DO NOT DEPLOY and contracts BEFORE CHECKING THIS!!!)