Maia DAO - Ulysses - yongskiws's results

Harnessing the power of Arbitrum, Ulysses Omnichain specializes in Virtualized Liquidity Management.

General Information

Platform: Code4rena

Start Date: 22/09/2023

Pot Size: $100,000 USDC

Total HM: 15

Participants: 175

Period: 14 days

Judge: alcueca

Total Solo HM: 4

Id: 287

League: ETH

Maia DAO

Findings Distribution

Researcher Performance

Rank: 68/175

Findings: 2

Award: $50.08

QA:
grade-b
Analysis:
grade-b

🌟 Selected for report: 0

šŸš€ Solo Findings: 0

Consider Relaying Messages to the Layer Zero Enpoint at the Gas Boundary

The impact is that when those fields are different between chains, one of two things may happen:

Less severe - we waste excess gas, which is refunded to the lzReceive() caller (Layer Zero) More severe - we underprice the delivery cost, causing lzReceive() to revert and the NFT/ASSET stuck in limbo forever. The code does not handle a failed lzReceive (differently to a failed executeJob).

Recommended Mitigation Steps Firstly, make sure to use the target gas costs. i.e. save some gas to emit result event.

https://github.com/code-423n4/2023-09-maia/blob/main/src/BranchBridgeAgent.sol#L161-L173 https://github.com/code-423n4/2023-09-maia/blob/main/src/BranchBridgeAgent.sol#L161-L174 https://github.com/code-423n4/2023-09-maia/blob/main/src/BranchBridgeAgent.sol#L765-L778 https://github.com/code-423n4/2023-09-maia/blob/main/src/BranchBridgeAgent.sol#L785-L795 https://github.com/code-423n4/2023-09-maia/blob/main/src/RootBridgeAgent.sol#L140-L153 https://github.com/code-423n4/2023-09-maia/blob/main/src/RootBridgeAgent.sol#L820-L838 https://github.com/code-423n4/2023-09-maia/blob/main/src/RootBridgeAgent.sol#L912-L930

src\interfaces\ILayerZeroEndpoint.sol 15: function send( 16: uint16 _dstChainId, 17: bytes calldata _destination, 18: bytes calldata _payload, 19: address payable _refundAddress, 20: address _zroPaymentAddress, 21: bytes calldata _adapterParams 22: ) external payable;

In the ArbitrumBranchBridgeAgent,ArbitrumBranchPort, CoreRootRouter, RootBridgeAgent ,VirtualAccount. Constructor the address&_rootChainId is passed in as an input parameter. address&_rootChainId. Hence the address&_rootChainId variable is a critical variable of the protocol. If address&_rootChainId is set to zero by mistake it will prompt a redeployment of the contract which could be wastage of gas and additional work load. Hence an input validity check should be performed for the address&_rootChainId variable inside the constructor as follows:


src\ArbitrumBranchBridgeAgent.sol
43:     constructor(
44:         uint16 _localChainId,
45:         address _rootBridgeAgentAddress,
46:         address _localRouterAddress,
47:         address _localPortAddress
48:     )

@>require(_localChainId > 0, "localChainId must be greater than zero");
@>require(isValidAddress(_rootBridgeAgentAddress), "Invalid rootBridgeAgentAddress");
@>require(isValidAddress(_localRouterAddress), "Invalid localRouterAddress");
@>require(isValidAddress(_localPortAddress), "Invalid localPortAddress");

57:     {}

src\ArbitrumBranchPort.sol
38:     constructor(uint16 _localChainId, address _rootPortAddress, address _owner) BranchPort(_owner) {
39:         require(_rootPortAddress != address(0), "Root Port Address cannot be 0");
40: 
@>require(_localChainId > 0, "localChainId must be greater than zero");
@>require(isValidAddress(_owner), "Invalid owner");
43:     }


src\CoreRootRouter.sol
71:     constructor(uint256 _rootChainId, address _rootPortAddress) {
@>require(_localChainId > 0, "localChainId must be greater than zero");
@>require(_rootPortAddress != address(0), "Root Port Address cannot be 0");    
72:         rootChainId = _rootChainId;
73:         rootPortAddress = _rootPortAddress;
74: 
77:     }

