Platform: Code4rena
Start Date: 24/03/2022
Pot Size: $75,000 USDC
Total HM: 15
Participants: 59
Period: 7 days
Judge: gzeon
Id: 103
League: ETH
Rank: 38/59
Findings: 2
Award: $203.26
๐ Selected for report: 0
๐ Solo Findings: 0
๐ Selected for report: hake
Also found by: 0v3rf10w, 0xDjango, 0xkatana, BouSalman, CertoraInc, Dravee, Hawkeye, IllIllI, JMukesh, Jujic, Kenshin, PPrieditis, Picodes, PranavG, Ruhum, SolidityScan, VAD37, WatchPug, aga7hokakological, catchup, csanuragjain, cthulhu_cult, defsec, dimitri, hickuphh3, hubble, hyh, kenta, kirk-baird, obront, peritoflores, rayn, robee, saian, samruna, shenwilly, shw, sorrynotsorry, tchkvsky, teryanarmen, ych18
132.5612 USDC - $132.56
_executeSwaps()
requires a specific order of swaps if the same asset is involvedConsider the following chain of swaps <token>(<amount>): A(1)->B(2), C(1)->B(2), B(5)->D. If the specified order happens, the first two swaps will have deposited the majority of the funds needed for the third. If the swaps are shuffled, it's possible for the third swap to come first, transferring B(5) first, then getting an additional B(4) from the other two swaps. Documentation should make it clear that the order in the array is the order that things will take place in (i.e. a list of swaps and not a set of swaps), and that this functionality should not be used for batching requests from multiple users.
if (!LibAsset.isNativeAsset(fromAssetId) && LibAsset.getOwnBalance(fromAssetId) < fromAmount) { LibAsset.transferFromERC20(fromAssetId, msg.sender, address(this), fromAmount); } if (!LibAsset.isNativeAsset(fromAssetId)) { LibAsset.approveERC20(IERC20(fromAssetId), _swapData.approveTo, fromAmount); }
receive()
The added capability of the contract to receive Ether, without any purpose, is incorrect state handling. Nothing is emitted, no revert stateemnts are added, and no calldata is passed.
receive() external payable {}
require()
should be used instead of assert()
assert(_amount <= self.balance);
assert(_amount <= assetBalance);
if (LibAsset.isNativeAsset(_cBridgeData.token)) { ICBridge(bridge).sendNative( _cBridgeData.receiver, _cBridgeData.amount, _cBridgeData.dstChainId, _cBridgeData.nonce, _cBridgeData.maxSlippage ); } else { // Give CBridge approval to bridge tokens LibAsset.approveERC20(IERC20(_cBridgeData.token), bridge, _cBridgeData.amount); // solhint-disable check-send-result ICBridge(bridge).send( _cBridgeData.receiver, _cBridgeData.token, _cBridgeData.amount, _cBridgeData.dstChainId, _cBridgeData.nonce, _cBridgeData.maxSlippage ); }
Consider adding a two-phase transfer, where the current owner nominates the next owner, and the next owner has to call acceptOwnership()
to become the new owner. This prevents passing the ownership to an account that is unable to use it.
function setContractOwner(address _newOwner) internal { DiamondStorage storage ds = diamondStorage(); address previousOwner = ds.contractOwner; ds.contractOwner = _newOwner; emit OwnershipTransferred(previousOwner, _newOwner); }
safeApprove()
is deprecatedDeprecated in favor of safeIncreaseAllowance()
and safeDecreaseAllowance()
if (allowance > 0) SafeERC20.safeApprove(IERC20(assetId), spender, 0);
SafeERC20.safeApprove(IERC20(assetId), spender, MAX_INT);
indexed
fieldsEach event
should use three indexed
fields if there are three or more fields
event AssetSwapped( bytes32 transactionId, address dex, address fromAssetId, address toAssetId, uint256 fromAmount, uint256 toAmount, uint256 timestamp );
event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);
event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
event LiquidityAdded(address indexed router, address indexed assetId, uint256 amount, address caller);
event LiquidityRemoved(address indexed router, address indexed assetId, uint256 amount, address recipient);
event LiFiTransferStarted( bytes32 indexed transactionId, string integrator, address referrer, address sendingAssetId, address receivingAssetId, address receiver, uint256 amount, uint256 destinationChainId, uint256 timestamp );
event LiFiTransferCompleted( bytes32 indexed transactionId, address receivingAssetId, address receiver, uint256 amount, uint256 timestamp );
event LiFiTransferConfirmed( bytes32 indexed transactionId, string integrator, address referrer, address sendingAssetId, address receivingAssetId, address receiver, uint256 amount, uint256 destinationChainId, uint256 timestamp );
event LiFiTransferRefunded( bytes32 indexed transactionId, string integrator, address referrer, address sendingAssetId, address receivingAssetId, address receiver, uint256 amount, uint256 destinationChainId, uint256 timestamp );
event Inited(address indexed bridge, uint64 chainId);
event NXTPBridgeStarted( bytes32 indexed lifiTransactionId, bytes32 nxtpTransactionId, ITransactionManager.TransactionData txData );
event LogWithdraw(address indexed _assetAddress, address _from, uint256 amount);
public
functions not called by the contract should be declared external
insteadContracts are allowed to override their parents' functions and change the visibility from external
to public
.
function startBridgeTokensViaNXTP(LiFiData memory _lifiData, ITransactionManager.PrepareArgs memory _nxtpData)
function swapAndStartBridgeTokensViaNXTP( LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData, ITransactionManager.PrepareArgs memory _nxtpData
function completeBridgeTokensViaNXTP( LiFiData memory _lifiData, address assetId, address receiver, uint256 amount
function swapAndCompleteBridgeTokensViaNXTP( LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData, address finalAssetId, address receiver
function startBridgeTokensViaHop(LiFiData memory _lifiData, HopData calldata _hopData) public payable {
function swapAndStartBridgeTokensViaHop( LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData, HopData memory _hopData
function swapTokensGeneric(LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData) public payable {
function withdraw( address _assetAddress, address _to, uint256 _amount
function startBridgeTokensViaAnyswap(LiFiData memory _lifiData, AnyswapData calldata _anyswapData) public payable {
function swapAndStartBridgeTokensViaAnyswap( LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData, AnyswapData memory _anyswapData
function startBridgeTokensViaCBridge(LiFiData memory _lifiData, CBridgeData calldata _cBridgeData) public payable {
function swapAndStartBridgeTokensViaCBridge( LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData, CBridgeData memory _cBridgeData
constant
s should be defined rather than using magic numbersif (_res.length < 68) return "Transaction reverted silently";
bytes memory revertData = _res.slice(4, _res.length - 4); // Remove the selector which is the first 4 bytes
bytes memory revertData = _res.slice(4, _res.length - 4); // Remove the selector which is the first 4 bytes
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
2**<n> - 1
should be re-written as type(uint<n>).max
uint256 private constant MAX_INT = 2**256 - 1;
uint256 private constant MAX_INT = 2**256 - 1;
* the inforamtion that does change between chains
inforamtion
// Add the diamondCut external function from the diamondCutFacet
diamondCutFacet -> _diamondCutFacet
/// @notice Batch register the addresss of DEX contracts to be approved for swapping.
addresss
* @dev Conatains the business logic for the bridge via Hop Protocol
Conatains
Code should follow the best-practice of the Checks-Effects-Interactions pattern
Reentrancy in NXTPFacet._startBridge(bytes32,ITransactionManager.PrepareArgs) (src/Facets/NXTPFacet.sol#175-188): External calls: - LibAsset.approveERC20(IERC20(sendingAssetId),address(s.nxtpTxManager),_nxtpData.amount) (src/Facets/NXTPFacet.sol#180) - result = s.nxtpTxManager.prepare{value: value}(_nxtpData) (src/Facets/NXTPFacet.sol#185) External calls sending eth: - result = s.nxtpTxManager.prepare{value: value}(_nxtpData) (src/Facets/NXTPFacet.sol#185) Event emitted after the call(s): - NXTPBridgeStarted(_transactionId,result.transactionId,result) (src/Facets/NXTPFacet.sol#187) Reentrancy in NXTPFacet.completeBridgeTokensViaNXTP(ILiFi.LiFiData,address,address,uint256) (src/Facets/NXTPFacet.sol#124-140): External calls: - LibAsset.transferFromERC20(assetId,msg.sender,address(this),amount) (src/Facets/NXTPFacet.sol#134) - LibAsset.transferAsset(assetId,address(receiver),amount) (src/Facets/NXTPFacet.sol#137) Event emitted after the call(s): - LiFiTransferCompleted(_lifiData.transactionId,assetId,receiver,amount,block.timestamp) (src/Facets/NXTPFacet.sol#139) Reentrancy in AnyswapFacet.startBridgeTokensViaAnyswap(ILiFi.LiFiData,AnyswapFacet.AnyswapData) (src/Facets/AnyswapFacet.sol#35-66): External calls: - underlyingToken = IAnyswapToken(_anyswapData.token).underlying() (src/Facets/AnyswapFacet.sol#36) - _anyswapData.token != address(0) && underlyingToken != IAnyswapRouter(_anyswapData.router).wNATIVE() (src/Facets/AnyswapFacet.sol#37) - LibAsset.transferFromERC20(underlyingToken,msg.sender,address(this),_anyswapData.amount) (src/Facets/AnyswapFacet.sol#43) - _startBridge(_anyswapData) (src/Facets/AnyswapFacet.sol#53) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - underlyingToken = IAnyswapToken(_anyswapData.token).underlying() (src/Facets/AnyswapFacet.sol#134) - underlyingToken == IAnyswapRouter(_anyswapData.router).wNATIVE() (src/Facets/AnyswapFacet.sol#136) - IAnyswapRouter(_anyswapData.router).anySwapOutNative{value: _anyswapData.amount}(_anyswapData.token,_anyswapData.recipient,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#137-141) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(underlyingToken),_anyswapData.router,_anyswapData.amount) (src/Facets/AnyswapFacet.sol#149) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - IAnyswapRouter(_anyswapData.router).anySwapOutUnderlying(_anyswapData.token,_anyswapData.recipient,_anyswapData.amount,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#151-156) - LibAsset.approveERC20(IERC20(_anyswapData.token),_anyswapData.router,_anyswapData.amount) (src/Facets/AnyswapFacet.sol#159) - IAnyswapRouter(_anyswapData.router).anySwapOut(_anyswapData.token,_anyswapData.recipient,_anyswapData.amount,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#161-166) External calls sending eth: - _startBridge(_anyswapData) (src/Facets/AnyswapFacet.sol#53) - IAnyswapRouter(_anyswapData.router).anySwapOutNative{value: _anyswapData.amount}(_anyswapData.token,_anyswapData.recipient,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#137-141) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/AnyswapFacet.sol#55-65) Reentrancy in CBridgeFacet.startBridgeTokensViaCBridge(ILiFi.LiFiData,CBridgeFacet.CBridgeData) (src/Facets/CBridgeFacet.sol#57-84): External calls: - LibAsset.transferFromERC20(_cBridgeData.token,msg.sender,address(this),_cBridgeData.amount) (src/Facets/CBridgeFacet.sol#61) - _startBridge(_cBridgeData) (src/Facets/CBridgeFacet.sol#71) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - ICBridge(bridge).sendNative(_cBridgeData.receiver,_cBridgeData.amount,_cBridgeData.dstChainId,_cBridgeData.nonce,_cBridgeData.maxSlippage) (src/Facets/CBridgeFacet.sol#150-156) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibAsset.approveERC20(IERC20(_cBridgeData.token),bridge,_cBridgeData.amount) (src/Facets/CBridgeFacet.sol#159) - ICBridge(bridge).send(_cBridgeData.receiver,_cBridgeData.token,_cBridgeData.amount,_cBridgeData.dstChainId,_cBridgeData.nonce,_cBridgeData.maxSlippage) (src/Facets/CBridgeFacet.sol#161-168) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) External calls sending eth: - _startBridge(_cBridgeData) (src/Facets/CBridgeFacet.sol#71) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/CBridgeFacet.sol#73-83) Reentrancy in HopFacet.startBridgeTokensViaHop(ILiFi.LiFiData,HopFacet.HopData) (src/Facets/HopFacet.sol#61-87): External calls: - LibAsset.transferFromERC20(sendingAssetId,msg.sender,address(this),_hopData.amount) (src/Facets/HopFacet.sol#67) - _startBridge(_hopData) (src/Facets/HopFacet.sol#74) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - LibAsset.approveERC20(IERC20(sendingAssetId),bridge,_hopData.amount) (src/Facets/HopFacet.sol#149) - IHopBridge(bridge).sendToL2{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.destinationAmountOutMin,_hopData.destinationDeadline,address(0),0) (src/Facets/HopFacet.sol#155-163) - IHopBridge(bridge).swapAndSend{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.bonderFee,_hopData.amountOutMin,_hopData.deadline,_hopData.destinationAmountOutMin,_hopData.destinationDeadline) (src/Facets/HopFacet.sol#167-176) External calls sending eth: - _startBridge(_hopData) (src/Facets/HopFacet.sol#74) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - IHopBridge(bridge).sendToL2{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.destinationAmountOutMin,_hopData.destinationDeadline,address(0),0) (src/Facets/HopFacet.sol#155-163) - IHopBridge(bridge).swapAndSend{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.bonderFee,_hopData.amountOutMin,_hopData.deadline,_hopData.destinationAmountOutMin,_hopData.destinationDeadline) (src/Facets/HopFacet.sol#167-176) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/HopFacet.sol#76-86) Reentrancy in NXTPFacet.startBridgeTokensViaNXTP(ILiFi.LiFiData,ITransactionManager.PrepareArgs) (src/Facets/NXTPFacet.sol#46-76): External calls: - LibAsset.transferFromERC20(sendingAssetId,msg.sender,address(this),_nxtpData.amount) (src/Facets/NXTPFacet.sol#55) - _startBridge(_lifiData.transactionId,_nxtpData) (src/Facets/NXTPFacet.sol#63) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.approveERC20(IERC20(sendingAssetId),address(s.nxtpTxManager),_nxtpData.amount) (src/Facets/NXTPFacet.sol#180) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - result = s.nxtpTxManager.prepare{value: value}(_nxtpData) (src/Facets/NXTPFacet.sol#185) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) External calls sending eth: - _startBridge(_lifiData.transactionId,_nxtpData) (src/Facets/NXTPFacet.sol#63) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - result = s.nxtpTxManager.prepare{value: value}(_nxtpData) (src/Facets/NXTPFacet.sol#185) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/NXTPFacet.sol#65-75) - NXTPBridgeStarted(_transactionId,result.transactionId,result) (src/Facets/NXTPFacet.sol#187) - _startBridge(_lifiData.transactionId,_nxtpData) (src/Facets/NXTPFacet.sol#63) Reentrancy in LibSwap.swap(bytes32,LibSwap.SwapData) (src/Libraries/LibSwap.sol#29-58): External calls: - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) External calls sending eth: - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) Event emitted after the call(s): - AssetSwapped(transactionId,_swapData.callTo,_swapData.sendingAssetId,_swapData.receivingAssetId,fromAmount,toAmount,block.timestamp) (src/Libraries/LibSwap.sol#49-57) Reentrancy in NXTPFacet.swapAndCompleteBridgeTokensViaNXTP(ILiFi.LiFiData,LibSwap.SwapData[],address,address) (src/Facets/NXTPFacet.sol#150-171): External calls: - _executeSwaps(_lifiData,_swapData) (src/Facets/NXTPFacet.sol#159) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - LibAsset.transferAsset(finalAssetId,address(receiver),finalBalance) (src/Facets/NXTPFacet.sol#167) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/NXTPFacet.sol#159) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) Event emitted after the call(s): - LiFiTransferCompleted(_lifiData.transactionId,finalAssetId,receiver,finalBalance,block.timestamp) (src/Facets/NXTPFacet.sol#170) Reentrancy in AnyswapFacet.swapAndStartBridgeTokensViaAnyswap(ILiFi.LiFiData,LibSwap.SwapData[],AnyswapFacet.AnyswapData) (src/Facets/AnyswapFacet.sol#74-123): External calls: - underlyingToken = IAnyswapToken(_anyswapData.token).underlying() (src/Facets/AnyswapFacet.sol#79) - _anyswapData.token != address(0) && underlyingToken != IAnyswapRouter(_anyswapData.router).wNATIVE() (src/Facets/AnyswapFacet.sol#80) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#88) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#88) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) Event emitted after the call(s): - AssetSwapped(transactionId,_swapData.callTo,_swapData.sendingAssetId,_swapData.receivingAssetId,fromAmount,toAmount,block.timestamp) (src/Libraries/LibSwap.sol#49-57) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#88) Reentrancy in AnyswapFacet.swapAndStartBridgeTokensViaAnyswap(ILiFi.LiFiData,LibSwap.SwapData[],AnyswapFacet.AnyswapData) (src/Facets/AnyswapFacet.sol#74-123): External calls: - underlyingToken = IAnyswapToken(_anyswapData.token).underlying() (src/Facets/AnyswapFacet.sol#79) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#99) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#99) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) Event emitted after the call(s): - AssetSwapped(transactionId,_swapData.callTo,_swapData.sendingAssetId,_swapData.receivingAssetId,fromAmount,toAmount,block.timestamp) (src/Libraries/LibSwap.sol#49-57) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#99) Reentrancy in AnyswapFacet.swapAndStartBridgeTokensViaAnyswap(ILiFi.LiFiData,LibSwap.SwapData[],AnyswapFacet.AnyswapData) (src/Facets/AnyswapFacet.sol#74-123): External calls: - underlyingToken = IAnyswapToken(_anyswapData.token).underlying() (src/Facets/AnyswapFacet.sol#79) - _anyswapData.token != address(0) && underlyingToken != IAnyswapRouter(_anyswapData.router).wNATIVE() (src/Facets/AnyswapFacet.sol#80) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#88) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#99) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_anyswapData) (src/Facets/AnyswapFacet.sol#110) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - underlyingToken = IAnyswapToken(_anyswapData.token).underlying() (src/Facets/AnyswapFacet.sol#134) - underlyingToken == IAnyswapRouter(_anyswapData.router).wNATIVE() (src/Facets/AnyswapFacet.sol#136) - IAnyswapRouter(_anyswapData.router).anySwapOutNative{value: _anyswapData.amount}(_anyswapData.token,_anyswapData.recipient,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#137-141) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(underlyingToken),_anyswapData.router,_anyswapData.amount) (src/Facets/AnyswapFacet.sol#149) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - IAnyswapRouter(_anyswapData.router).anySwapOutUnderlying(_anyswapData.token,_anyswapData.recipient,_anyswapData.amount,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#151-156) - LibAsset.approveERC20(IERC20(_anyswapData.token),_anyswapData.router,_anyswapData.amount) (src/Facets/AnyswapFacet.sol#159) - IAnyswapRouter(_anyswapData.router).anySwapOut(_anyswapData.token,_anyswapData.recipient,_anyswapData.amount,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#161-166) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#88) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#99) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_anyswapData) (src/Facets/AnyswapFacet.sol#110) - IAnyswapRouter(_anyswapData.router).anySwapOutNative{value: _anyswapData.amount}(_anyswapData.token,_anyswapData.recipient,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#137-141) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/AnyswapFacet.sol#112-122) Reentrancy in CBridgeFacet.swapAndStartBridgeTokensViaCBridge(ILiFi.LiFiData,LibSwap.SwapData[],CBridgeFacet.CBridgeData) (src/Facets/CBridgeFacet.sol#92-134): External calls: - _executeSwaps(_lifiData,_swapData) (src/Facets/CBridgeFacet.sol#101) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _executeSwaps(_lifiData,_swapData) (src/Facets/CBridgeFacet.sol#112) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_cBridgeData) (src/Facets/CBridgeFacet.sol#121) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - ICBridge(bridge).sendNative(_cBridgeData.receiver,_cBridgeData.amount,_cBridgeData.dstChainId,_cBridgeData.nonce,_cBridgeData.maxSlippage) (src/Facets/CBridgeFacet.sol#150-156) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibAsset.approveERC20(IERC20(_cBridgeData.token),bridge,_cBridgeData.amount) (src/Facets/CBridgeFacet.sol#159) - ICBridge(bridge).send(_cBridgeData.receiver,_cBridgeData.token,_cBridgeData.amount,_cBridgeData.dstChainId,_cBridgeData.nonce,_cBridgeData.maxSlippage) (src/Facets/CBridgeFacet.sol#161-168) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/CBridgeFacet.sol#101) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _executeSwaps(_lifiData,_swapData) (src/Facets/CBridgeFacet.sol#112) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_cBridgeData) (src/Facets/CBridgeFacet.sol#121) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/CBridgeFacet.sol#123-133) Reentrancy in HopFacet.swapAndStartBridgeTokensViaHop(ILiFi.LiFiData,LibSwap.SwapData[],HopFacet.HopData) (src/Facets/HopFacet.sol#95-126): External calls: - _executeSwaps(_lifiData,_swapData) (src/Facets/HopFacet.sol#105) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_hopData) (src/Facets/HopFacet.sol#113) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - LibAsset.approveERC20(IERC20(sendingAssetId),bridge,_hopData.amount) (src/Facets/HopFacet.sol#149) - IHopBridge(bridge).sendToL2{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.destinationAmountOutMin,_hopData.destinationDeadline,address(0),0) (src/Facets/HopFacet.sol#155-163) - IHopBridge(bridge).swapAndSend{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.bonderFee,_hopData.amountOutMin,_hopData.deadline,_hopData.destinationAmountOutMin,_hopData.destinationDeadline) (src/Facets/HopFacet.sol#167-176) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/HopFacet.sol#105) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_hopData) (src/Facets/HopFacet.sol#113) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - IHopBridge(bridge).sendToL2{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.destinationAmountOutMin,_hopData.destinationDeadline,address(0),0) (src/Facets/HopFacet.sol#155-163) - IHopBridge(bridge).swapAndSend{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.bonderFee,_hopData.amountOutMin,_hopData.deadline,_hopData.destinationAmountOutMin,_hopData.destinationDeadline) (src/Facets/HopFacet.sol#167-176) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/HopFacet.sol#115-125) Reentrancy in NXTPFacet.swapAndStartBridgeTokensViaNXTP(ILiFi.LiFiData,LibSwap.SwapData[],ITransactionManager.PrepareArgs) (src/Facets/NXTPFacet.sol#85-115): External calls: - _executeSwaps(_lifiData,_swapData) (src/Facets/NXTPFacet.sol#94) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_lifiData.transactionId,_nxtpData) (src/Facets/NXTPFacet.sol#102) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.approveERC20(IERC20(sendingAssetId),address(s.nxtpTxManager),_nxtpData.amount) (src/Facets/NXTPFacet.sol#180) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - result = s.nxtpTxManager.prepare{value: value}(_nxtpData) (src/Facets/NXTPFacet.sol#185) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/NXTPFacet.sol#94) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_lifiData.transactionId,_nxtpData) (src/Facets/NXTPFacet.sol#102) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - result = s.nxtpTxManager.prepare{value: value}(_nxtpData) (src/Facets/NXTPFacet.sol#185) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/NXTPFacet.sol#104-114) - NXTPBridgeStarted(_transactionId,result.transactionId,result) (src/Facets/NXTPFacet.sol#187) - _startBridge(_lifiData.transactionId,_nxtpData) (src/Facets/NXTPFacet.sol#102) Reentrancy in GenericSwapFacet.swapTokensGeneric(ILiFi.LiFiData,LibSwap.SwapData[]) (src/Facets/GenericSwapFacet.sol#22-43): External calls: - _executeSwaps(_lifiData,_swapData) (src/Facets/GenericSwapFacet.sol#26) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - LibAsset.transferAsset(_lifiData.receivingAssetId,address(msg.sender),postSwapBalance) (src/Facets/GenericSwapFacet.sol#30) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/GenericSwapFacet.sol#26) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/GenericSwapFacet.sol#32-42) Reentrancy in WithdrawFacet.withdraw(address,address,uint256) (src/Facets/WithdrawFacet.sol#20-38): External calls: - IERC20(_assetAddress).safeTransfer(sendTo,_amount) (src/Facets/WithdrawFacet.sol#35) External calls sending eth: - address(sendTo).transfer(_amount) (src/Facets/WithdrawFacet.sol#31) Event emitted after the call(s): - LogWithdraw(sendTo,_assetAddress,_amount) (src/Facets/WithdrawFacet.sol#37) ```
#0 - H3xept
2022-04-01T10:11:56Z
Fixed by lifinance/lifi-contracts@ae1dc0bb1d27be95910df70022b19c64acddfb7a
#1 - H3xept
2022-04-11T11:21:21Z
Duplicate of #165
#2 - H3xept
2022-04-11T11:23:24Z
Duplicate of #82
#3 - H3xept
2022-04-11T12:23:01Z
Duplicate of #143
๐ Selected for report: Dravee
Also found by: 0v3rf10w, 0xDjango, 0xNazgul, 0xkatana, ACai, CertoraInc, FSchmoede, Funen, Hawkeye, IllIllI, Jujic, Kenshin, PPrieditis, Picodes, SolidityScan, TerrierLover, Tomio, WatchPug, catchup, csanuragjain, defsec, dimitri, hake, hickuphh3, kenta, minhquanym, obront, peritoflores, rayn, rfa, robee, saian, samruna, tchkvsky, teryanarmen, ych18
70.6981 USDC - $70.70
The chain of getOwnBalance(), _executeSwaps(), getOwnBalance(), require(), assign, should be refactored to a common function https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/NXTPFacet.sol#L91-L100 https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/HopFacet.sol#L102-L111 https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/AnyswapFacet.sol#L85-L94 https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/CBridgeFacet.sol#L98-L107 The same should be done for the native versions
if (<x> == true)
=> if (<x>)
, if (<x> == false)
=> if (!<x>)
if (s.dexWhitelist[_dex] == true) {
if (s.dexWhitelist[_dexs[i]] == true) {
if (s.dexWhitelist[_dex] == false) {
if (s.dexWhitelist[_dexs[i]] == false) {
ls.dexWhitelist[_swapData[i].approveTo] == true && ls.dexWhitelist[_swapData[i].callTo] == true,
ls.dexWhitelist[_swapData[i].approveTo] == true && ls.dexWhitelist[_swapData[i].callTo] == true,
keccak256()
, should use immutable
rather than constant
See this issue for a detail description of the issue
bytes32 internal constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
bytes32 internal constant NAMESPACE = keccak256("com.lifi.facets.nxtp");
bytes32 internal constant NAMESPACE = keccak256("com.lifi.facets.hop");
bytes32 internal constant NAMESPACE = keccak256("com.lifi.facets.cbridge2");
block.timestamp
and block.number
are added to event information by default so adding them manually wastes gas
uint256 timestamp
uint256 timestamp
uint256 timestamp
uint256 timestamp
uint256 timestamp
++i
/i++
should be unchecked{++i}
/unchecked{++i}
when it is not possible for them to overflow, as is the case when used in for
- and while
-loopsfor (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
for (uint256 i; i < _dexs.length; i++) {
for (uint256 i; i < s.dexs.length; i++) {
for (uint256 i; i < _dexs.length; i++) {
for (uint256 j; j < s.dexs.length; j++) {
for (uint8 i; i < _tokens.length; i++) {
for (uint8 i; i < _swapData.length; i++) {
for (uint256 i; i < numFacets; i++) {
<array>.length
should not be looked up in every loop of a for
-loopEven memory arrays incur the overhead of bit tests and bit shifts to calculate the array length
for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
for (uint256 i; i < _dexs.length; i++) {
for (uint256 i; i < s.dexs.length; i++) {
for (uint256 i; i < _dexs.length; i++) {
for (uint256 j; j < s.dexs.length; j++) {
for (uint8 i; i < _tokens.length; i++) {
for (uint8 i; i < _swapData.length; i++) {
calldata
instead of memory
for read-only arguments in external
functions saves gasstring[] memory _tokens,
IHopBridge.BridgeConfig[] memory _bridgeConfigs,
require()
or revert()
statements that check input arguments should be at the top of the functionrequire(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
internal
functions only called once can be inlined to save gasfunction _bridge() internal view returns (address) {
++i
costs less gas than ++i
, especially when it's used in for
-loops (--i
/i--
too)for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
for (uint256 i; i < _dexs.length; i++) {
for (uint256 i; i < s.dexs.length; i++) {
for (uint256 i; i < _dexs.length; i++) {
for (uint256 j; j < s.dexs.length; j++) {
for (uint8 i; i < _tokens.length; i++) {
for (uint8 i; i < _swapData.length; i++) {
for (uint256 i; i < numFacets; i++) {
Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity 0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
pragma solidity ^0.8.7;
require()
statements that use &&
saves gasSee this issue for an example
require( ls.dexWhitelist[_swapData[i].approveTo] == true && ls.dexWhitelist[_swapData[i].callTo] == true, "Contract call not allowed!" );
require()
/revert()
checks should be refactored to a modifier or functionrequire(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
> 0
costs more gas than != 0
when used on a uint
in a require()
statementrequire(contractSize > 0, _errorMessage);
require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
require()
/revert()
strings longer than 32 bytes cost extra gasrequire(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
revert("LibDiamondCut: Incorrect FacetCutAction");
require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");
require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function");
require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
require(_facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist");
require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function");
require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty");
require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)");
revert("LibDiamondCut: _init function reverted");
require(s.hopChainId != _hopData.chainId, "Cannot bridge to the same network.");
require(block.chainid != _anyswapData.toChainId, "Cannot bridge to the same network.");
require(s.cBridgeChainId != _cBridgeData.dstChainId, "Cannot bridge to the same network.");
The instances below point to the second access of a state variable within a function. Less obvious optimizations include having local storage variables of mappings within state variable mappings or mappings within state variable structs, having local storage variables of structs within mappings, or having local caches of state variable contracts/addresses.
s.dexWhitelist[_dex] = true;
s.dexWhitelist[_dexs[i]] = true;
s.dexWhitelist[_dex] = false;
s.dexWhitelist[_dexs[i]] = false;
s.dexs[index] = s.dexs[s.dexs.length - 1];
ls.dexWhitelist[_swapData[i].approveTo] == true && ls.dexWhitelist[_swapData[i].callTo] == true,
uints
/ints
smaller than 32 bytes (256 bits) incurs overheadWhen using elements that are smaller than 32 bytes, your contractโs gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.
https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Use a larger size then downcast where needed
uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
uint96 _selectorPosition,
event Inited(address indexed bridge, uint64 chainId);
uint64 _dstChinId,
uint64 _nonce,
uint32 _maxSlippage
uint64 _dstChinId,
uint64 _nonce,
uint32 _maxSlippage
for (uint8 i; i < _tokens.length; i++) {
for (uint8 i; i < _swapData.length; i++) {
uint64 cBridgeChainId;
uint64 dstChainId;
uint64 nonce;
uint32 maxSlippage;
function initCbridge(address _cBridge, uint64 _chainId) external {
struct CBridgeData { address receiver; address token; uint256 amount; uint64 dstChainId; uint64 nonce; uint32 maxSlippage; }
Struct member ordering with 3 slots instead of the current 4: uint256(32):amount,address(20):receiver,uint64(8):dstChainId,uint32(4):maxSlippage,address(20):token,uint64(8):nonce
uint256 private constant MAX_INT = 2**256 - 1;
Various files and various locations
#0 - H3xept
2022-04-01T10:42:06Z
Fixed by lifinance/lifi-contracts@39dd074acf47b40f9a544439427e58de0208b961
#1 - H3xept
2022-04-01T10:50:21Z
We internally decided to avoid unchecked expressions for now.
#2 - H3xept
2022-04-01T10:59:41Z
I found no evidence online about this. Upon testing locally, this seems to be wrong (&& saves gas!!)
#3 - H3xept
2022-04-01T11:01:12Z
Fixed by lifinance/lifi-contracts@975f12529f2232a59def392349bf8dccf4141aa9 Duplicate of #44
#4 - H3xept
2022-04-01T11:03:56Z
Fixed by lifinance/lifi-contracts@45edddfb56028db3cfd070b57990ae8a455f0109
#5 - H3xept
2022-04-01T11:07:54Z
Fixed by lifinance/lifi-contracts@2b0c057fb05c62d95c0b04edd1864c184ccf9ad8
#6 - H3xept
2022-04-08T15:17:16Z
Duplicate of #100
#7 - H3xept
2022-04-11T10:30:30Z
Duplicate of #100
#8 - H3xept
2022-04-11T10:51:15Z
Duplicate of #178
#9 - H3xept
2022-04-11T11:12:02Z
Duplicate of #100
#10 - H3xept
2022-04-11T12:02:00Z
We internally decided to avoid previx increments for now.
#11 - H3xept
2022-04-11T12:41:49Z
Duplicate of #152
#12 - H3xept
2022-04-11T12:52:46Z
Duplicate of #182