Platform: Code4rena
Start Date: 10/03/2022
Pot Size: $75,000 USDT
Total HM: 25
Participants: 54
Period: 7 days
Judge: pauliax
Total Solo HM: 10
Id: 97
League: ETH
Rank: 30/54
Findings: 2
Award: $295.96
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: hickuphh3
Also found by: 0v3rf10w, 0x1f8b, 0xDjango, 0xNazgul, 0xngndev, 0xwags, Cantor_Dust, CertoraInc, Dravee, IllIllI, PPrieditis, Ruhum, TerrierLover, WatchPug, XDms, benk10, berndartmueller, bitbopper, catchup, cmichel, cryptphi, csanuragjain, danb, defsec, gzeon, hagrid, hubble, jayjonah8, kenta, kyliek, minhquanym, rfa, robee, saian, samruna, throttle, ye0lde, z3s
119.3436 USDT - $119.34
onlyExecutor()
is defined but not used at all. Can delete it.
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/ExecutorManager.sol#L15-L19
// MODIFIERS modifier onlyExecutor() { require(executorStatus[msg.sender], "You are not allowed to perform this operation"); _; }
Simply delete onlyExecutor
modifier
transfer function has _tokenAddress
and _tokenAmount
arguments with _
. This is not aligned with other patterns (_
is added when there are naming conflicts with state variables)
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityPool.sol#L395-L397
function transfer( address _tokenAddress, address receiver, uint256 _tokenAmount ) external whenNotPaused onlyLiquidityProviders nonReentrant {
To be consistent with other functions in this contract, should not add _
for _tokenAddress
and _tokenAmount
.
This comment does not do anything. This should simply be removed. https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityPool.sol#L374
// uint256 gasFeeAccumulated = gasFeeAccumulatedByToken[tokenAddress];
contract ExecutorManager is IExecutorManager, Ownable { address[] internal executors; mapping(address => bool) internal executorStatus; event ExecutorAdded(address executor, address owner); event ExecutorRemoved(address executor, address owner);
Add indexed at address
arguments.
event ExecutorAdded(address indexed executor, address indexed owner); event ExecutorRemoved(address indexed executor, address indexed owner);
🌟 Selected for report: Dravee
Also found by: 0v3rf10w, 0x1f8b, 0xDjango, 0xNazgul, 0xngndev, 0xwags, Cantor_Dust, CertoraInc, IllIllI, Jujic, Kenshin, Kiep, PPrieditis, TerrierLover, Tomio, WatchPug, antonttc, benk10, berndartmueller, bitbopper, csanuragjain, defsec, gzeon, hagrid, hickuphh3, kenta, minhquanym, oyc_109, pedroais, peritoflores, rfa, robee, saian, samruna, sirhashalot, throttle, wuwe1, z3s
176.617 USDT - $176.62
initialGas
is not needed at LiquidityPool.sol
initialGas
is defined at the top of the function, but this is not needed at all.
uint256 initialGas = gasleft(); ... uint256 amountToTransfer = getAmountToTransfer(initialGas, tokenAddress, amount, tokenGasPrice);
Simply removing initialGas
variable, and call gasleft()
directly.
uint256 amountToTransfer = getAmountToTransfer(gasleft(), tokenAddress, amount, tokenGasPrice);
Deployments gas fee of LiquidityPool
Both functions have onlyOwner
modifier, so the owner can control the number of arrays in executorArray
. So can use unchecked directory for ++i.
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/ExecutorManager.sol#L31
function addExecutors(address[] calldata executorArray) external override onlyOwner { for (uint256 i = 0; i < executorArray.length; ++i) { addExecutor(executorArray[i]); } }
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/ExecutorManager.sol#L47
function removeExecutors(address[] calldata executorArray) external override onlyOwner { for (uint256 i = 0; i < executorArray.length; ++i) { removeExecutor(executorArray[i]); } }
index
is less likely to overflow.
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L233
for (index = 0; index < nftsStakedLength; ++index) { if (nftIdsStaked[msgSender][index] == _nftId) { break; } }
Following two functions use onlyOwner
modifier, so may be able to use unchecked for ++i.
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/WhitelistPeriodManager.sol#L180-L183
for (uint256 i = 0; i < _addresses.length; ++i) { isExcludedAddress[_addresses[i]] = _status[i]; emit ExcludedAddressStatusUpdated(_addresses[i], _status[i]); }
for (uint256 i = 0; i < _tokens.length; ++i) { setCap(_tokens[i], _totalCaps[i], _perTokenWalletCaps[i]); }
i can be go up to totalSupply
which is uint256. It will not be overflown, so can use unchecked directory.
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/WhitelistPeriodManager.sol#L248-L253
for (uint256 i = 1; i <= totalSupply; ++i) { uint256 liquidity = totalLiquidityByLp[_token][lpToken.ownerOf(i)]; if (liquidity > maxLp) { maxLp = liquidity; } }
It is less likely for owners to have the max value of NFT. Hense, ++i can be wrapped with unchecked.
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/token/LPToken.sol#L77-L79
function getAllNftIdsByUser(address _owner) public view returns (uint256[] memory) { uint256[] memory nftIds = new uint256[](balanceOf(_owner)); for (uint256 i = 0; i < nftIds.length; ++i) { nftIds[i] = tokenOfOwnerByIndex(_owner, i); } return nftIds; }
onlyOwner
modifier is used, so may be able to use unchecked for ++index.
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/token/TokenManager.sol#L78-L81
for (uint256 index = 0; index < tokenConfig.length; ++index) { depositConfig[toChainId[index]][tokenAddresses[index]].min = tokenConfig[index].min; depositConfig[toChainId[index]][tokenAddresses[index]].max = tokenConfig[index].max; }
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/ExecutorManager.sol#L31
function addExecutors(address[] calldata executorArray) external override onlyOwner { for (uint256 i = 0; i < executorArray.length; ++i) { addExecutor(executorArray[i]); } }
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/ExecutorManager.sol#L47
function removeExecutors(address[] calldata executorArray) external override onlyOwner { for (uint256 i = 0; i < executorArray.length; ++i) { removeExecutor(executorArray[i]); } }
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/ExecutorManager.sol#L31
function addExecutors(address[] calldata executorArray) external override onlyOwner { for (uint256 i = 0; i < executorArray.length; ) { addExecutor(executorArray[i]); unchecked { ++i; } } }
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/ExecutorManager.sol#L47
function removeExecutors(address[] calldata executorArray) external override onlyOwner { for (uint256 i = 0; i < executorArray.length; ) { removeExecutor(executorArray[i]); unchecked { ++i; } } }
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L233
for (index = 0; index < nftsStakedLength; ) { if (nftIdsStaked[msgSender][index] == _nftId) { break; } unchecked { ++index; } }
for (uint256 i = 0; i < _addresses.length; ) { isExcludedAddress[_addresses[i]] = _status[i]; emit ExcludedAddressStatusUpdated(_addresses[i], _status[i]); unchecked { ++i; } }
for (uint256 i = 0; i < _tokens.length; ) { setCap(_tokens[i], _totalCaps[i], _perTokenWalletCaps[i]); unchecked { ++i; } }
for (uint256 i = 1; i <= totalSupply; ) { uint256 liquidity = totalLiquidityByLp[_token][lpToken.ownerOf(i)]; if (liquidity > maxLp) { maxLp = liquidity; } unchecked { ++i; } }
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/token/LPToken.sol#L77-L79
function getAllNftIdsByUser(address _owner) public view returns (uint256[] memory) { uint256[] memory nftIds = new uint256[](balanceOf(_owner)); for (uint256 i = 0; i < nftIds.length; ) { nftIds[i] = tokenOfOwnerByIndex(_owner, i); unchecked { ++i; } } return nftIds; }
for (uint256 index = 0; index < tokenConfig.length; ) { depositConfig[toChainId[index]][tokenAddresses[index]].min = tokenConfig[index].min; depositConfig[toChainId[index]][tokenAddresses[index]].max = tokenConfig[index].max; unchecked { ++index; } }
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/ExecutorManager.sol#L31
function addExecutors(address[] calldata executorArray) external override onlyOwner { for (uint256 i = 0; i < executorArray.length; ) { addExecutor(executorArray[i]); unchecked { ++i; } } }
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/ExecutorManager.sol#L47
function removeExecutors(address[] calldata executorArray) external override onlyOwner { for (uint256 i = 0; i < executorArray.length; ) { removeExecutor(executorArray[i]); unchecked { ++i; } } }
Contract | Methods | Before | After | Change |
---|---|---|---|---|
HyphenLiquidityFarming | extractRewards | 135652 | 131459 | -4193 |
TokenManager | setDepositConfig | 74455 | 74391 | -64 |
WhitelistPeriodManager | setCaps | 180517 | 180381 | 136 |
Contract | Before | After | Change |
---|---|---|---|
ExecutorManager | 548814 | 536945 | -11869 |
HyphenLiquidityFarming | 2981386 | 2973842 | -7544 |
LPToken | 3148707 | 3141187 | -7520 |
TokenManager | 1157654 | 1147933 | -9721 |
WhitelistPeriodManager | 2006185 | 1995210 | -10975 |
if (tokenAddress == NATIVE) { require(address(this).balance >= amountToTransfer, "Not Enough Balance"); (bool success, ) = receiver.call{value: amountToTransfer}(""); require(success, "Native Transfer Failed"); } else { require(IERC20Upgradeable(tokenAddress).balanceOf(address(this)) >= amountToTransfer, "Not Enough Balance"); SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(tokenAddress), receiver, amountToTransfer); }
if (_tokenAddress == NATIVE) { require(address(this).balance >= _tokenAmount, "ERR__INSUFFICIENT_BALANCE"); (bool success, ) = receiver.call{value: _tokenAmount}(""); require(success, "ERR__NATIVE_TRANSFER_FAILED"); } else { IERC20Upgradeable baseToken = IERC20Upgradeable(_tokenAddress); require(baseToken.balanceOf(address(this)) >= _tokenAmount, "ERR__INSUFFICIENT_BALANCE"); SafeERC20Upgradeable.safeTransfer(baseToken, receiver, _tokenAmount); }
First, define private function _sendNativeOrERC20Token
as follows, and use this function at the above codebase.
function _sendNativeOrERC20Token( address tokenAddress, address receiver, uint256 amount ) private { if (tokenAddress == NATIVE) { require(address(this).balance >= amount, "Not Enough Balance"); (bool success, ) = receiver.call{value: amount}(""); require(success, "Native Transfer Failed"); } else { require(IERC20Upgradeable(tokenAddress).balanceOf(address(this)) >= amount, "Not Enough Balance"); SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(tokenAddress), receiver, amount); } }
function sendFundsToUser( address tokenAddress, uint256 amount, address payable receiver, bytes memory depositHash, uint256 tokenGasPrice, uint256 fromChainId ) external nonReentrant onlyExecutor tokenChecks(tokenAddress) whenNotPaused { ...Omitted... uint256 amountToTransfer = getAmountToTransfer(initialGas, tokenAddress, amount, tokenGasPrice); liquidityProviders.decreaseCurrentLiquidity(tokenAddress, amountToTransfer); _sendNativeOrERC20Token( tokenAddress, receiver, amountToTransfer ); emit AssetSent(tokenAddress, amount, amountToTransfer, receiver, depositHash, fromChainId); }
function transfer( address _tokenAddress, address receiver, uint256 _tokenAmount ) external whenNotPaused onlyLiquidityProviders nonReentrant { require(receiver != address(0), "Invalid receiver"); _sendNativeOrERC20Token( _tokenAddress, receiver, _tokenAmount ); }
Contract | Methods | Before | After | Change |
---|---|---|---|---|
HyphenLiquidityFarming | extractRewards | 135652 | 131459 | -4193 |
LiquidityPool | depositNative | 97651 | 97433 | -218 |
LiquidityPool | withdrawNativeGasFee | 54143 | 54044 | -99 |
Contract | Before | After | Change |
---|---|---|---|
LiquidityPool | 3841453 | 3752872 | -88581 |
In the following codes, (amount * transferFeePerc) / BASE_DIVISOR
is called multiple times. It can reduce the gas by removing the duplication.
uint256 transferFeePerc = getTransferFee(tokenAddress, amount); uint256 lpFee; if (transferFeePerc > tokenManager.getTokensInfo(tokenAddress).equilibriumFee) { // Here add some fee to incentive pool also lpFee = (amount * tokenManager.getTokensInfo(tokenAddress).equilibriumFee) / BASE_DIVISOR; incentivePool[tokenAddress] = (incentivePool[tokenAddress] + (amount * (transferFeePerc - tokenManager.getTokensInfo(tokenAddress).equilibriumFee))) / BASE_DIVISOR; } else { lpFee = (amount * transferFeePerc) / BASE_DIVISOR; } uint256 transferFeeAmount = (amount * transferFeePerc) / BASE_DIVISOR;
Here are two changes which can be added:
transferFeeAmount
variable outside of if-else blocktransferFeeAmount
variable by refactoring calculation a bitlpFee
variable in else block can directly use transferFeeAmount
variableuint256 transferFeePerc = getTransferFee(tokenAddress, amount); uint256 lpFee; uint256 transferFeeAmount = (amount * transferFeePerc) / BASE_DIVISOR; if (transferFeePerc > tokenManager.getTokensInfo(tokenAddress).equilibriumFee) { // Here add some fee to incentive pool also lpFee = (amount * tokenManager.getTokensInfo(tokenAddress).equilibriumFee) / BASE_DIVISOR; incentivePool[tokenAddress] = incentivePool[tokenAddress] + transferFeeAmount - lpFee; } else { lpFee = transferFeeAmount; }
Contract | Methods | Before | After | Change |
---|---|---|---|---|
LiquidityPool | sendFundsToUser | 245626 | 242482 | -3144 |
Contract | Before | After | Change |
---|---|---|---|
LiquidityPool | 3841453 | 3801684 | -39769 |
function getTransferFee(address tokenAddress, uint256 amount) public view returns (uint256 fee) { uint256 currentLiquidity = getCurrentLiquidity(tokenAddress); uint256 providedLiquidity = liquidityProviders.getSuppliedLiquidityByToken(tokenAddress); uint256 resultingLiquidity = currentLiquidity - amount;
Just call getCurrentLiquidity(tokenAddress)
when defining resultingLiquidity
variable
function getTransferFee(address tokenAddress, uint256 amount) public view returns (uint256 fee) { uint256 providedLiquidity = liquidityProviders.getSuppliedLiquidityByToken(tokenAddress); uint256 resultingLiquidity = getCurrentLiquidity(tokenAddress) - amount;
Contract | Methods | Before | After | Change |
---|---|---|---|---|
LiquidityPool | sendFundsToUser | 245626 | 245619 | -7 |
Contract | Before | After | Change |
---|---|---|---|
LiquidityPool | 3841453 | 3840541 | -912 |
tokenManager.getTokensInfo(tokenAddress)
multiple timeIn these codes, tokenManager.getTokensInfo(tokenAddress)
is called multiple times. Calling function multiple time would increase the gas usage.
if (transferFeePerc > tokenManager.getTokensInfo(tokenAddress).equilibriumFee) { // Here add some fee to incentive pool also lpFee = (amount * tokenManager.getTokensInfo(tokenAddress).equilibriumFee) / BASE_DIVISOR; incentivePool[tokenAddress] = (incentivePool[tokenAddress] + (amount * (transferFeePerc - tokenManager.getTokensInfo(tokenAddress).equilibriumFee))) / BASE_DIVISOR; } else { lpFee = (amount * transferFeePerc) / BASE_DIVISOR; } uint256 transferFeeAmount = (amount * transferFeePerc) / BASE_DIVISOR; liquidityProviders.addLPFee(tokenAddress, lpFee); uint256 totalGasUsed = initialGas - gasleft(); totalGasUsed = totalGasUsed + tokenManager.getTokensInfo(tokenAddress).transferOverhead;
Here are example changes. Basically, it defines ITokenManager.TokenInfo memory tokenInfo = tokenManager.getTokensInfo(tokenAddress)
, and use tokenInfo
variable instead of calling tokenManager.getTokensInfo(tokenAddress)
multiple times.
ITokenManager.TokenInfo memory tokenInfo = tokenManager.getTokensInfo(tokenAddress); if (transferFeePerc > tokenInfo.equilibriumFee) { // Here add some fee to incentive pool also lpFee = (amount * tokenInfo.equilibriumFee) / BASE_DIVISOR; incentivePool[tokenAddress] = (incentivePool[tokenAddress] + (amount * (transferFeePerc - tokenInfo.equilibriumFee))) / BASE_DIVISOR; } else { lpFee = (amount * transferFeePerc) / BASE_DIVISOR; } uint256 transferFeeAmount = (amount * transferFeePerc) / BASE_DIVISOR; liquidityProviders.addLPFee(tokenAddress, lpFee); uint256 totalGasUsed = initialGas - gasleft(); totalGasUsed = totalGasUsed + tokenInfo.transferOverhead; totalGasUsed = totalGasUsed + baseGas;
Contract | Methods | Before | After | Change |
---|---|---|---|---|
LiquidityPool | sendFundsToUser | 245626 | 236716 | -8910 |
Contract | Before | After | Change |
---|---|---|---|
LiquidityPool | 3841453 | 3760632 | -80821 |
function withdrawErc20GasFee(address tokenAddress) external onlyExecutor whenNotPaused nonReentrant { require(tokenAddress != NATIVE, "Can't withdraw native token fee"); // uint256 gasFeeAccumulated = gasFeeAccumulatedByToken[tokenAddress]; uint256 _gasFeeAccumulated = gasFeeAccumulated[tokenAddress][_msgSender()]; require(_gasFeeAccumulated != 0, "Gas Fee earned is 0"); gasFeeAccumulatedByToken[tokenAddress] = gasFeeAccumulatedByToken[tokenAddress] - _gasFeeAccumulated; gasFeeAccumulated[tokenAddress][_msgSender()] = 0; SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(tokenAddress), _msgSender(), _gasFeeAccumulated); emit GasFeeWithdraw(tokenAddress, _msgSender(), _gasFeeAccumulated); } function withdrawNativeGasFee() external onlyExecutor whenNotPaused nonReentrant { uint256 _gasFeeAccumulated = gasFeeAccumulated[NATIVE][_msgSender()]; require(_gasFeeAccumulated != 0, "Gas Fee earned is 0"); gasFeeAccumulatedByToken[NATIVE] = gasFeeAccumulatedByToken[NATIVE] - _gasFeeAccumulated; gasFeeAccumulated[NATIVE][_msgSender()] = 0; (bool success, ) = payable(_msgSender()).call{value: _gasFeeAccumulated}(""); require(success, "Native Transfer Failed"); emit GasFeeWithdraw(address(this), _msgSender(), _gasFeeAccumulated); }
Following codes are duplicated ones seen in withdrawErc20GasFee and withdrawNativeGasFee.
require(_gasFeeAccumulated != 0, "Gas Fee earned is 0"); gasFeeAccumulatedByToken[tokenAddress] = gasFeeAccumulatedByToken[tokenAddress] - _gasFeeAccumulated; gasFeeAccumulated[tokenAddress][_msgSender()] = 0;
The difference is whether it uses tokenAddress
or NATIVE
variable.
Here are example changes. Basically it defines _withdrawCommon
function.
function withdrawErc20GasFee(address tokenAddress) external onlyExecutor whenNotPaused nonReentrant { require(tokenAddress != NATIVE, "Can't withdraw native token fee"); // uint256 gasFeeAccumulated = gasFeeAccumulatedByToken[tokenAddress]; uint256 _gasFeeAccumulated = gasFeeAccumulated[tokenAddress][_msgSender()]; _withdrawCommon(tokenAddress, _gasFeeAccumulated); SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(tokenAddress), _msgSender(), _gasFeeAccumulated); emit GasFeeWithdraw(tokenAddress, _msgSender(), _gasFeeAccumulated); } function withdrawNativeGasFee() external onlyExecutor whenNotPaused nonReentrant { uint256 _gasFeeAccumulated = gasFeeAccumulated[NATIVE][_msgSender()]; _withdrawCommon(NATIVE, _gasFeeAccumulated); (bool success, ) = payable(_msgSender()).call{value: _gasFeeAccumulated}(""); require(success, "Native Transfer Failed"); emit GasFeeWithdraw(address(this), _msgSender(), _gasFeeAccumulated); } function _withdrawCommon(address tokenOrNativeAddress, uint256 gasFeeAccumulated_) private { require(gasFeeAccumulated_ != 0, "Gas Fee earned is 0"); gasFeeAccumulatedByToken[tokenOrNativeAddress] = gasFeeAccumulatedByToken[tokenOrNativeAddress] - gasFeeAccumulated_; gasFeeAccumulated[tokenOrNativeAddress][_msgSender()] = 0; }
Contract | Methods | Before | After | Change |
---|---|---|---|---|
LiquidityPool | depositNative | 97651 | 97592 | -59 |
LiquidityPool | sendFundsToUser | 245626 | 245593 | -33 |
LiquidityPool | withdrawNativeGasFee | 54143 | 54265 | +122 |
In LiquidityPool.sol, depositNative and sendFundsToUser function can reduce the gas, but withdrawNativeGasFee sees the gas increase.
Contract | Before | After | Change |
---|---|---|---|
LiquidityPool | 3841453 | 3809973 | -31480 |
There is an opportunity to use unchecked for providedLiquidity - currentLiquidity
. It is obvious that providedLiquidity - currentLiquidity
will never be underflown since the if checks currentLiquidity < providedLiquidity
.
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityPool.sol#L178-L187
if (currentLiquidity < providedLiquidity) { uint256 liquidityDifference = providedLiquidity - currentLiquidity; if (amount >= liquidityDifference) { rewardAmount = incentivePool[tokenAddress]; } else { // Multiply by 10000000000 to avoid 0 reward amount for small amount and liquidity difference rewardAmount = (amount * incentivePool[tokenAddress] * 10000000000) / liquidityDifference; rewardAmount = rewardAmount / 10000000000; } }
Wrap by unchecked for providedLiquidity - currentLiquidity
.
if (currentLiquidity < providedLiquidity) { uint256 liquidityDifference; unchecked { liquidityDifference = providedLiquidity - currentLiquidity; } if (amount >= liquidityDifference) { rewardAmount = incentivePool[tokenAddress]; } else { // Multiply by 10000000000 to avoid 0 reward amount for small amount and liquidity difference rewardAmount = (amount * incentivePool[tokenAddress] * 10000000000) / liquidityDifference; rewardAmount = rewardAmount / 10000000000; } }
Contract | Methods | Before | After | Change |
---|---|---|---|---|
LiquidityPool | depositErc20 | 142899 | 142875 | -24 |
LiquidityPool | depositNative | 97651 | 97598 | -53 |
Contract | Before | After | Change |
---|---|---|---|
LiquidityPool | 3841453 | 3839045 | -2408 |
There are three gas improvement opportunities.
accumulator
variablerewardRateLog[_baseToken].length - 1
can be wrapped by unchecked--i
can be wrapped by unchecked
https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L266-L284uint256 accumulator = 0; uint256 lastUpdatedTime = poolInfo[_baseToken].lastRewardTime; uint256 counter = block.timestamp; uint256 i = rewardRateLog[_baseToken].length - 1; while (true) { if (lastUpdatedTime >= counter) { break; } unchecked { accumulator += rewardRateLog[_baseToken][i].rewardsPerSecond * (counter - max(lastUpdatedTime, rewardRateLog[_baseToken][i].timestamp)); } counter = rewardRateLog[_baseToken][i].timestamp; if (i == 0) { break; } --i; }
uint256 accumulator; uint256 lastUpdatedTime = poolInfo[_baseToken].lastRewardTime; uint256 counter = block.timestamp; uint256 i; unchecked { i = rewardRateLog[_baseToken].length - 1; } while (true) { if (lastUpdatedTime >= counter) { break; } unchecked { accumulator += rewardRateLog[_baseToken][i].rewardsPerSecond * (counter - max(lastUpdatedTime, rewardRateLog[_baseToken][i].timestamp)); } counter = rewardRateLog[_baseToken][i].timestamp; if (i == 0) { break; } unchecked { --i; } }
Contract | Methods | Before | After | Change |
---|---|---|---|---|
HyphenLiquidityFarming | extractRewards | 148287 | 135526 | -12761 |
HyphenLiquidityFarming | withdraw | 148287 | 135526 | -17490 |
Contract | Before | After | Change |
---|---|---|---|
HyphenLiquidityFarming | 2981386 | 2972318 | -9068 |
#0 - ankurdubey521
2022-04-01T10:10:39Z
Thanks a lot for including the data related to the savings in gas