Maia DAO - Ulysses - hihen'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: 60/175

Findings: 1

Award: $78.19

Gas:
grade-a

🌟 Selected for report: 0

šŸš€ Solo Findings: 0

Awards

78.1884 USDC - $78.19

Labels

bug
G (Gas Optimization)
grade-a
sufficient quality report
G-11

External Links

Summary

Total 27 instances over 5 issueswith 40213 gas saved:

IDIssueInstancesGas
[G‑01]Use unchecked block for safe subtractions185
[G‑02]Do not cache state variables that are used only once26
[G‑03]Unlimited gas consumption risk due to external call recipients13-
[G‑04]Use selfbalance() instead of address(x).balance9135
[G‑05]Consider using bytes32 rather than a string240000

Gas Optimizations

[G‑01] Use unchecked block for safe subtractions

If it can be confirmed that the subtraction operation will not overflow, using an unchecked block can save gas. For example, require(x <= y); z = y - x; can be optimized to require(x <= y); unchecked { z = y - x; }.

There is 1 instance:

  • RootBridgeAgent.sol ( #L1149 ):
/// @audit checked on line 1142
1149:         if (_amount - _deposit > 0) {

[G‑02] Do not cache state variables that are used only once

It's cheaper to access the state variable directly if it is accessed only once. This can save the 3 gas cost of the extra stack allocation.

There are 2 instances:

195:         address globalAddress = getGlobalTokenFromLocal[_localAddress][_srcChainId];

206:         address localAddress = getLocalTokenFromGlobal[_globalAddress][_srcChainId];

[G‑03] Unlimited gas consumption risk due to external call recipients

When calling an external function without specifying a gas limit , the called contract may consume all the remaining gas, causing the tx to be reverted. To mitigate this, it is recommended to explicitly set a gas limit when making low level external calls.

There are 13 instances (click to show):

239:             IVirtualAccount(userAccount).call(calls);

248:             IVirtualAccount(userAccount).call(calls);

275:             IVirtualAccount(userAccount).call(calls);

328:             IVirtualAccount(userAccount).call(calls);

337:             IVirtualAccount(userAccount).call(calls);

364:             IVirtualAccount(userAccount).call(calls);

416:             IVirtualAccount(userAccount).call(calls);

425:             IVirtualAccount(userAccount).call(calls);

452:             IVirtualAccount(userAccount).call(calls);
835:             callee.call{value: msg.value}("");

927:             callee.call{value: _value}("");
74:             if (isContract(_call.target)) (success, returnData[i]) = _call.target.call(_call.callData);

101:             if (isContract(_call.target)) (success, returnData[i]) = _call.target.call{value: val}(_call.callData);

[G‑04] Use selfbalance() instead of address(x).balance

Use assembly when getting a contract's balance of ETH. You can use selfbalance() instead of address(x).balance when getting your contract's balance of ETH to save gas. Additionally, you can use balance(address) instead of address.balance() when getting an external contract's balance of ETH. Saves 15 gas when checking internal balance, 6 for external.

There are 9 instances:

717:         (bool success,) = bridgeAgentExecutorAddress.call{value: address(this).balance}(_calldata);

737:         (bool success,) = bridgeAgentExecutorAddress.call{value: address(this).balance}(_calldata);

787:         ILayerZeroEndpoint(lzEndpointAddress).send{value: address(this).balance}(
  • BranchBridgeAgentExecutor.sol ( #L92, #L126 ):
92:             _recipient.safeTransferETH(address(this).balance);

126:             _recipient.safeTransferETH(address(this).balance);
695:                 address(this).balance

754:         (bool success,) = bridgeAgentExecutorAddress.call{value: address(this).balance}(_calldata);

779:         (bool success,) = bridgeAgentExecutorAddress.call{value: address(this).balance}(_calldata);

940:         ILayerZeroEndpoint(lzEndpointAddress).send{value: address(this).balance}(

[G‑05] Consider using bytes32 rather than a string

Using the bytes types for fixed-length strings is more efficient than having the EVM have to incur the overhead of string processing. Consider whether the value needs to be a string. A good reason to keep it as a string would be if the variable is defined in an interface that this project does not own.

There are 2 instances:

  • ERC20hTokenBranchFactory.sol ( #L26, #L29 ):
26:     string public chainName;

29:     string public chainSymbol;

#0 - c4-pre-sort

2023-10-15T17:07:08Z

0xA5DF marked the issue as sufficient quality report

#1 - c4-judge

2023-10-26T13:47:15Z

alcueca marked the issue as grade-a

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