CertiK reviewed Lakefront Finance (Lakefront Audit) on 14 Sep 2022: 16 findings, 0 critical; 9 marked fixed, 4 acknowledged, 3 open.
Report hosted on skynet.certik.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 4 | 0 |
| Medium | 0 | 0 | 1 |
| Low | 3 | 0 | 8 |
When transferring deflationary ERC20 tokens, the input amount may not be equal to the received amount due to the charged transaction fee. For example, if a user sends 100 deflationary tokens (with a 10% transaction fee), only 90 tokens actually arrived to the contract. However, a failure to discount such fees may allow the same user to withdraw 100 tokens from the contract, which causes the contract to lose 10 tokens in such a transaction. Reference: https://thoreum-finance.medium.com/what-exploit-happened-today-for-gocerberus-and-garuda-also-for-lokum-ybear-piggy-caramelswap-3943ee23a39f ```solidity=43 IERC20(_depositTokenAddress).safeTransferFrom(msg.sender, address(this), _amountInDepositToken); ``` - Transferring tokens by `_amountInDepositToken`. ```solidity=61 IUniswapRouterETH(unirouterAddress).swapExactTokensForTokens(_amountInDepositToken, 0, paths, address(this), block.timestamp); ``` - The `_amountInDepositToken` appears to be used for bookkeeping purposes without compensating the potential transfer fees. - Note: `swapExactTokensForTokens` is an external function and its behavior wasn't evaluated. --- ```solidity=124 shipyardVault.safeTransferFrom(msg.sender, address(this), _withdrawAmountInShipToken); ``` - Transferring tokens by `_withdrawAmountInShipToken`. ```solidity=126 shipyardVault.withdraw(_withdrawAmountInShipToken); ``` - The `_withdrawAmountInShipToken` appears to be used for bookkeeping purposes without compensating the potential transfer fees. - Note: `withdraw` is an external function and its behavior wasn't evaluated.
Multiple Solidity versions are used in the codebase. Versions used: `^0.6.12`, `^0.6.0`, `>=0.6.2<0.9.0` `^0.6.12` is used in projects/Lakefront/contracts/strategies/common/FeeManager.sol file. ```solidity=3 pragma solidity ^0.6.12; ``` `^0.6.0` is used in projects/Lakefront/contracts/strategies/curve/StrategyCurveLP.sol file. ```solidity=3 pragma solidity ^0.6.0; ``` `>=0.6.0<0.9.0` is used in projects/Lakefront/contracts/interfaces/common/IUniswapRouterETH.sol file. ```solidity=3 pragma solidity >=0.6.0 <0.9.0; ```
Performing integer division before multiplication truncates the low bits, losing the precision of calculation. --- ```solidity=345 return nativeOut.mul(5).div(1000).mul(callFee).div(MAX_FEE); ```
The functions which are never called internally within the contract should have external visibility for gas optimization. ```solidity=23 function setCallFee(uint256 _fee) public onlyManager { ``` --- ```solidity=30 function setPerformanceFee(uint256 _fee) public onlyManager { ``` --- ```solidity=37 function setStrategistFee(uint256 _fee) public onlyManager { ``` --- ```solidity=340 function callReward() public view returns (uint256) { ``` --- ```solidity=353 function panic() public onlyManager { ``` --- ```solidity=390 function underlyingToken(address _tokenAddress) public view returns (bool){ ``` --- ```solidity=394 function underlyingTokenIndex(address _tokenAddress) public view returns (uint256){ ``` --- ```solidity=72 function getPricePerFullShare() public view returns (uint256) { ```
There should always be events emitted in the sensitive functions that are controlled by centralization roles.
Addresses should be checked before assignment or external call to make sure they are not zero addresses. ```solidity=27 usdcAddress = _usdcAddress; ``` - `_usdcAddress` is not zero-checked before being used. --- ```solidity=37 keeper = _keeper; ``` - `_keeper` is not zero-checked before being used. --- ```solidity=38 strategist = _strategist; ``` - `_strategist` is not zero-checked before being used. --- ```solidity=39 unirouter = _unirouter; ``` - `_unirouter` is not zero-checked before being used. --- ```solidity=40 vault = _vault; ``` - `_vault` is not zero-checked before being used. --- ```solidity=41 companyFeeRecipient = _companyFeeRecipient; ``` - `_companyFeeRecipient` is not zero-checked before being used. --- ```solidity=55 keeper = _keeper; ``` - `_keeper` is not zero-checked before being used. --- ```solidity=64 strategist = _strategist; ``` - `_strategist` is not zero-checked before being used. --- ```solidity=72 unirouter = _unirouter; ``` - `_unirouter` is not zero-checked before being used. --- ```solidity=80 vault = _vault; ``` - `_vault` is not zero-checked before being used. --- ```solidity=88 companyFeeRecipient = _companyFeeRecipient; ``` - `_companyFeeRecipient` is not zero-checked before being used. --- ```solidity=86 want = _want; ``` - `_want` is not zero-checked before being used. --- ```solidity=87 gaugeFactory = _gaugeFactory; ``` - `_gaugeFactory` is not zero-checked before being used. --- ```solidity=88 rewardsGauge = _gauge; ``` - `_gauge` is not zero-checked before being used. --- ```solidity=89 pool = _pool; ``` - `_pool` is not zero-checked before being used. --- ```solidity=109 preferredUnderlyingToken = _preferredUnderlyingToken; ``` - `_preferredUnderlyingToken` is not zero-checked before being used. --- ```solidity=317 crvRouter = _router; ``` - `_router` is not zero-checked before being used.
State variables that never change should be declared as `constant` to save gas. ```solidity=12 address public gasprice = address(0xA43509661141F254F54D9A326E8Ec851A0b95307); ``` - `gasprice` should be declared `constant`.
The return value of an external call is not stored in a local or state variable. ```solidity=61 IUniswapRouterETH(unirouterAddress).swapExactTokensForTokens(_amountInDepositToken, 0, paths, address(this), block.timestamp); ``` --- ```solidity=174 IUniswapRouterETH(unirouter).swapExactTokensForTokens(_withdrawAmountInShipToken, 0, paths, address(this), block.timestamp); ``` --- ```solidity=190 IUniswapRouterETH(crvRouter).swapExactTokensForTokens(crvBal, 0, crvToNativeRoute, address(this), block.timestamp); ``` --- ```solidity=196 IUniswapRouterETH(unirouter).swapExactTokensForTokens(bal, 0, rewards[i].toNativeRoute, address(this), block.timestamp); ``` --- ```solidity=225 IUniswapRouterETH(unirouter).swapExactTokensForTokens(nativeBal, 0, nativeToDepositRoute, address(this), block.timestamp); ```
The linked variables assigned in the constructor can be declared as `immutable`. Immutable state variables can be assigned during contract creation but will remain constant throughout the lifetime of a deployed contract. A big advantage of immutable variables is that reading them is significantly cheaper than reading from regular state variables since they will not be stored in storage.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (15)
1,044 projects reviewed · 1,375 reports · latest May 2025
See CertiK’s auditsSomething wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us