src\RootBridgeAgent.sol
105:     constructor(
106:         uint16 _localChainId,
107:         address _lzEndpointAddress,
108:         address _localPortAddress,
109:         address _localRouterAddress
110:     ) {
@>require(_localChainId > 0, "localChainId must be greater than zero");
111:         require(_lzEndpointAddress != address(0), "Layerzero Enpoint Address cannot be zero address");
112:         require(_localPortAddress != address(0), "Port Address cannot be zero address");
113:         require(_localRouterAddress != address(0), "Router Address cannot be zero address");

src\VirtualAccount.sol
35:     constructor(address _userAddress, address _localPortAddress) {
@>require(isValidAddress(_userAddress), "Invalid _userAddress");    
@>require(isValidAddress(_localPortAddress), "Invalid _localPortAddress");    
36:         userAddress = _userAddress;
37:         localPortAddress = _localPortAddress;
38:     }



function isValidAddress(address _addr) internal pure returns (bool) {
    return _addr != address(0);
}

Add if necessary Emit event or add STATUS_PENDING to executionState

src\BranchBridgeAgent.sol
730:   function _execute(bool _hasFallbackToggled, uint32 _settlementNonce, address _refundee, bytes memory _calldata)
731:         private
732:     {

 E.G @>       require(executionState[_settlementNonce] == STATUS_PENDING, "Transaction has already been executed");

733:         //Update tx state as executed
734:         executionState[_settlementNonce] = STATUS_DONE;
735: 
736:         //Try to execute the remote request
737:         (bool success,) = bridgeAgentExecutorAddress.call{value: address(this).balance}(_calldata);
738: 
739:         //Update tx state if execution failed
740:         if (!success) {
741:             //Read the fallback flag and perform the fallback call if necessary. If not, allow for retrying deposit.
742:             if (_hasFallbackToggled) {
743:                 // Update tx state as retrieve only
744:                 executionState[_settlementNonce] = STATUS_RETRIEVE;
745: 
746:                 // Perform fallback call
747:                 _performFallbackCall(payable(_refundee), _settlementNonce);

//Emit an event to notify that execution failed and fallback is enabled
  @>          emit ExecutionFailedWithFallback(_settlementNonce);

748:             } else {
749:                 // If no fallback is requested revert allowing for settlement retry.
750:                 revert ExecutionFailure();
751:             }
752:         }else
//Emit an event to notify that execution was successful
   @>         emit ExecutionSucceeded(_settlementNonce);
             }
753:     }


src\RootBridgeAgent.sol
768:     function _execute(
769:         bool _hasFallbackToggled,
770:         uint32 _depositNonce,
771:         address _refundee,
772:         bytes memory _calldata,
773:         uint16 _srcChainId
774:     ) private {
E.G // Make sure that the transaction has not been executed previously
@>    require(executionState[_srcChainId][_depositNonce] == STATUS_PENDING, "Transaction has been executed");
775:         //Update tx state as executed
776:         executionState[_srcChainId][_depositNonce] = STATUS_DONE;
777: 
778:         //Try to execute the remote request
779:         (bool success,) = bridgeAgentExecutorAddress.call{value: address(this).balance}(_calldata);
780: 
781:         //Update tx state if execution failed
782:         if (!success) {
783:             //Read the fallback flag.
784:             if (_hasFallbackToggled) {
785:                 // Update tx state as retrieve only
786:                 executionState[_srcChainId][_depositNonce] = STATUS_RETRIEVE;
787:                 // Perform the fallback call
788:                 _performFallbackCall(payable(_refundee), _depositNonce, _srcChainId);

                    //Emit an event to notify that execution failed and fallback is enabled
@>                    emit ExecutionFailedWithFallback(_depositNonce, _srcChainId);
789:             } else {
790:                 // No fallback is requested revert allowing for retry.
791:                 revert ExecutionFailure();
792:             }
793:         }else
        //Emit an event to notify that execution was successful
@>        emit ExecutionSucceeded(_depositNonce, _srcChainId);
            }
794:     }
795: 

Typo in revert error Branc SHOULD BE Branch

src\interfaces\IRootPort.sol
408:     error InvalidCoreBrancBridgeAgent();

src\RootPort.sol
545:         if (_coreBranchBridgeAgent == address(0)) revert InvalidCoreBrancBridgeAgent();
529:         if (_coreBranchBridgeAgent == address(0)) revert InvalidCoreBrancBridgeAgent();

