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
Rank: 66/175
Findings: 2
Award: $58.62
π Selected for report: 0
π Solo Findings: 0
π Selected for report: LokiThe5th
Also found by: 0xadrii, 33BYTEZZZ, 3docSec, Bauchibred, DevABDee, Koolex, Kow, Limbooo, QiuhaoLi, Tendency, ast3ros, ihtishamsudo, kodyvim, lsaudit, neumo, peakbolt, windhustler
20.0051 USDC - $20.01
https://github.com/code-423n4/2023-09-maia/blob/c0dc3550e0754571b82d7bfd8f0282ac8fa5e42f/src/RootBridgeAgent.sol#L419 https://github.com/code-423n4/2023-09-maia/blob/c0dc3550e0754571b82d7bfd8f0282ac8fa5e42f/src/BranchBridgeAgent.sol#L574
The absence of the forceResumeReceive
function, as recommended by LayerZero, means that there is no defined mechanism for the owner or multisig to unblock the queue of messages in case of unexpected events. Without this function, the contract lacks a crucial emergency recovery mechanism, leaving the message queue susceptible to potential long-lasting blockages due to unforeseen circumstances.
Also the lack of nonce tracking through events in the lzReceive
function makes it challenging for external users and contracts to track and correlate messages sent and received by the contract, potentially leading to issues related to transaction ordering and verification.
It is clearly stated in the LayerZero documentation that implementing the ILayerZeroApplicationConfig
interface, specifically the forceResumeReceive
function, is highly recommended. However, this recommendation has not been implemented in the LayerZero External Functions
of RootBridgeAgent.sol
and BranchBridgeAgent.sol
. This absence leaves the contract vulnerable to message queue blockages without a recovery mechanism.
Another recommended implementation, also lacking in the code, is the TRACKING OF NONCE
as stated in the LayerZero documentation. Proper nonce tracking, achieved through emitting events, is essential for correlating send and receive side transactions. However, the lzReceive()
function in both RootBridgeAgent.sol
and BranchBridgeAgent.sol
does not emit events to track nonces, leading to potential issues related to transaction verification and sequencing.
/// @inheritdoc ILayerZeroReceiver function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64, bytes calldata _payload) public { (bool success,) = address(this).excessivelySafeCall( gasleft(), 150, abi.encodeWithSelector(this.lzReceiveNonBlocking.selector, msg.sender, _srcChainId, _srcAddress, _payload) ); // @audit-issue: Nonce tracking recommended by LayerZero is missing if (!success) if (msg.sender == getBranchBridgeAgent[localChainId]) revert ExecutionFailure(); }
Manual Review
LayerZero Best Practices Should be Followed, and Recommendations by LayerZero Must be Implemented.
The ILayerZeroUserApplicationConfig.sol
interface must be implemented wherever the LayerZero is inherited. This interface provides the forceResumeReceive
function, which, in the worst-case scenario, can allow the owner/multisig to unblock the queue of messages if something unexpected happens.
Emitting events to track nonces provides transparency and allows for correlation between the send and receive side transactions. Without emitting events related to nonces, it might be challenging for external users and contracts to track and correlate messages sent and received by the contract. Code can be mitigated as follows:
/// @inheritdoc ILayerZeroReceiver function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64, bytes calldata _payload) public { (bool success,) = address(this).excessivelySafeCall( gasleft(), 150, abi.encodeWithSelector(this.lzReceiveNonBlocking.selector, msg.sender, _srcChainId, _srcAddress, _payload) ); // Emit an event to track the nonce + emit NonceReceived(msg.sender, _srcChainId, _srcAddress, _nonce); if (!success) if (msg.sender == getBranchBridgeAgent[localChainId]) revert ExecutionFailure(); }
Context
#0 - c4-pre-sort
2023-10-11T11:20:11Z
0xA5DF marked the issue as duplicate of #875
#1 - c4-pre-sort
2023-10-11T11:21:10Z
0xA5DF marked the issue as sufficient quality report
#2 - c4-judge
2023-10-22T04:48:26Z
alcueca marked the issue as satisfactory
#3 - c4-judge
2023-10-22T04:48:31Z
alcueca marked the issue as partial-50
#4 - c4-judge
2023-10-22T04:56:30Z
alcueca marked the issue as duplicate of #399
π Selected for report: MrPotatoMagic
Also found by: 0xHelium, 0xSmartContract, 0xbrett8571, 0xsagetony, 33BYTEZZZ, Bauchibred, K42, Littlebeast, LokiThe5th, Oxsadeeq, SAAJ, Sathish9098, ZdravkoHr, albertwh1te, alexxander, catellatech, chaduke, hunter_w3b, ihtishamsudo, invitedtea, jauvany, klau5, kodyvim, lsaudit, pavankv, pfapostol, yongskiws
38.6134 USDC - $38.61
To understand What Ulysses is first there's a need to understand What is Maia DAO.
But This audit was focused on Maia DAO - Ulysses
, So, I'll try to Explain What I understand about Ulysses and How It Works according to the codebase.
Current Codebase Have All The Contracts in src
in Scope, That I'll try to summarize in more details.
I'll start summarizing in a sequence from factory contracts.
Total of Five Factory Contracts That Are Summarized As Stated :
It is an implementation of an Arbitrum Branch Bridge Agent Factory. It allows for the permissionless deployment of new Arbitrum Branch Bridge Agents. These agents are responsible for managing the deposit and withdrawal of assets between branch chains and an omnichain environment.
BranchBridgeAgentFactory
.BranchBridgeAgentFactory
to create specific Arbitrum branch bridge agents.Initialization:
Initializer Function:
initialize
function is used to set up the contract after deployment. It takes the address of the Core Root Bridge Agent and deploys a new Arbitrum branch bridge agent.External Functions:
createBridgeAgent
:
DeployArbitrumBranchBridgeAgent.deploy
function, passing the necessary parameters such as root chain ID, root bridge agent address, new branch router address, and local port address.IPort(localPortAddress).addBridgeAgent(newBridgeAgent)
.In summary, this contract acts as a factory for creating Arbitrum branch bridge agents, allowing for the seamless movement of assets between different chains within the Arbitrum network.
It is a factory contract for deploying and managing Branch Bridge Agents, facilitating the transfer of assets between branch chains and an omnichain environment. Here's a breakdown of its functionalities:
Constructor:
Initializer Function (initialize
):
External Function (createBridgeAgent
):
Chain IDs and Addresses:
Deployment Logic:
DeployBranchBridgeAgent.deploy
function to create new Branch Bridge Agents with specific parameters for inter-chain communication.This contract serves as a factory, providing a structured way to create and manage Branch Bridge Agents for seamless asset transfer between branch chains and an overarching omnichain network.
It is an ERC20 hToken Branch Factory. Its primary purpose is to enable the creation and management of hTokens (ERC20 tokens) on a specific chain. Here's a breakdown of its functionalities:
Constructor:
Initializer Function (initialize
):
External Function (createToken
):
Modifiers (requiresCoreRouter
):
View Function (getHTokens
):
Chain Identifiers and Addresses:
Deployment Logic:
This contract serves as a factory, providing a structured way to create and manage customized ERC20 hTokens on a specific chain, with flexibility in naming and symbol conventions. It ensures secure and controlled token creation by verifying the authenticity of the Core Router contract from the local chain.
An ERC20 hToken Root Factory. Its main purpose is to create and manage hTokens (ERC20 tokens) on a root chain. Below are the contract's key functionalities:
Constructor:
Initializer Function (initialize
):
External Function (createToken
):
Modifiers (requiresCoreRouterOrPort
):
View Function (getHTokens
):
Chain Identifiers and Addresses:
Deployment Logic:
This contract acts as a factory, providing a structured way to create and manage ERC20 hTokens on the root chain. It ensures secure and controlled token creation by verifying the authenticity of the Core Router contract from the root chain or the root port address.
An ERC20 hToken Root Factory. Its main purpose is to create and manage hTokens (ERC20 tokens) on a root chain.
Constructor:
Initializer Function (initialize
):
External Function (createToken
):
Modifiers (requiresCoreRouterOrPort
):
View Function (getHTokens
):
Chain Identifiers and Addresses:
Deployment Logic:
This contract acts as a factory, providing a structured way to create and manage ERC20 hTokens on the root chain. It ensures secure and controlled token creation by verifying the authenticity of the Core Router contract from the root chain or the root port address.
Proper Implementation of Interfaces it provides in Main Contracts In Src. Will Try To Provide Details About Interfaces as well in Main Contracts.
Ulysses Unified Tokens mark a significant advancement in accessing liquidity across various blockchains. These tokens enable users to interact seamlessly with a liquidity pool spanning diverse chains, offering convenience and adaptability.
It is an implementation of an ERC20 hToken Branch. Here's an explanation of its functionalities:
Constructor:
ERC20 Logic:
mint
and burn
, which are extended to include the onlyOwner
modifier. This modifier restricts the minting and burning functions to be accessible only by the contract owner, enhancing security and control.Ownership Control:
Token Minting:
mint
function allows the owner to create new tokens and assign them to a specified account.Token Burning:
burn
function enables the owner to destroy a specific amount of tokens, reducing the total token supply.
This contract represents an ERC20 hToken on a specific branch or chain. It includes standard ERC20 functionalities with the added control of ownership, ensuring that minting and burning operations are restricted to the contract owner for enhanced security and management.It is an implementation of an ERC20 hToken Root.
Constructor:
Mapping:
getTokenBalance
which maps chain IDs to token balances. This mapping keeps track of token balances for specific chains.ERC20 Logic:
mint
and burn
, which are extended to include the onlyOwner
modifier. This modifier restricts minting and burning functions to be accessible only by the contract owner, enhancing security and control.mint
function allows the owner to create new tokens and assigns them to a specified account while updating the total supply for the given chain.burn
function enables the owner to destroy a specific amount of tokens from a specified account while updating the total supply for the given chain.Token Minting:
mint
function allows the owner to create new tokens and assign them to a specified account while updating the total supply for the given chain.Token Burning:
burn
function enables the owner to destroy a specific amount of tokens from a specified account, reducing the total supply for the given chain.This contract represents an ERC20 hToken on a specific chain. It includes standard ERC20 functionalities with the added control of ownership, ensuring that minting and burning operations are restricted to the contract owner for enhanced security and management. It also maintains a mapping to keep track of token balances for different chains.
These Contracts Have Core Functionality about how Ulysses Omnichain Liquidity Protocol Works.
This Solidity smart contract is an implementation of an Arbitrum Branch Bridge Agent. Here's an explanation of its functionalities:
Libraries and Interfaces:
IArbitrumBranchPort
, IRootBridgeAgent
, and IBranchBridgeAgent
. It also imports the BranchBridgeAgent
contract.DeployArbitrumBranchBridgeAgent
used for deploying new instances of ArbitrumBranchBridgeAgent
.Constructor:
BranchBridgeAgent
with specific parameters.User External Functions:
depositToPort
: Allows users to deposit a specific amount of an underlying asset to the local port. The function forwards the deposit request to IArbitrumBranchPort
for processing.withdrawFromPort
: Allows users to withdraw a specific amount of a local hToken from the local port. The function forwards the withdrawal request to IArbitrumBranchPort
for processing.Settlement External Functions:
retrySettlement
: A function that should be accessed from the Root environment. It handles settlement retries in the LayerZero cross-chain messaging system.Layer Zero Internal Functions:
_performCall
: An internal function that performs a call to LayerZero messaging layer Endpoint for cross-chain messaging. It sends gas to the Root Bridge Agent and executes the call locally._performFallbackCall
: An internal function that performs a fallback call to the LayerZero Endpoint Contract for cross-chain messaging, specifically for settlement retries.Modifier Internal Functions:
_requiresEndpoint
: An internal modifier function used to verify that the caller is the Root Bridge Agent.Ownership Control:
IArbitrumBranchPort
).Cross-Chain Communication:
This contract facilitates the deposit and withdrawal of assets between Arbitrum Branch Chains and the root omnichain environment. It acts as a bridge, enabling users and routers to interact seamlessly with LayerZero cross-chain messaging and Port communication systems.
An implementation of an Arbitrum Branch Port has following key functionalities
External Functions:
depositToPort
: Allows depositing assets to the local port. It takes parameters such as depositor, recipient, underlying asset address, and deposit amount. It transfers assets from the depositor to the port and requests minting of global tokens in the root port.withdrawFromPort
: Allows withdrawing assets from the local port. It takes parameters such as depositor, recipient, global token address, and withdrawal amount. It burns tokens from the local branch, transfers the underlying assets to the recipient, and bridges the tokens to the root chain if needed.Internal Functions:
_bridgeIn
: Internal function to bridge in assets from the Root Chain. It bridges the specified amount of assets to the recipient._bridgeOut
: Internal function to bridge out assets to the Root Chain. It handles the deposit of underlying assets and burning of hTokens if necessary before bridging the assets to the Root Chain.Cross-Chain Communication:
Asset Bridging:
An implementation of an Arbitrum Core Branch Router.
Libraries and Interfaces:
ERC20
contract for ERC20 token functionality.IBranchBridgeAgent
, IBranchBridgeAgentFactory
, and IArbitrumBranchPort
for interaction with bridge agents and ports.Inheritance:
CoreBranchRouter
, implying it extends the functionality of a core branch router and includes additional Arbitrum-specific logic.Constructor:
External Functions:
addLocalToken
: Allows adding a local token to the Arbitrum environment. It encodes the necessary data and sends a cross-chain request to the local bridge agent to add the token.Internal Functions:
_receiveAddBridgeAgent
: Internal function to receive and process a request to add a bridge agent. It verifies the sender, creates the bridge agent, and bridges the response back to the requester.LayerZero External Functions:
executeNoSettlement
: Handles incoming cross-chain messages and executes the corresponding actions based on the function selector (FUNC ID) provided in the message data. It supports functions like adding a bridge agent, toggling a bridge agent factory, removing a bridge agent, managing strategy tokens, and managing port strategies.Bridge Agent Management:
Token Management:
Cross-Chain Communication:
Functionality Control:
This contract acts as a core bridge router specifically tailored for the Arbitrum environment. It manages the addition of bridge agents, local tokens, and various strategies, ensuring smooth cross-chain communication within the Arbitrum ecosystem.
BaseBranchRouter
, serves as a fundamental component in a bridge system, allowing tokens to be transferred between different blockchain networks.
Libraries and Interfaces:
SafeTransferLib
) and interfaces for interacting with the bridge agent and port contracts.Inheritance and Ownership:
Ownable
contract, allowing an owner to perform certain administrative functions.IBranchRouter
interface, defining the required functions for a branch router in the bridge system.Constructor:
Initialization Function:
initialize
: An external function that initializes the base branch router by setting the local bridge agent address, local port address, and bridge agent executor address. This function can only be called by the owner.View Function:
getDepositEntry
: Allows external callers to view a specific deposit entry using its deposit nonce.External Functions:
callOut
: Allows external entities to call out to the bridge agent with specific parameters and gas settings.callOutAndBridge
: Allows external entities to call out to the bridge agent, initiate a bridge operation, and transfer tokens.callOutAndBridgeMultiple
: Similar to callOutAndBridge
, but for multiple token transfers.Internal Functions:
_transferAndApproveToken
: Internal function used by callOutAndBridge
to transfer tokens into the contract and approve them for further transactions._transferAndApproveMultipleTokens
: Internal function to handle multiple token transfers and approvals.Modifiers:
requiresAgentExecutor
: Modifier that ensures the sender is the designated bridge agent executor.lock
: Modifier for a simple reentrancy check, preventing recursive calls to certain functions.Token Transfer and Approval:
Cross-Chain Communication:
callOut
, callOutAndBridge
, callOutAndBridgeMultiple
) facilitate communication with the bridge agent, allowing cross-chain operations and token transfers.Initialization and Ownership Control:
Security Measures:
lock
modifier) to prevent recursive calls and potential reentrancy attacks.BaseBranchRouter
acts as an intermediary component in a bridge system, enabling communication between different blockchains. It handles token transfers, approvals, and cross-chain communication with the bridge agent, ensuring secure and controlled interactions between blockchain networks. Note that certain functions, such as executeNoSettlement
and executeSettlement
, are placeholders and need further implementation.
BranchBridgeAgent
, plays a crucial role in a cross-chain bridge system, enabling communication and value transfer between different blockchain networks. This contract manages the deposit and settlement process, facilitates token transfers, and ensures secure communication between different blockchain networks. It includes various external functions for handling deposits, settlements, and token management, providing a comprehensive solution for interoperability.
Libraries and Interfaces:
ExcessivelySafeCall
) and interfaces for interacting with the bridge agent and port contracts.Constructor:
State Variables:
External Functions:
callOutSystem
, callOut
, callOutAndBridge
, etc.) that allow users to initiate cross-chain communication and token transfers._performCall
internal function.Deposit Management:
callOutAndBridge
and callOutAndBridgeMultiple
. These deposits store information about the transferred tokens.Settlement Execution State:
Reentrancy Protection:
lock
) to prevent recursive calls and potential reentrancy attacks.Initialization:
Cross-Chain Communication:
callOutSystem
, callOut
, callOutAndBridge
, callOutAndBridgeMultiple
, callOutSigned
, callOutSignedAndBridge
, and callOutSignedAndBridgeMultiple
.Deposit Management:
callOutAndBridge
and callOutAndBridgeMultiple
.Settlement Execution:
executionState
mapping, ensuring that settlements are not duplicated.Fallback Function:
Reentrancy Protection:
lock
modifier prevents reentrancy attacks, ensuring that functions are not called recursively.retryDeposit(bool _isSigned, uint32 _depositNonce, bytes calldata _params, GasParams calldata _gParams, bool _hasFallbackToggled)
: Allows the deposit owner to retry a failed deposit. It encodes the data and performs a cross-chain call to rectify the failed deposit, updating the deposit status accordingly.retrieveDeposit(uint32 _depositNonce, GasParams calldata _gParams)
: Permits the deposit owner to retrieve their deposit. It encodes the data and performs a cross-chain call to initiate the deposit retrieval process.redeemDeposit(uint32 _depositNonce)
: Enables the deposit owner to redeem a successful deposit. It transfers tokens back to the depositor and clears the deposit information.retrySettlement(uint32 _settlementNonce, bytes calldata _params, GasParams[2] calldata _gParams, bool _hasFallbackToggled)
: Allows the settlement initiator to retry a failed settlement. It encodes the settlement data and performs a cross-chain call to retry the settlement process.clearToken(address _recipient, address _hToken, address _token, uint256 _amount, uint256 _deposit)
: Allows the agent executor to clear a specific token by transferring it to the recipient. This function is used for individual token clearance.clearTokens(bytes calldata _sParams, address _recipient)
: Enables the agent executor to clear multiple tokens in a single transaction. It processes multiple tokens and their corresponding amounts and deposits, transferring them to the specified recipient.lzReceive(uint16, bytes calldata _srcAddress, uint64, bytes calldata _payload)
: This function serves as an entry point for Layer Zero messages. It processes Layer Zero messages, determining the type of operation to be performed based on the flag in the payload.lzReceiveNonBlocking(address _endpoint, bytes calldata _srcAddress, bytes calldata _payload)
: This function handles Layer Zero messages, decoding the payload and executing the appropriate actions based on the flag received._execute(uint256 _settlementNonce, bytes memory _calldata)
: This internal function requests execution from the BranchBridgeAgentExecutor
contract. It updates the transaction state and attempts to execute the provided calldata._execute(bool _hasFallbackToggled, uint32 _settlementNonce, address _refundee, bytes memory _calldata)
: Similar to the above function, but this one also handles fallback mechanisms based on the _hasFallbackToggled
parameter._performFallbackCall(address payable _refundee, uint32 _settlementNonce)
: This internal function triggers a fallback call, allowing for retrying failed settlements or deposits._performCall(address payable _refundee, bytes memory _payload, GasParams calldata _gParams)
: This internal function performs a call to the Layer Zero messaging layer for cross-chain messaging. It includes gas parameters for efficient execution._clearToken(address _recipient, address _hToken, address _token, uint256 _amount, uint256 _deposit)
: This internal function clears tokens, transferring them to the recipient, based on the provided parameters._createDeposit(uint32 _depositNonce, address payable _refundee, address _hToken, address _token, uint256 _amount, uint256 _deposit)
: This internal function moves assets from the branch chain to the root omnichain environment for a single token deposit._createDepositMultiple(uint32 _depositNonce, address payable _refundee, address[] memory _hTokens, address[] memory _tokens, uint256[] memory _amounts, uint256[] memory _deposits)
: Similar to the above function, but for handling multiple token deposits._clearToken(address _recipient, address _hToken, address _token, uint256 _amount, uint256 _deposit)
: This internal function clears token balances for a given user, transferring them to the specified recipient.lock()
: A reentrancy check modifier to prevent reentrancy attacks during function execution.requiresEndpoint(address _endpoint, bytes calldata _srcAddress)
: Ensures that the caller is the authorized Layer Zero Endpoint or Local Branch Bridge Agent.requiresRouter()
: Verifies that the caller is the Branch Bridge Agent's Router.requiresAgentExecutor()
: Ensures that the caller is the Bridge Agent Executor.lock
modifier) is applied throughout the contract, safeguarding against reentrancy attacks.BranchBridgeAgentExecutor
, is an essential component of a cross-chain bridge system. Its primary purpose is to execute cross-chain requests and handle settlements based on messages received from the root environment. Let's break down its functionality:
Ownable
and SafeTransferLib
: The contract imports the Ownable
contract for ownership management and a custom library SafeTransferLib
for safe token transfers.IRouter
Interface: The contract imports the interface for the IBranchRouter
, indicating interaction with a router contract on the network.executeNoSettlement(address _router, bytes calldata _payload) external payable onlyOwner
: Executes a cross-chain request without any settlement. The payload contains the necessary data for the execution.executeWithSettlement(address _recipient, address _router, bytes calldata _payload) external payable onlyOwner
: Executes a cross-chain request with a single settlement. It also handles the transfer of tokens to the recipient.executeWithSettlementMultiple(address _recipient, address _router, bytes calldata _payload) external payable onlyOwner
: Executes a cross-chain request with multiple settlements. It bridges in assets, performs settlements, and transfers remaining tokens to the recipient._initializeOwner(address _owner) internal
: Initializes the owner of the contract. It is used in the constructor._recipient.safeTransferETH(address(this).balance)
: Transfers the remaining native/Gas tokens to the recipient after executing settlements.The BranchPort
contract serves as a management system for tokens bridged across different chains. It facilitates the interaction between different components in the blockchain network.
coreBranchRouterAddress
: Stores the address of the local core branch router.isBridgeAgent
: Mapping that keeps track of active bridge agents.bridgeAgents
: Array storing addresses of active bridge agents.isBridgeAgentFactory
: Mapping that keeps track of active bridge agent factories.bridgeAgentFactories
: Array storing addresses of active bridge agent factories.isStrategyToken
: Mapping indicating if a token is active for usage in port strategies.strategyTokens
: Array listing tokens allowed for usage in port strategies.getStrategyTokenDebt
: Mapping indicating the total debt incurred by port strategies for a specific token.getMinimumTokenReserveRatio
: Mapping indicating the minimum reserve ratio a token should have for the port.isPortStrategy
: Mapping indicating if a port strategy is allowed to manage a specific strategy token.portStrategies
: Array storing addresses of active port strategies.strategyDailyLimitAmount
: Mapping indicating the daily management limit for port strategies with specific tokens.strategyDailyLimitRemaining
: Mapping indicating the remaining daily management limit for port strategies with specific tokens.lastManaged
: Mapping indicating the last time a port strategy managed a specific token.withdraw
: Allows external contracts to withdraw funds.bridgeIn
: Bridges in hTokens.bridgeInMultiple
: Bridges in multiple hTokens and clears underlying tokens.bridgeOut
: Bridges out hTokens and underlying tokens.bridgeOutMultiple
: Bridges out multiple hTokens and underlying tokens.requiresCoreRouter()
: Ensures the caller is the recognized core router.requiresBridgeAgent()
: Ensures the caller is a recognized bridge agent.requiresBridgeAgentFactory()
: Ensures the caller is a recognized bridge agent factory.requiresPortStrategy(address _token)
: Ensures the caller is a recognized port strategy for the specified token.lock()
: Provides a simple reentrancy check.This is the implementation of the Core Branch Router for a blockchain network. The contract handles various functionalities related to token management and bridge agent management across different chains. Let's break down the key aspects of this contract:
ICoreBranchRouter
: This contract implements the interface ICoreBranchRouter
.BaseBranchRouter
: This contract inherits from BaseBranchRouter
.The contract has a constructor that takes the address of the hToken Factory and initializes the hTokenFactoryAddress
variable.
addGlobalToken
:_globalAddress
(token address in the global environment), _dstChainId
(destination chain ID), _gParams
(gas parameters).addLocalToken
:_underlyingAddress
(address of the underlying token), _gParams
(gas parameters).executeNoSettlement
:_params
(encoded parameters for various internal functions)._params
._receiveAddGlobalToken
:_globalAddress
, _name
, _symbol
, _decimals
, _refundee
, _gParams
._receiveAddBridgeAgent
:_newBranchRouter
, _branchBridgeAgentFactory
, _rootBridgeAgent
, _rootBridgeAgentFactory
, _refundee
, _gParams
._toggleBranchBridgeAgentFactory
:_newBridgeAgentFactoryAddress
._removeBranchBridgeAgent
:_branchBridgeAgent
._manageStrategyToken
:_underlyingToken
, _minimumReservesRatio
._managePortStrategy
:_portStrategy
, _underlyingToken
, _dailyManagementLimit
, _isUpdateDailyLimit
.requiresAgentExecutor
:This is the implementation of the Core Root Router for a cross-chain bridging protocol. It is designed to manage the integration and communication between different chains in a multi-chain environment. Let me break down its functionality and components for you:
Initialization:
initialize
function sets up the initial configuration of the contract, including the bridge agent address and ERC20 hToken root factory address.Token Management:
Bridge Agent Management:
Core Branch Management:
Modifiers and Error Handling:
This Solidity contract is a part of a decentralized application (dApp) infrastructure for handling cross-chain transactions within a multi-chain environment. Let's break down its functionality step by step:
Ownable
, SafeTransferLib
, IMulticall2
, IRootBridgeAgent
, IRootRouter
, and IVirtualAccount
.OutputParams
and OutputMultipleParams
. These structs are used to represent parameters for output assets during cross-chain transactions.MulticallRootRouter
is declared, inheriting from IRootRouter
and Ownable
. It implements functions specified in the IRootRouter
interface.initialize
function is used to set the bridge agent address. It can only be called once and is intended to be called by the contract owner.execute
, executeDepositSingle
, executeDepositMultiple
, executeSigned
, executeSignedDepositSingle
, and executeSignedDepositMultiple
. These functions are specified by the IRootRouter
interface for executing cross-chain transactions and handling deposits._multicall
used to perform a set of actions on the omnichain environment without using the user's Virtual Account._approveAndCallOut
and _approveMultipleAndCallOut
are used to approve token spend and bridge out assets from the omnichain environment._decode
function is a placeholder for decoding data. In the current implementation, it simply returns the input data as is.lock
, requiresExecutor
, and _requiresExecutor
. These modifiers are used to control reentrancy and ensure that only authorized entities can execute certain functions.UnrecognizedFunctionId
and UnrecognizedBridgeAgentExecutor
) that are thrown when specific conditions are not met.Ownable
contract.lock
modifier.MulticallRootRouterLibZip
is an extension of the MulticallRootRouter
contract. It adds a decompression feature using the LibZip
library. Let's break down its functionality:
LibZip
from the LibZip
library.MulticallRootRouter
contract.MulticallRootRouterLibZip
is declared, inheriting from MulticallRootRouter
.MulticallRootRouter
.using LibZip for bytes;
statement. This allows the contract to use the functions defined in the LibZip
library on bytes
data type._localChainId
, _localPortAddress
, and _multicallAddress
. These parameters are used to initialize the base MulticallRootRouter
contract._decode
function from the base contract. This function is used to decompress data before processing it further._decode
function calls the cdDecompress()
function from the LibZip
library to decompress the input data before returning it.cdDecompress()
function is assumed to be part of the LibZip
library and handles the decompression logic.MulticallRootRouter
by adding the ability to decompress input data before processing it.LibZip
), and the contract utilizes this logic through the using LibZip for bytes;
statement.MulticallRootRouter
contract with specific parameters.MulticallRootRouterLibZip
contract acts as a middleware between the external world and the core MulticallRootRouter
contract, providing decompression capabilities.RootBridgeAgentExecutor
, is a part of a decentralized system for handling cross-chain communication and token settlements between different blockchains.
DeployRootBridgeAgentExecutor
is a library used for deploying instances of the RootBridgeAgentExecutor
contract.RootBridgeAgentExecutor
is declared, inheriting from Ownable
and using constants defined in BridgeAgentConstants
._rootBridgeAgent
as a parameter. It initializes the contract and sets the specified address as the owner of the contract. The owner is the account that has the authority to execute various functions within the contract.onlyOwner
modifier). These functions are used for executing different types of remote requests from other chains._bridgeIn
and _bridgeInMultiple
) used for bridging assets from branch chains to the root omnichain environment. These functions are called internally by the executor functions to handle asset transfers.This is an implementation of a Root Port for managing tokens across different chains in a blockchain network. The contract facilitates the interaction between different blockchain networks, allowing the transfer and management of tokens across these networks. Here's a breakdown of its functionality:
initialize
and initializeCore
: Functions used for initializing the contract and setting up core components._getLocalToken
: Internal view function returning the local address of a token on another chain.setAddresses
and setLocalAddress
: Functions for setting addresses for hTokens and their local counterparts.bridgeToRoot
, bridgeToRootFromLocalBranch
, bridgeToLocalBranchFromRoot
, burn
, burnFromLocalBranch
, mintToLocalBranch
: Functions for bridging tokens between chains.fetchVirtualAccount
, addVirtualAccount
, toggleVirtualAccountApproved
: Functions for managing virtual accounts and their approval status for routers.addBridgeAgent
, syncBranchBridgeAgentWithRoot
: Functions for adding and syncing bridge agents with the root chain.toggleBridgeAgent
, addBridgeAgentFactory
, toggleBridgeAgentFactory
: Functions for toggling bridge agents and managing bridge agent factories.addNewChain
, addEcosystemToken
: Functions for adding new chains and ecosystem tokens to the system.setCoreRootRouter
, setCoreBranchRouter
, syncNewCoreBranchRouter
: Functions for setting core root and branch routers, and syncing new branch routers with the root chain.The contract emits various events such as LocalTokenAdded
, BridgeAgentAdded
, VirtualAccountCreated
, etc., to log important state changes and actions within the contract.
This represents a virtual user account on the Root Chain of a blockchain network.
userAddress
and localPortAddress
variables.receive
function that allows it to receive Ether.withdrawNative(uint256 _amount) external override requiresApprovedCaller
: Allows the user to withdraw Ether from the virtual account.withdrawERC20(address _token, uint256 _amount) external override requiresApprovedCaller
: Allows the user to withdraw ERC20 tokens from the virtual account.withdrawERC721(address _token, uint256 _tokenId) external override requiresApprovedCaller
: Allows the user to withdraw ERC721 tokens from the virtual account.call(Call[] calldata calls) external override requiresApprovedCaller returns (bytes[] memory returnData)
: Allows the user to execute multiple external calls to contracts.payableCall(PayableCall[] calldata calls) public payable returns (bytes[] memory returnData)
: Allows the user to execute multiple external payable calls to contracts.onERC721Received
, onERC1155Received
, onERC1155BatchReceived
: External hooks conforming to ERC721 and ERC1155 standards.isContract(address addr) internal view returns (bool)
: Checks whether an address corresponds to a smart contract.requiresApprovedCaller() modifier
: Ensures that only approved callers (owner or approved router) can access certain functions.While the provided contracts exhibit several good practices, there are always areas for potential improvement. Here are some suggestions for enhancing the architecture further:
call
or delegatecall
, handle potential errors and exceptions properly. These low-level functions can lead to unexpected behavior if not handled carefully.By addressing these points, the overall architecture can become more secure, efficient, and maintainable. Regular code reviews, security audits, and adherence to best practices contribute significantly to the solidity of the smart contract system.
Codebase Quality Analysis Report
Overall Rating: 60%
**1. Test Coverage Analysis:
**2. Invariant Coverage Analysis:
**3. Fuzzing Analysis:
**4. Code Readability and Documentation:
**5. Error Handling and Consistency:
Conclusion: The codebase demonstrates potential but requires significant improvements in test coverage, invariant validation, and fuzz testing. Addressing these issues will enhance the code's quality, security, and reliability. Aiming for at least 90% test coverage, complete invariant coverage, and systematic fuzz testing will greatly improve the overall robustness of the system.
Overall The Codebase Is properly managed and certain practices are implemented to minimize centralization risk but here are few weak points that I would like to mention : Evaluating centralization risk in a decentralized application involves considering the concentration of control or authority within the system. In the provided codebase, there are a few aspects that could potentially pose centralization risks:
Bridge Agent Management: The code includes functionality for adding, syncing, and toggling bridge agents. If these actions are not decentralized or if specific addresses have unilateral control over these operations, it might create a centralization risk.
Mitigation: Implement a decentralized and community-driven process for adding and managing bridge agents. Consider using voting mechanisms or other consensus protocols to make decisions collectively.
Approval of Virtual Accounts: The requiresApprovedCaller
modifier in the VirtualAccount
contract checks for approval from the local port contract. If this approval is controlled by a centralized entity or is not transparently managed, it can be a centralization risk, especially if critical functions depend on this approval.
Mitigation: Use transparent and decentralized mechanisms for approving virtual accounts. Consider allowing a decentralized network of nodes or users to validate and approve accounts based on consensus.
Governance of Core Contracts: The core contracts, such as the RootPort
contract, have various initialization and configuration functions. If these functions can only be called by specific addresses, it creates a centralization risk.
Mitigation: Utilize decentralized governance mechanisms to manage the configuration of core contracts. This can involve community proposals, voting, and transparent decision-making processes.
Bridge Agents and Chain Management: The management of bridge agents and chains is crucial. If decisions about adding new chains or bridge agents are centralized, it poses a centralization risk.
Mitigation: Implement a decentralized proposal and approval process for adding new chains or bridge agents. Community governance and consensus mechanisms can be applied here as well.
70 Hours
70 hours
#0 - c4-pre-sort
2023-10-15T14:04:54Z
0xA5DF marked the issue as sufficient quality report
#1 - alcueca
2023-10-20T12:22:59Z
You donβt need to sell the product. Let MaiaDAO do that.
Missing system overview. Extensive contract overview.
Architectural Improvement is boilerplate or AI
Centralization risk section is good.
#2 - c4-judge
2023-10-20T12:23:08Z
alcueca marked the issue as grade-b