Platform: Code4rena
Start Date: 02/08/2022
Pot Size: $50,000 USDC
Total HM: 12
Participants: 69
Period: 5 days
Judge: gzeon
Total Solo HM: 5
Id: 150
League: ETH
Rank: 14/69
Findings: 2
Award: $889.68
š Selected for report: 1
š Solo Findings: 0
š Selected for report: IllIllI
Also found by: 0x1f8b, 0xDjango, 0xNazgul, 0xc0ffEE, 8olidity, Bnke0x0, Chom, CodingNameKiki, Deivitto, Dravee, Funen, JC, JohnSmith, NoamYakov, ReyAdmirado, Rohan16, Rolezn, Sm4rty, SooYa, TomFrenchBlockchain, TomJ, Waze, __141345__, ajtra, ak1, aysha, bin2chen, bobirichman, brgltd, bulej93, c3phas, delfin454000, durianSausage, erictee, fatherOfBlocks, gogo, horsefacts, hyh, ladboy233, mics, natzuu, nxrblsrpr, oyc_109, rbserver, samruna, sikorico, simon135, tofunmi, wagmi
660.5833 USDC - $660.58
Issue | Instances | |
---|---|---|
[Lā01] | Use of msg.value in functions available to batches | 1 |
[Lā02] | Unused/empty receive() /fallback() function | 1 |
[Lā03] | Missing checks for address(0x0) when assigning values to address state variables | 2 |
Total: 4 instances over 3 issues
Issue | Instances | |
---|---|---|
[Nā01] | Missing initializer modifier on constructor | 1 |
[Nā02] | override function arguments that are unused should have the variable name removed or commented out to avoid compiler warnings | 5 |
[Nā03] | constant s should be defined rather than using magic numbers | 2 |
[Nā04] | Use a more recent version of solidity | 11 |
[Nā05] | Constant redefined elsewhere | 7 |
[Nā06] | Lines are too long | 1 |
[Nā07] | Typos | 12 |
[Nā08] | File is missing NatSpec | 11 |
[Nā09] | NatSpec is incomplete | 23 |
[Nā10] | Event is missing indexed fields | 5 |
[Nā11] | Not using the named return variables anywhere in the function is confusing | 3 |
Total: 81 instances over 11 issues
msg.value
in functions available to batchesThe contract extends BoringBatchable
, which warns to ensure msg.value
isn't able to be used in a batchable call. MIMOVaultActions.depositETH()
and MIMOVaultActions.depositETHAndBorrow()
both use msg.value
but aren't currently exploitable due to the fact that it has to be executed by the owner or an envoy, needs to be allow-listed, and even then the functions would require latent funds.
There is 1 instance of this issue:
File: /contracts/proxy/MIMOProxy.sol 54: function execute(address target, bytes calldata data) public payable override returns (bytes memory response) {
receive()
/fallback()
functionIf the intention is for the Ether to be used, the function should call another function, otherwise it should revert (e.g. require(msg.sender == address(weth))
)
There is 1 instance of this issue:
File: contracts/proxy/MIMOProxy.sol 38: receive() external payable {}
address(0x0)
when assigning values to address
state variablesThere are 2 instances of this issue:
File: contracts/proxy/MIMOProxyFactory.sol 27: mimoProxyBase = _mimoProxyBase;
File: contracts/proxy/MIMOProxy.sol 122: owner = newOwner;
initializer
modifier on constructorOpenZeppelin recommends that the initializer
modifier be applied to constructors in order to avoid potential griefs, social engineering, or exploits. Ensure that the modifier is applied to the implementation contract. If the default constructor is currently being used, it should be changed to be an explicit one with the modifier applied.
There is 1 instance of this issue:
File: contracts/proxy/MIMOProxy.sol 12: contract MIMOProxy is IMIMOProxy, Initializable, BoringBatchable {
override
function arguments that are unused should have the variable name removed or commented out to avoid compiler warningsThere are 5 instances of this issue:
File: contracts/actions/MIMOFlashloan.sol 39: address[] calldata assets, 40: uint256[] calldata amounts, 41: uint256[] calldata premiums, 42: address initiator, 43: bytes calldata params
constant
s should be defined rather than using magic numbersEven assembly can benefit from using readable constants instead of hex/numeric literals
There are 2 instances of this issue:
File: contracts/actions/automated/MIMOAutoRebalance.sol /// @audit 1e15 180: uint256 targetRatio = autoVault.targetRatio + 1e15; // add 0.1% to account for rounding
File: contracts/proxy/MIMOProxy.sol /// @audit 5_000 30: minGasReserve = 5_000;
Use a solidity version of at least 0.8.13 to get the ability to use using for
with a list of free functions
There are 11 instances of this issue:
File: contracts/actions/automated/MIMOAutoAction.sol 2: pragma solidity 0.8.10;
File: contracts/actions/automated/MIMOAutoRebalance.sol 2: pragma solidity 0.8.10;
File: contracts/actions/managed/MIMOManagedAction.sol 2: pragma solidity 0.8.10;
File: contracts/actions/managed/MIMOManagedRebalance.sol 2: pragma solidity 0.8.10;
File: contracts/actions/MIMOEmptyVault.sol 2: pragma solidity 0.8.10;
File: contracts/actions/MIMOFlashloan.sol 2: pragma solidity 0.8.10;
File: contracts/actions/MIMOLeverage.sol 2: pragma solidity 0.8.10;
File: contracts/actions/MIMORebalance.sol 2: pragma solidity 0.8.10;
File: contracts/actions/MIMOSwap.sol 2: pragma solidity 0.8.10;
File: contracts/actions/MIMOVaultActions.sol 3: pragma solidity 0.8.10;
File: contracts/proxy/MIMOProxyFactory.sol 2: pragma solidity >=0.8.4;
Consider defining in only one contract so that values cannot become out of sync when only one location is updated. A cheap way to store constants in a single location is to create an internal constant
in a library
. If the variable is a local cache of another contract's value, consider making the cache variable internal or private, which will require external users to query the contract with the source of truth, so that callers don't get out of sync.
There are 7 instances of this issue:
File: contracts/actions/managed/MIMOManagedAction.sol /// @audit seen in contracts/actions/automated/MIMOAutoAction.sol 12: IAddressProvider public immutable a; /// @audit seen in contracts/actions/automated/MIMOAutoAction.sol 13: IMIMOProxyRegistry public immutable proxyRegistry;
File: contracts/actions/managed/MIMOManagedRebalance.sol /// @audit seen in contracts/actions/automated/MIMOAutoRebalance.sol 20: address public immutable mimoRebalance;
File: contracts/actions/MIMOEmptyVault.sol /// @audit seen in contracts/actions/managed/MIMOManagedAction.sol 17: IMIMOProxyRegistry public immutable proxyRegistry;
File: contracts/actions/MIMOLeverage.sol /// @audit seen in contracts/actions/MIMOEmptyVault.sol 17: IMIMOProxyRegistry public immutable proxyRegistry;
File: contracts/actions/MIMORebalance.sol /// @audit seen in contracts/actions/MIMOLeverage.sol 17: IMIMOProxyRegistry public immutable proxyRegistry;
File: contracts/actions/MIMOSwap.sol /// @audit seen in contracts/actions/managed/MIMOManagedAction.sol 19: IAddressProvider public immutable a;
Usually lines in source code are limited to 80 characters. Today's screens are much larger so it's reasonable to stretch this in some cases. Since the files will most likely reside in GitHub, and GitHub starts using a scroll bar in all cases when the length is over 164 characters, the lines below should be split when they reach that length
There is 1 instance of this issue:
File: contracts/actions/managed/MIMOManagedRebalance.sol 14: @notice This contract only serves to change the access control and enforce the `managedRebalance` configuration; the actual rebalance logic is done through the `MIMORebalance` contract through a `delegateCall` from a `MIMOProxy` clone
There are 12 instances of this issue:
File: contracts/actions/automated/MIMOAutoRebalance.sol /// @audit aggegator 52: @param swapData SwapData struct containing aggegator swap parameters /// @audit reblanced 84: @param assets Address array with one element corresponding to the address of the reblanced asset /// @audit rebalnce 157: @notice Helper function calculating the amount to rebalance from vault A and to mint from vault B with rebalnce formula /// @audit og 159: @param vaultState VaultState struct og the vault to rebalance /// @audit allowedVaration 254: @dev Checks that change in global vault value (vault A + B) is below allowedVaration and vault A ratio equal or above targetRatio
File: contracts/actions/managed/MIMOManagedRebalance.sol /// @audit aggegator 48: @param swapData SwapData struct containing aggegator swap parameters /// @audit reblanced 85: @param assets Address array with one element corresponding to the address of the reblanced asset /// @audit allowedVaration 170: @dev Checks that change in global vault value (vault A + B) is below allowedVaration and vault A & B ratios are at least targetRatios
File: contracts/actions/MIMOLeverage.sol /// @audit FlashloanDat /// @audit struc 42: @param _calldata Bytes containing depositAmount, stablex swapAmount, struct FlashloanDat data and struc SwapData
File: contracts/actions/MIMORebalance.sol /// @audit reblanced 57: @param assets Address array with one element corresponding to the address of the reblanced asset
File: contracts/proxy/interfaces/IMIMOProxyFactory.sol /// @audit PRBProxy 19: /// @notice The release version of PRBProxy.
There are 11 instances of this issue:
File: contracts/actions/automated/interfaces/IMIMOAutoAction.sol
File: contracts/actions/automated/interfaces/IMIMOAutoRebalance.sol
File: contracts/actions/interfaces/IMIMOEmptyVault.sol
File: contracts/actions/interfaces/IMIMOFlashloan.sol
File: contracts/actions/interfaces/IMIMOLeverage.sol
File: contracts/actions/interfaces/IMIMOProxyAction.sol
File: contracts/actions/interfaces/IMIMORebalance.sol
File: contracts/actions/interfaces/IMIMOSwap.sol
File: contracts/actions/interfaces/IMIMOVaultActions.sol
File: contracts/actions/managed/interfaces/IMIMOManagedAction.sol
File: contracts/actions/managed/interfaces/IMIMOManagedRebalance.sol
There are 23 instances of this issue:
File: contracts/actions/automated/MIMOAutoAction.sol /// @audit Missing: '@param vaultId' 54 /** 55 @return AutomatedVault struct of a specific vault id 56 */ 57: function getAutomatedVault(uint256 vaultId) external view override returns (AutomatedVault memory) { /// @audit Missing: '@param vaultId' 61 /** 62 @return Timestamp of the last performed operation 63 */ 64: function getOperationTracker(uint256 vaultId) external view override returns (uint256) { /// @audit Missing: '@param autoVault' /// @audit Missing: '@param rebalanceValue' /// @audit Missing: '@param swapResultValue' 88 /** 89 @notice Helper function determining if a vault value variation is within vault's management parameters 90 @return True if value change is below allowedVariation and false if it is above 91 */ 92 function _isVaultVariationAllowed( 93 AutomatedVault memory autoVault, 94 uint256 rebalanceValue, 95 uint256 swapResultValue 96: ) internal pure returns (bool) {
File: contracts/actions/automated/MIMOAutoRebalance.sol /// @audit Missing: '@return' 88 @param params Bytes sent by this contract containing MIMOProxy owner, RebalanceData struct and SwapData struct 89 */ 90 function executeOperation( 91 address[] calldata assets, 92 uint256[] calldata amounts, 93 uint256[] calldata premiums, 94 address initiator, 95 bytes calldata params 96: ) external override returns (bool) {
File: contracts/actions/managed/MIMOManagedAction.sol /// @audit Missing: '@param vaultId' 67 /** 68 @return ManagedVault struct of a specific vault id 69 */ 70: function getManagedVault(uint256 vaultId) external view override returns (ManagedVault memory) { /// @audit Missing: '@param vaultId' 74 /** 75 @return Timestamp of the last performed operation 76 */ 77: function getOperationTracker(uint256 vaultId) external view override returns (uint256) { /// @audit Missing: '@param manager' 81 /** 82 @return Bool value indicating if an address is allowed to manage user vaults or not 83 */ 84: function getManager(address manager) external view override returns (bool) { /// @audit Missing: '@param vaultId' 88 /** 89 @notice Helper function calculating LTV ratio 90 @return Vault collateral value / vault debt 91 */ 92: function _getVaultRatio(uint256 vaultId) internal view returns (uint256) { /// @audit Missing: '@param managedVault' /// @audit Missing: '@param rebalanceValue' /// @audit Missing: '@param swapResultValue' 111 /** 112 @notice Helper function determining if a vault value variation is within vault's management parameters 113 @return True if value change is below allowedVariation and false if it is above 114 */ 115 function _isVaultVariationAllowed( 116 ManagedVault memory managedVault, 117 uint256 rebalanceValue, 118 uint256 swapResultValue 119: ) internal pure returns (bool) {
File: contracts/actions/managed/MIMOManagedRebalance.sol /// @audit Missing: '@return' 89 @param params Bytes sent by this contract containing MIMOProxy owner, RebalanceData struct and SwapData struct 90 */ 91 function executeOperation( 92 address[] calldata assets, 93 uint256[] calldata amounts, 94 uint256[] calldata premiums, 95 address initiator, 96 bytes calldata params 97: ) external override returns (bool) { /// @audit Missing: '@param rebalanceAmount' 135 /** 136 @notice Helper function performing pre rebalance operation sanity checks 137 @dev Checks that vault is managed, that rebalance was called by manager, and maximum daily operation was not reached 138 @param managedVault ManagedVault struct of the vault to rebalance 139 @param rbData RebalanceData struct of the vault to rebalance 140 @param vaultsData Cached VaultsDataProvider interface for gas saving 141 */ 142 function _preRebalanceChecks( 143 ManagedVault memory managedVault, 144 IMIMORebalance.RebalanceData calldata rbData, 145 IVaultsDataProvider vaultsData, 146: uint256 rebalanceAmount
File: contracts/actions/MIMOEmptyVault.sol /// @audit Missing: '@return' 61 @param params Bytes sent by this contract containing MIMOProxy owner, target vault id, SwapData struct 62 */ 63 function executeOperation( 64 address[] calldata assets, 65 uint256[] calldata amounts, 66 uint256[] calldata premiums, 67 address initiator, 68 bytes calldata params 69: ) external override returns (bool) {
File: contracts/actions/MIMOFlashloan.sol /// @audit Missing: '@return' 36 @param params Bytes sent in the _takeFlashLoan calls that encode any additional needed information to complete the transaction 37 */ 38 function executeOperation( 39 address[] calldata assets, 40 uint256[] calldata amounts, 41 uint256[] calldata premiums, 42 address initiator, 43 bytes calldata params 44: ) external virtual override returns (bool) {}
File: contracts/actions/MIMOLeverage.sol /// @audit Missing: '@return' 66 @param params Bytes sent by this contract containing MIMOProxy owner, stablex swap amount and swap data 67 */ 68 function executeOperation( 69 address[] calldata assets, 70 uint256[] calldata amounts, 71 uint256[] calldata premiums, 72 address initiator, 73 bytes calldata params 74: ) external override returns (bool) {
File: contracts/actions/MIMORebalance.sol /// @audit Missing: '@return' 61 @param params Bytes sent by this contract containing MIMOProxy owner, RebalanceData struct and SwapData struct 62 */ 63 function executeOperation( 64 address[] calldata assets, 65 uint256[] calldata amounts, 66 uint256[] calldata premiums, 67 address initiator, 68 bytes calldata params 69: ) external override returns (bool) {
File: contracts/proxy/interfaces/IMIMOProxyFactory.sol /// @audit Missing: '@return' 15 /// @notice Mapping to track all deployed proxies. 16 /// @param proxy The address of the proxy to make the check for. 17: function isProxy(address proxy) external view returns (bool result);
File: contracts/proxy/interfaces/IMIMOProxyRegistry.sol /// @audit Missing: '@return' 16 /// @notice Gets the current proxy of the given owner. 17 /// @param owner The address of the owner of the current proxy. 18: function getCurrentProxy(address owner) external view returns (IMIMOProxy proxy);
File: contracts/proxy/interfaces/IMIMOProxy.sol /// @audit Missing: '@return' 22 /// @param selector The selector of the method of the target contract called by the envoy 23 /// contract and function selector. 24 function getPermission( 25 address envoy, 26 address target, 27 bytes4 selector 28: ) external view returns (bool); /// @audit Missing: '@return' 77 /// @param targets An array of contract addresses to call 78 /// @param data The bytes for each batched function call 79: function multicall(address[] calldata targets, bytes[] calldata data) external returns (bytes[] memory);
indexed
fieldsIndex event fields make the field more quickly accessible to off-chain tools that parse events. However, note that each index field costs extra gas during emission, so it's not necessarily best to index the maximum allowed per event (threefields). Each event
should use three indexed
fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three fields, all of the fields should be indexed.
There are 5 instances of this issue:
File: contracts/actions/automated/interfaces/IMIMOAutoAction.sol 25: event AutomationSet(uint256 vaultId, AutomatedVault autoVault);
File: contracts/actions/managed/interfaces/IMIMOManagedAction.sol 22: event ManagerSet(address manager, bool isManager); 23: event ManagementSet(uint256 vaultId, ManagedVault managedVault);
File: contracts/proxy/interfaces/IMIMOProxyFactory.sol 11: event DeployProxy(address indexed deployer, address indexed owner, address proxy);
File: contracts/proxy/interfaces/IMIMOProxy.sol 9: event Execute(address indexed target, bytes data, bytes response);
Consider changing the variable to be an unnamed one
There are 3 instances of this issue:
File: contracts/actions/automated/MIMOAutoRebalance.sol /// @audit rebalanceAmount /// @audit mintAmount /// @audit autoFee 142 function getAmounts(uint256 vaultId, address toCollateral) 143 external 144 view 145 override 146 returns ( 147 uint256 rebalanceAmount, 148 uint256 mintAmount, 149: uint256 autoFee
#0 - m19
2022-08-18T08:10:21Z
This is an outstanding QA report
#1 - liveactionllama
2022-09-06T16:50:16Z
Per @gzeoneth (judge), they agree with the severities outlined above by the warden.
š Selected for report: Dravee
Also found by: 0x040, 0x1f8b, 0xDjango, 0xNazgul, 0xSmartContract, 0xc0ffEE, Aymen0909, Bnke0x0, Chom, CodingNameKiki, Deivitto, Fitraldys, Funen, IllIllI, JC, JohnSmith, NoamYakov, ReyAdmirado, Rolezn, TomJ, Waze, ajtra, bearonbike, bobirichman, brgltd, c3phas, durianSausage, fatherOfBlocks, gogo, ignacio, jag, joestakey, ladboy233, mics, oyc_109, rbserver, samruna, sikorico, simon135
229.1011 USDC - $229.10
Issue | Instances | |
---|---|---|
[Gā01] | Multiple address /ID mappings can be combined into a single mapping of an address /ID to a struct , where appropriate | 2 |
[Gā02] | State variables only set in the constructor should be declared immutable | 2 |
[Gā03] | State variables should be cached in stack variables rather than re-reading them from storage | 5 |
[Gā04] | internal functions only called once can be inlined to save gas | 5 |
[Gā05] | Add unchecked {} for subtractions where the operands cannot underflow because of a previous require() or if -statement | 4 |
[Gā06] | Optimize names to save gas | 15 |
[Gā07] | Using bool s for storage incurs overhead | 3 |
[Gā08] | ++i costs less gas than i++ , especially when it's used in for -loops (--i /i-- too) | 1 |
[Gā09] | Empty blocks should be removed or emit something | 1 |
[Gā10] | Use custom errors rather than revert() /require() strings to save gas | 5 |
Total: 43 instances over 10 issues
address
/ID mappings can be combined into a single mapping
of an address
/ID to a struct
, where appropriateSaves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot. Finally, if both fields are accessed in the same function, can save ~42 gas per access due to not having to recalculate the key's keccak256 hash (Gkeccak256 - 30 gas) and that calculation's associated stack operations.
There are 2 instances of this issue:
File: contracts/actions/automated/MIMOAutoAction.sol 15 mapping(uint256 => AutomatedVault) internal _automatedVaults; 16: mapping(uint256 => uint256) internal _operationTracker;
File: contracts/actions/managed/MIMOManagedAction.sol 15 mapping(uint256 => ManagedVault) internal _managedVaults; 16: mapping(uint256 => uint256) internal _operationTracker;
immutable
Avoids a Gsset (20000 gas) in the constructor, and replaces the first access in each transaction (Gcoldsload - 2100 gas) and each access thereafter (Gwarmacces - 100 gas) with a PUSH32
(3 gas).
There are 2 instances of this issue:
File: contracts/proxy/MIMOProxyRegistry.sol /// @audit factory (constructor) 27: factory = factory_; /// @audit factory (access) 54: proxy = factory.deployFor(owner);
The instances below point to the second+ access of a state variable within a function. Caching of a state variable replace each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
There are 5 instances of this issue:
File: contracts/proxy/MIMOProxy.sol /// @audit owner on line 56 62: revert CustomErrors.EXECUTION_NOT_AUTHORIZED(owner, msg.sender, target, selector); /// @audit owner on line 62 72: address owner_ = owner; /// @audit owner on line 82 83: revert CustomErrors.OWNER_CHANGED(owner_, owner); /// @audit owner on line 110 111: revert CustomErrors.NOT_OWNER(owner, msg.sender); /// @audit owner on line 128 129: revert CustomErrors.NOT_OWNER(owner, msg.sender);
internal
functions only called once can be inlined to save gasNot inlining costs 20 to 40 gas because of two extra JUMP
instructions and additional stack operations needed for function calls.
There are 5 instances of this issue:
File: contracts/actions/automated/MIMOAutoRebalance.sol 204 function _getRebalanceParams( 205 AutomatedVault memory autoVault, 206 VaultState memory vaultState, 207 IERC20 toCollateral, 208 uint256 vaultId 209 ) 210 internal 211 view 212 returns ( 213 IMIMORebalance.RebalanceData memory rbData, 214 FlashLoanData memory flData, 215: uint256 autoFee 236 function _preRebalanceChecks( 237 AutomatedVault memory autoVault, 238 uint256 vaultId, 239: uint256 vaultARatio 262 function _postRebalanceChecks( 263 AutomatedVault memory autoVault, 264 uint256 rebalanceAmount, 265 uint256 vaultBBalanceBefore, 266 uint256 vaultId, 267 address vaultOwner, 268: IVaultsDataProvider vaultsData
File: contracts/actions/managed/MIMOManagedRebalance.sol 142 function _preRebalanceChecks( 143 ManagedVault memory managedVault, 144 IMIMORebalance.RebalanceData calldata rbData, 145 IVaultsDataProvider vaultsData, 146: uint256 rebalanceAmount 179 function _postRebalanceChecks( 180 ManagedVault memory managedVault, 181 uint256 rebalanceAmount, 182 uint256 vaultBBalanceBefore, 183 uint256 vaultId, 184 address vaultOwner, 185 address toCollateral, 186: IVaultsDataProvider vaultsData
unchecked {}
for subtractions where the operands cannot underflow because of a previous require()
or if
-statementrequire(a <= b); x = b - a
=> require(a <= b); unchecked { x = b - a }
There are 4 instances of this issue:
File: contracts/actions/MIMOLeverage.sol /// @audit require() on line 130 133: token.safeIncreaseAllowance(address(core), collateralBalanceAfter - flashloanRepayAmount); /// @audit require() on line 130 134: core.deposit(address(token), collateralBalanceAfter - flashloanRepayAmount); /// @audit if-condition on line 132 133: token.safeIncreaseAllowance(address(core), collateralBalanceAfter - flashloanRepayAmount); /// @audit if-condition on line 132 134: core.deposit(address(token), collateralBalanceAfter - flashloanRepayAmount);
public
/external
function names and public
member variable names can be optimized to save gas. See this link for an example of how it works. Below are the interfaces/abstract contracts that can be optimized so that the most frequently-called functions use the least amount of gas possible during method lookup. Method IDs that have two leading zero bytes can save 128 gas each during deployment, and renaming functions to have lower method IDs will save 22 gas per call, per sorted position shifted
There are 15 instances of this issue:
File: contracts/actions/automated/interfaces/IMIMOAutoAction.sol /// @audit setAutomation(), a(), proxyRegistry(), getAutomatedVault(), getOperationTracker() 7: interface IMIMOAutoAction {
File: contracts/actions/automated/interfaces/IMIMOAutoRebalance.sol /// @audit rebalance(), getAmounts() 9: interface IMIMOAutoRebalance is IMIMOAutoAction {
File: contracts/actions/interfaces/IMIMOEmptyVault.sol /// @audit emptyVaultOperation() 7: interface IMIMOEmtpyVault is IMIMOProxyAction, IMIMOSwap {
File: contracts/actions/interfaces/IMIMOFlashloan.sol /// @audit executeOperation(), lendingPool() 10: interface IMIMOFlashloan {
File: contracts/actions/interfaces/IMIMOLeverage.sol /// @audit leverageOperation() 9: interface IMIMOLeverage is IMIMOSwap, IMIMOProxyAction {
File: contracts/actions/interfaces/IMIMOProxyAction.sol /// @audit executeAction() 4: interface IMIMOProxyAction {
File: contracts/actions/interfaces/IMIMORebalance.sol /// @audit rebalanceOperation() 7: interface IMIMORebalance is IMIMOProxyAction, IMIMOSwap {
File: contracts/actions/interfaces/IMIMOVaultActions.sol /// @audit deposit(), depositETH(), depositAndBorrow(), depositETHAndBorrow(), withdraw(), withdrawETH(), borrow(), core(), vaultsData(), stablex() 8: interface IMIMOVaultActions {
File: contracts/actions/managed/interfaces/IMIMOManagedAction.sol /// @audit setManagement(), setManager(), a(), proxyRegistry(), getManagedVault(), getOperationTracker(), getManager() 11: interface IMIMOManagedAction {
File: contracts/actions/managed/interfaces/IMIMOManagedRebalance.sol /// @audit rebalance() 11: interface IMIMOManagedRebalance is IMIMOManagedAction {
File: contracts/actions/MIMOEmptyVault.sol /// @audit emptyVaultOperation() 14: contract MIMOEmptyVault is MIMOSwap, MIMOFlashloan, IMIMOEmtpyVault {
File: contracts/proxy/interfaces/IMIMOProxyFactory.sol /// @audit isProxy(), VERSION(), deploy(), deployFor() 8: interface IMIMOProxyFactory {
File: contracts/proxy/interfaces/IMIMOProxyRegistry.sol /// @audit factory(), getCurrentProxy(), deploy(), deployFor() 10: interface IMIMOProxyRegistry {
File: contracts/proxy/interfaces/IMIMOProxy.sol /// @audit initialize(), getPermission(), minGasReserve(), execute(), setPermission(), multicall() 6: interface IMIMOProxy {
File: contracts/proxy/MIMOProxy.sol /// @audit initialize() 12: contract MIMOProxy is IMIMOProxy, Initializable, BoringBatchable {
bool
s for storage incurs overhead// Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled.
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/58f635312aa21f947cae5f8578638a85aa2519f5/contracts/security/ReentrancyGuard.sol#L23-L27
Use uint256(1)
and uint256(2)
for true/false to avoid a Gwarmaccess (100 gas) for the extra SLOAD, and to avoid Gsset (20000 gas) when changing from false
to true
, after having been true
in the past
There are 3 instances of this issue:
File: contracts/actions/managed/MIMOManagedAction.sol 17: mapping(address => bool) internal _managers;
File: contracts/proxy/MIMOProxyFactory.sol 24: mapping(address => bool) internal _proxies;
File: contracts/proxy/MIMOProxy.sol 24: mapping(address => mapping(address => mapping(bytes4 => bool))) internal _permissions;
++i
costs less gas than i++
, especially when it's used in for
-loops (--i
/i--
too)Saves 5 gas per loop
There is 1 instance of this issue:
File: contracts/proxy/MIMOProxy.sol 132: for (uint256 i = 0; i < targets.length; i++) {
The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the contract is meant to be extended, the contract should be abstract
and the function signatures be added without any default implementation. If the block is an empty if
-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if(x){}else if(y){...}else{...}
=> if(!x){if(y){...}else{...}}
). Empty receive()
/fallback() payable
functions that are not used, can be removed to save deployment gas.
There is 1 instance of this issue:
File: contracts/proxy/MIMOProxy.sol 38: receive() external payable {}
revert()
/require()
strings to save gasCustom errors are available from solidity version 0.8.4. Custom errors save ~50 gas each time they're hit by avoiding having to allocate and store the revert string. Not defining the strings also save deployment gas
There are 5 instances of this issue:
File: contracts/actions/MIMOEmptyVault.sol 96: require(flashloanRepayAmount <= vaultCollateral.balanceOf(address(this)), Errors.CANNOT_REPAY_FLASHLOAN);
File: contracts/actions/MIMOLeverage.sol 130: require(collateralBalanceAfter >= flashloanRepayAmount, Errors.CANNOT_REPAY_FLASHLOAN);
File: contracts/actions/MIMORebalance.sol 129 require( 130 a.vaultsData().vaultCollateralBalance(rbData.vaultId) >= flashloanRepayAmount, 131 Errors.CANNOT_REPAY_FLASHLOAN 132: );
File: contracts/actions/MIMOSwap.sol 47: require(proxy != address(0), Errors.INVALID_AGGREGATOR); 48: require(router != address(0), Errors.INVALID_AGGREGATOR);
#0 - m19
2022-08-18T07:57:57Z
We found this gas report really outstanding