Typo in function _performCall callee SHOULD BE calleer


src\RootBridgeAgent.sol
808:     function _performCall(
809:         uint16 _dstChainId,
810:         address payable _refundee,
811:         bytes memory _payload,
812:         GasParams calldata _gParams
813:     ) internal {
814:         // Get destination Branch Bridge Agent
815: @>         address callee = getBranchBridgeAgent[_dstChainId];
816: 
817:         // Check if valid destination
818: @>        if (callee == address(0)) revert UnrecognizedBridgeAgent();
819: 
820:         // Check if call to remote chain
821:         if (_dstChainId != localChainId) {
822:             //Sends message to Layerzero Enpoint
823:             ILayerZeroEndpoint(lzEndpointAddress).send{value: msg.value}(
824:                 _dstChainId,
825:                 getBranchBridgeAgentPath[_dstChainId],
826:                 _payload,
827:                 _refundee,
828:                 address(0),
829: @>                abi.encodePacked(uint16(2), _gParams.gasLimit, _gParams.remoteBranchExecutionGas, callee)
830:             );
831: 
832:             // Check if call to local chain
833:         } else {
834:             //Send Gas to Local Branch Bridge Agent
835: @>             callee.call{value: msg.value}("");
836:             //Execute locally
837: @>           IBranchBridgeAgent(callee).lzReceive(0, "", 0, _payload);
838:         }
839:     }

#0 - c4-pre-sort

2023-10-15T12:05:42Z

0xA5DF marked the issue as sufficient quality report

#1 - c4-judge

2023-10-20T13:34:50Z

alcueca marked the issue as grade-a

#2 - c4-judge

2023-10-27T10:43:58Z

alcueca marked the issue as grade-b

Awards

38.6134 USDC - $38.61

Labels

analysis-advanced
grade-b
sufficient quality report
A-01

External Links

Architecture Description and Diagram

ArbitrumBranchBridgeAgent

ArbitrumBranchBridgeAgent is a derivative of the BranchBridgeAgent contract and is used as an intermediary agent to access LayerZero cross-chain communications and Port communications.

ArbitrumBranchBridgeAgent contract also has several important external functions, including depositToPort and withdrawFromPort, which are used to deposit and withdraw assets to/from the local Port.

ArbitrumBranchPort

ArbitrumBranchPort contract has two important external functions, namely depositToPort and withdrawFromPort, which are used to deposit and withdraw assets to/from the local Port. This second function has a modification lock that ensures that only one transaction can be executed at a time.

ArbitrumCoreBranchRouter

executeNoSettlement to execute various system functions. It can process several types of operations such as adding a Bridge Agent, replacing a Factory Bridge Agent, removing a Bridge Agent, managing strategy tokens, and more. This function receives data containing system function calls via cross-chain messaging.

BranchBridgeAgent

Main Functions: has various main functions, such as deposit creation, signed cross-chain invocation, invocation with fallback handling, and so on. These functions allow users to initiate and manage transfers between chains.

Error Handling: BranchBridgeAgent also comes with an error handling mechanism. If there is an error in cross-chain transaction execution, such as a failed execution, has the ability to return the deposit to the sender or activate a fallback to reprocess.

Inter-Chain Communication: uses LayerZero, which is a cross-chain messaging layer, to communicate with other chains in the network. This enables secure and efficient transfers between chains.

Modifiers and Verification: uses modifiers to ensure that only authorized parties can access certain functions. It is designed to increase security and prevent protection.

Documentation: also includes documentation in the form of comments, which explains the logic and use of the functions.

BaseBranchRouter

BaseBranchRouter stores several important addresses used in the ecosystem, including local bridge agent addresses and bridge agent executing addresses. This data is used to direct communications and asset transfers. also regulates the approval required for the use of these assets in cross-chain transactions.

BranchPort

1.Port Strategy decisions to manage tokens and port management strategies. 2.Triggers the user to recharge reserve tokens. 3.Users longing to transfer tokens cross-chain. 4.Asks the owner to update the ecosystem by adding new Bridge Agents, Factories and Port Strategies.

Risk Security: includes multiple layers of security, including sender message verification, daily settings for Port Strategy, and token reserve replenishment. This helps ensure that users and port management strategies can operate securely.

My Thoughts

Ulysses Protocol is a decentralized Omnichain Liquidity Protocol aimed at optimizing liquidity management in DeFi. It allows Liquidity Providers to deploy assets across multiple chains, earn revenue from various chains, and reduce operational costs for DeFi protocols. The protocol has two key components: Virtualized and Unified Liquidity Management. It uses Arbitrum's Balancer's Composable Stable Pools and enables a single token representing stable LP from different chains for full composability. Understanding Ulysses Ports and Virtualized Liquidity is crucial, and cross-chain messaging is facilitated through Layer0. Explore Ulysses Unified Tokens for insights into stable pools and liquidity architecture.

Systemic Risks

Block Timestamp Settings: Different chains may have varying requirements for block timestamp settings. This could lead to discrepancies or challenges in managing timestamps across chains.

Gas Refunds: When using a Virtual Account as a refundee for cross-chain messages, excess gas refunds on branch chains may become inaccessible. This is because the refundee is not an Externally Owned Account (EOA) capable of claiming funds on branch chains.

Pragma Version: The code will be deployed with pragma version 0.8.19, which may have implications for compatibility and functionality with different Solidity versions.

Ownership Renouncement: Some contracts allow for the renouncement of ownership without overriding the renounceOwnership function from the Solady library. This could potentially lead to unexpected consequences.

Permissionless Factories: The protocol includes permissionless factories, where anyone can create contracts. This opens the possibility for the creation of malicious contracts or the deposit of potentially harmful tokens in ports. While contracts generated by these actions are not in the protocol's scope, they may impact other contracts or balances.

Admin Functions: Most admin functions can only be called by other contracts in the system or by Hermes Protocol's Governance. However, RootBridgeAgent Managers are open to whoever creates them. Misuse of these functions by Hermes Governance is out of scope, except when it affects other contracts or balances. If a Manager of RootBridgeAgent misuses these functions and it has an impact on other contracts or balances, it is considered a valid concern.

Centralization Risks

Control by a Single Party: This risk occurs when one entity or a small group has significant control over assets or critical functions within the protocol. This can lead to manipulation or unfair decision-making.

Key Contractors: If there are key contractors or third parties with a pivotal role in the development, maintenance, or operation of the protocol, centralization risk can arise if there is excessive dependence on that entity.

Centralized Governance Power: This risk is related to strong control by a single entity or group in the decision-making process and rule-setting within the protocol. It can undermine the desired decentralization aspects of DeFi.

Use of Power Tokens: If tokens that grant voting rights or control in the protocol are owned by a small number of individuals or entities, centralization risk can emerge due to the significant control held by these parties.

Single-Asset Risk: Centralization can also occur if the protocol is heavily reliant on a single asset or a specific blockchain chain. This dependency can lead to vulnerabilities if the asset or chain experiences issues.

Architecture Recommendations

Emergency Monitoring and Response: Have a robust monitoring system and emergency response plan to quickly address operational issues.

Security Planning: recommends robust security planning to deal with emergency situations and effective vulnerability reporting.

Comprehensive Testing: Perform comprehensive unit testing and integration testing to verify proper functioning of the protocol.

Smart Contract Upgrades: Consider secure smart capability upgrade mechanisms so that the protocol can evolve over time without risk of vulnerabilities.

Strong Documentation: Provides strong documentation for the source code so that developers, users, and third parties can easily understand how the protocol works.

Solidity Best Practices: follow Solidity best practices in writing code, such as avoiding using constructs that are vulnerable to attack and avoiding using functions that require excessive gas.

Modularity: Building protocols with a modular approach that allows components to interact separately. This makes maintenance and future development easier.

TREE CODE

src\ArbitrumBranchBridgeAgent.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IArbitrumBranchPort.sol ^0.8.0 │ └── src\interfaces\IBranchPort.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IRootBridgeAgent.sol ^0.8.0 │ ā”œā”€ā”€ src\interfaces\ILayerZeroReceiver.sol >=0.5.0 │ └── src\interfaces\BridgeAgentStructs.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IBranchBridgeAgent.sol ^0.8.0 │ ā”œā”€ā”€ src\interfaces\ILayerZeroReceiver.sol >=0.5.0 │ └── src\interfaces\BridgeAgentStructs.sol ^0.8.0 └── src\BranchBridgeAgent.sol ^0.8.0 ā”œā”€ā”€ lib/ExcessivelySafeCall.sol >=0.7.6 ā”œā”€ā”€ src\interfaces\IBranchPort.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\BridgeAgentConstants.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IBranchBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\ILayerZeroEndpoint.sol >=0.5.0 │ └── src\interfaces\ILayerZeroUserApplicationConfig.sol >=0.5.0 └── src\BranchBridgeAgentExecutor.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/auth/Ownable.sol ^0.8.4 ā”œā”€ā”€ lib/solady/src/utils/SafeTransferLib.sol ^0.8.4 ā”œā”€ā”€ src\interfaces\IBranchRouter.sol ^0.8.0 │ └── src\interfaces\IBranchBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\BranchBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\BridgeAgentConstants.sol ^0.8.0 └── src\interfaces\IBranchBridgeAgent.sol ^0.8.0 (*) src\ArbitrumBranchPort.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/utils/SafeTransferLib.sol ^0.8.4 ā”œā”€ā”€ src\interfaces\IArbitrumBranchPort.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\IRootPort.sol ^0.8.0 │ ā”œā”€ā”€ src\interfaces\IRootBridgeAgent.sol ^0.8.0 (*) │ └── src\VirtualAccount.sol ^0.8.0 │ ā”œā”€ā”€ lib/solady/src/utils/SafeTransferLib.sol ^0.8.4 │ ā”œā”€ā”€ lib/solmate/src/tokens/ERC721.sol >=0.8.0 │ ā”œā”€ā”€ lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Receiver.sol ^0.8.0 │ │ ā”œā”€ā”€ lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol ^0.8.0 │ │ │ └── lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol ^0.8.0 │ │ └── lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol ^0.8.0 │ │ └── lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol ^0.8.0 │ ā”œā”€ā”€ lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol ^0.8.0 (*) │ ā”œā”€ā”€ lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol ^0.8.0 │ ā”œā”€ā”€ src\interfaces\IVirtualAccount.sol ^0.8.0 │ │ └── lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol ^0.8.0 │ └── src\interfaces\IRootPort.sol ^0.8.0 (*) └── src\BranchPort.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/auth/Ownable.sol ^0.8.4 ā”œā”€ā”€ lib/solady/src/utils/SafeTransferLib.sol ^0.8.4 ā”œā”€ā”€ lib/solmate/src/tokens/ERC20.sol >=0.8.0 ā”œā”€ā”€ src\interfaces\IPortStrategy.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IBranchPort.sol ^0.8.0 └── src\token\ERC20hTokenBranch.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/auth/Ownable.sol ^0.8.4 ā”œā”€ā”€ lib/solmate/src/tokens/ERC20.sol >=0.8.0 └── src\interfaces\IERC20hTokenBranch.sol ^0.8.0 src\ArbitrumCoreBranchRouter.sol ^0.8.0 ā”œā”€ā”€ lib/solmate/src/tokens/ERC20.sol >=0.8.0 ā”œā”€ā”€ src\interfaces\IBranchBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\IBranchBridgeAgentFactory.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IArbitrumBranchPort.sol ^0.8.0 (*) └── src\CoreBranchRouter.sol ^0.8.0 ā”œā”€ā”€ lib/solmate/src/tokens/ERC20.sol >=0.8.0 ā”œā”€ā”€ src\interfaces\IBranchPort.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IBranchBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\IBranchBridgeAgentFactory.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IBranchRouter.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\ICoreBranchRouter.sol ^0.8.0 │ └── src\interfaces\IBranchBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\IERC20hTokenBranchFactory.sol ^0.8.0 │ └── src\token\ERC20hTokenBranch.sol ^0.8.0 (*) ā”œā”€ā”€ src\BaseBranchRouter.sol ^0.8.0 │ ā”œā”€ā”€ lib/solady/src/auth/Ownable.sol ^0.8.4 │ ā”œā”€ā”€ lib/solady/src/utils/SafeTransferLib.sol ^0.8.4 │ ā”œā”€ā”€ lib/solmate/src/tokens/ERC20.sol >=0.8.0 │ ā”œā”€ā”€ src\interfaces\IBranchRouter.sol ^0.8.0 (*) │ └── src\interfaces\IBranchBridgeAgent.sol ^0.8.0 (*) └── src\token\ERC20hTokenBranch.sol ^0.8.0 (*) src\BaseBranchRouter.sol ^0.8.0 (*) src\BranchBridgeAgent.sol ^0.8.0 (*) src\BranchBridgeAgentExecutor.sol ^0.8.0 (*) src\BranchPort.sol ^0.8.0 (*) src\CoreBranchRouter.sol ^0.8.0 (*) src\CoreRootRouter.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/auth/Ownable.sol ^0.8.4 ā”œā”€ā”€ lib/solmate/src/tokens/ERC20.sol >=0.8.0 ā”œā”€ā”€ src\interfaces\IERC20hTokenRootFactory.sol ^0.8.0 │ └── src\token\ERC20hTokenRoot.sol ^0.8.0 │ ā”œā”€ā”€ lib/solady/src/auth/Ownable.sol ^0.8.4 │ ā”œā”€ā”€ lib/solmate/src/tokens/ERC20.sol >=0.8.0 │ └── src\interfaces\IERC20hTokenRoot.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IRootRouter.sol ^0.8.0 │ └── src\interfaces\IRootBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\IRootBridgeAgent.sol ^0.8.0 (*) └── src\interfaces\IRootPort.sol ^0.8.0 (*) src\MulticallRootRouter.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/auth/Ownable.sol ^0.8.4 ā”œā”€ā”€ lib/solady/src/utils/SafeTransferLib.sol ^0.8.4 ā”œā”€ā”€ src\interfaces\IMulticall2.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IRootBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\IRootRouter.sol ^0.8.0 (*) └── src\interfaces\IVirtualAccount.sol ^0.8.0 (*) src\MulticallRootRouterLibZip.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/utils/LibZip.sol ^0.8.4 └── src\MulticallRootRouter.sol ^0.8.0 (*) src\RootBridgeAgent.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/utils/SafeTransferLib.sol ^0.8.4 ā”œā”€ā”€ lib/ExcessivelySafeCall.sol >=0.7.6 ā”œā”€ā”€ src\interfaces\ILayerZeroEndpoint.sol >=0.5.0 (*) ā”œā”€ā”€ src\interfaces\IBranchBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\IERC20hTokenRoot.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\BridgeAgentConstants.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IRootBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\IRootPort.sol ^0.8.0 (*) ā”œā”€ā”€ src\VirtualAccount.sol ^0.8.0 (*) └── src\RootBridgeAgentExecutor.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/auth/Ownable.sol ^0.8.4 ā”œā”€ā”€ src\interfaces\IRootRouter.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\IRootBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\BridgeAgentConstants.sol ^0.8.0 └── src\RootBridgeAgent.sol ^0.8.0 (*) src\RootBridgeAgentExecutor.sol ^0.8.0 (*) src\RootPort.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/auth/Ownable.sol ^0.8.4 ā”œā”€ā”€ lib/solady/src/utils/SafeTransferLib.sol ^0.8.4 ā”œā”€ā”€ src\interfaces\IERC20hTokenRootFactory.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\IRootBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\IRootPort.sol ^0.8.0 (*) └── src\token\ERC20hTokenRoot.sol ^0.8.0 (*) src\VirtualAccount.sol ^0.8.0 (*) src\factories\ArbitrumBranchBridgeAgentFactory.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IArbitrumBranchPort.sol ^0.8.0 (*) ā”œā”€ā”€ src\ArbitrumBranchBridgeAgent.sol ^0.8.0 (*) └── src\factories\BranchBridgeAgentFactory.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/auth/Ownable.sol ^0.8.4 ā”œā”€ā”€ src\BranchBridgeAgent.sol ^0.8.0 (*) ā”œā”€ā”€ src\interfaces\IBranchPort.sol ^0.8.0 └── src\interfaces\IBranchBridgeAgentFactory.sol ^0.8.0 src\factories\BranchBridgeAgentFactory.sol ^0.8.0 (*) src\factories\ERC20hTokenBranchFactory.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/auth/Ownable.sol ^0.8.4 ā”œā”€ā”€ src\token\ERC20hTokenBranch.sol ^0.8.0 (*) └── src\interfaces\IERC20hTokenBranchFactory.sol ^0.8.0 (*) src\factories\ERC20hTokenRootFactory.sol ^0.8.0 ā”œā”€ā”€ lib/solady/src/auth/Ownable.sol ^0.8.4 ā”œā”€ā”€ lib/solmate/src/tokens/ERC20.sol >=0.8.0 └── src\interfaces\IERC20hTokenRootFactory.sol ^0.8.0 (*) src\factories\RootBridgeAgentFactory.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IRootBridgeAgentFactory.sol ^0.8.0 ā”œā”€ā”€ src\interfaces\IRootPort.sol ^0.8.0 (*) └── src\RootBridgeAgent.sol ^0.8.0 (*)

Gas Optimizations

Lock modifiers are used in some contract functions to prevent reentrance. This is a good approach to avoid reentrance attacks, but keep in mind that this modifier will consume additional gas on each function call that uses this modifier. Therefore, it is necessary to ensure that the use of the lock modifier is justified and necessary in each case.

Some arithmetic operations, such as subtraction and multiplication, can require significant gas depending on the number of binary digits. It is worth checking whether these operations can be optimized or replaced with more efficient approaches.

Function calls from other or external contracts usually require more gas than internal function calls. Make sure external function calls are only used when absolutely necessary and consider more gas-efficient alternatives whenever possible.

Looping can waste significant gas if not managed properly. Ensure that iterations in contract functions do not exceed the maximum gas limit allowed in an Ethereum block.

Mapping can consume gas if used in complex operations. Ensure the use of efficient mappings and consider whether some mappings can be replaced with other, more gas-efficient data structures.

External calls with gas stipends can be used to avoid "out of gas" errors, but they can also lead to potential reentrance attacks. Make sure that resuming external calls are used carefully and only when necessary.

The unchecked keyword is used in some parts of the code to avoid throwing under certain conditions. This can speed up execution, but also increases the risk of errors. Ensure safe and appropriate use of unchecked.

Please note that the total block size of Ethereum transactions has limits. If contract functions produce very large outputs, this may result in transactions being too large to be included in the block.

It is important to understand that there is a maximum gas limit that can be assigned to an Relaying Messages to the Layer Zero Endpoint transaction. If a function requires more gas than the maximum limit, the transaction will fail. Therefore, it is necessary to ensure that each function operates within reasonable gas limits.

When compiling contracts using Solidity, the optimizer configuration can impact gas usage. The use of optimizers such as --optimize and --runs needs to be considered to achieve more efficient results.

Using token.balanceOf(address(this)) Branch Port every time can potentially reduce the contract's performance. Frequent external calls to other contracts, such as reading the balance of the token contract, can be expensive in terms of gas costs and execution time. This can lead to higher transaction costs and slower contract execution

Explicitly initializing default values for variables consumes additional gas during contract deployment. If you rely on the EVM's automatic default initialization, you can save gas costs associated with these unnecessary operations

Minimize the number of state variable reads and writes. Use local variables when possible to avoid additional storage operations

Limit the number of iterations in loops to prevent excessive gas consumption. Consider using other patterns like mapping, where possible, to reduce the need for loops

Whenever applicable, consider batching multiple operations together to save on gas costs. For example, you can combine multiple token transfers into a single function call

Remove any unused or commented-out code to save space and simplify contract logic

Check if modifiers can be combined or reused across multiple functions to reduce the number of modifier calls. This can save gas by avoiding redundant checks.

Consider batching the make emit events in every function or using other gas-saving techniques to reduce transaction costs

Reuse variables instead of creating new ones when possible. This can reduce memory usage and, in turn, save gas

Time spent:

15 hours

#0 - c4-pre-sort

2023-10-15T13:58:58Z

0xA5DF marked the issue as sufficient quality report

#1 - alcueca

2023-10-20T13:00:55Z

Missing system overview Decent contract by contract description Risk sections are not very original Recommendations are good, even if possibly picked from a boilerplate list. Same with Gas Optimizations.

#2 - c4-judge

2023-10-20T13:01:01Z

alcueca marked the issue as grade-b

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Ā© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter