Platform: Code4rena
Start Date: 03/07/2023
Pot Size: $40,000 USDC
Total HM: 14
Participants: 74
Period: 7 days
Judge: alcueca
Total Solo HM: 9
Id: 259
League: ETH
Rank: 28/74
Findings: 2
Award: $64.54
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xprinc
Also found by: 0x11singh99, 0xAnah, 0xWaitress, 0xkazim, 2997ms, 33audits, 404Notfound, 8olidity, CRIMSON-RAT-REACH, CyberPunks, DanielWang888, Deekshith99, Eeyore, Eurovickk, Inspecktor, JGcarv, John, Jorgect, Kaysoft, LosPollosHermanos, MohammedRizwan, Qeew, QiuhaoLi, Rolezn, TheSavageTeddy, Topmark, Trust, Udsen, a3yip6, alexzoid, bigtone, codegpt, erebus, fatherOfBlocks, ginlee, glcanvas, hunter_w3b, josephdara, kaveyjoe, kutugu, mahdirostami, max10afternoon, oakcobalt, peanuts, pfapostol, ptsanev, qpzm, radev_sw, ravikiranweb3, sces60107, seth_lawson, te_aut, twcctop, zhaojie, ziyou-
6.0655 USDC - $6.07
Issue | Contexts | |
---|---|---|
LOW‑1 | Consider the case where lpTokenSupply is 0 | 2 |
LOW‑2 | Draft Import Dependencies | 1 |
LOW‑3 | Function can risk gas exhaustion on large receipt calls due to multiple mandatory loops | 1 |
LOW‑4 | Missing Contract-existence Checks Before Low-level Calls | 1 |
LOW‑5 | safeTransfer function does not check for contract existence | 1 |
LOW‑6 | Solidity version 0.8.20 may not work on other chains due to PUSH0 | 0 |
LOW‑7 | Consider case where the variable will not be set and will default to zero | 1 |
Total: 7 contexts over 7 issues
Issue | Contexts | |
---|---|---|
NC‑1 | Consider adding a deny-list | 1 |
NC‑2 | No need to initialize uints to zero | 1 |
NC‑3 | Use SMTChecker | 1 |
Total: 3 contexts over 3 issues
lpTokenSupply
is 0Consider the case where lpTokenSupply
is 0. When lpTokenSupply
is 0, it should return 0 directly, because there will be an error of dividing by 0.
This would cause the affected functions to revert and as a result can lead to potential loss.
File: ProportionalLPToken2.sol 22: underlyingAmounts[0] = lpTokenAmount * reserves[0] / lpTokenSupply; 23: underlyingAmounts[1] = lpTokenAmount * reserves[1] / lpTokenSupply;
https://github.com/code-423n4/2023-07-basin/tree/main/src/functions/ProportionalLPToken2.sol#L22-L23
Add check for zero value and return 0.
if ( lpTokenSupply == 0) return 0;
Contracts are importing draft dependencies. These imported contracts are still a draft and are not considered ready for mainnet use and have not received adequate security auditing or are liable to change with future development.
File: Well.sol 6: import {ERC20Upgradeable, ERC20PermitUpgradeable} from "ozu/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol";
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L6
Stop using draft imported contracts and use their release version if it exists.
The function contains loops over arrays that the user cannot influence. In any call for the function, users spend gas to iterate over the array. There are loops in the following functions that iterate all array values. Which could risk gas exhaustion on large array calls.
This risk is small, but could be lessened somewhat by allowing separate calls for small loops. Consider allowing partial calls via array arguments, or detecting expensive call bundles and only partially iterating over them. Since the logic already filters out calls, this would make the later loops smaller.
File: MultiFlowPump.sol 285: function _readCumulativeReserves(address well) internal view returns (bytes16[] memory cumulativeReserves) { bytes32 slot = _getSlotForAddress(well); uint256[] memory reserves = IWell(well).getReserves(); (uint8 numberOfReserves, uint40 lastTimestamp, bytes16[] memory lastReserves) = slot.readLastReserves(); if (numberOfReserves == 0) { revert NotInitialized(); } uint256 offset = _getSlotsOffset(numberOfReserves) << 1; assembly { slot := add(slot, offset) } cumulativeReserves = slot.readBytes16(numberOfReserves); uint256 deltaTimestamp = _getDeltaTimestamp(lastTimestamp); bytes16 deltaTimestampBytes = deltaTimestamp.fromUInt(); bytes16 blocksPassed = (deltaTimestamp / BLOCK_TIME).fromUInt(); for (uint256 i; i < cumulativeReserves.length; ++i) { lastReserves[i] = _capReserve(lastReserves[i], reserves[i].fromUIntToLog2(), blocksPassed); cumulativeReserves[i] = cumulativeReserves[i].add(lastReserves[i].mul(deltaTimestampBytes)); } }
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L285
</details>Low-level calls return success if there is no code present at the specified address.
File: Aquifer.sol 55: (bool success, bytes memory returnData) = well.call(initFunctionCall);
https://github.com/code-423n4/2023-07-basin/tree/main/src/Aquifer.sol#L55
In addition to the zero-address checks, add a check to verify that <address>.code.length > 0
safeTransfer
function does not check for contract existenceAccording to the implementation of the of the library's safeTransfer function, the contract existences are not checked. It is possible that a token becomes non-existent in the future; for instance, if some bugs are found for the output token, it is possible that the output token will be destroyed through calling its selfdestruct function after migrating its data to another contract for fixing these bugs. When this happens, such output token becomes non-existent but calling the swap function to swap for it does not revert. As a result, the user can lose tokens
File: Well.sol 774: function _safeTransferFromFeeOnTransfer( IERC20 token, address from, uint256 amount ) internal returns (uint256 amountTransferred) { uint256 balanceBefore = token.balanceOf(address(this)); token.safeTransferFrom(from, address(this), amount); amountTransferred = token.balanceOf(address(this)) - balanceBefore; }
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L774
In the library's safeTransfer
function, the existence of the contract for token should be checked before performing the low-level call. If such contract does not exist, calling this function should revert.
PUSH0
The compiler for Solidity 0.8.20 switches the default target EVM version to Shanghai, which includes the new PUSH0
op code. This op code may not yet be implemented on all L2s, so deployment on these chains will fail. To work around this issue, use an earlier EVM version. While the project itself may or may not compile with 0.8.20, other projects with which it integrates, or which extend this project may, and those projects will have problems deploying these contracts/libraries.
File: Aquifer.sol pragma solidity ^0.8.17;
https://github.com/code-423n4/2023-07-basin/tree/main/src/Aquifer.sol#L3
File: Well.sol pragma solidity ^0.8.17;
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L3
File: ConstantProduct2.sol pragma solidity ^0.8.17;
https://github.com/code-423n4/2023-07-basin/tree/main/src/functions/ConstantProduct2.sol#L3
File: ProportionalLPToken2.sol pragma solidity ^0.8.17;
https://github.com/code-423n4/2023-07-basin/tree/main/src/functions/ProportionalLPToken2.sol#L3
File: LibBytes.sol pragma solidity ^0.8.17;
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes.sol#L3
File: LibBytes16.sol pragma solidity ^0.8.17;
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes16.sol#L3
File: LibContractInfo.sol pragma solidity ^0.8.17;
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibContractInfo.sol#L3
File: LibLastReserveBytes.sol pragma solidity ^0.8.17;
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibLastReserveBytes.sol#L3
File: LibWellConstructor.sol pragma solidity ^0.8.17;
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibWellConstructor.sol#L4
File: MultiFlowPump.sol pragma solidity ^0.8.17;
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L3
</details>As per the _init
function in the MultiFlowPump.sol
contract will just continue its logic even though reserves
was not set (0 value) as there is no revert case when reserves
is equal to 0
File: MultiFlowPump.sol 146: function _init(bytes32 slot, uint40 lastTimestamp, uint256[] memory reserves) internal { uint256 numberOfReserves = reserves.length; bytes16[] memory byteReserves = new bytes16[](numberOfReserves); // Skip {_capReserve} since we have no prior reference for (uint256 i; i < numberOfReserves; ++i) { if (reserves[i] == 0) return; byteReserves[i] = reserves[i].fromUIntToLog2(); } // Write: Last Timestamp & Last Reserves slot.storeLastReserves(lastTimestamp, byteReserves); // Write: EMA Reserves // Start at the slot after `byteReserves` uint256 numSlots = _getSlotsOffset(byteReserves.length); assembly { slot := add(slot, numSlots) } slot.storeBytes16(byteReserves); // EMA Reserves }
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L146
Doing so will significantly increase centralization, but will help to prevent hackers from using stolen tokens
File: Well.sol 22: contract Well is ERC20PermitUpgradeable, IWell, IWellErrors, ReentrancyGuardUpgradeable, ClonePlus
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L22
There is no need to initialize uint
variables to zero as their default value is 0
File: Well.sol 77: uint256 constant LOC_AQUIFER_ADDR = 0;
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L77
The highest tier of smart contract behavior assurance is formal mathematical verification. All assertions that are made are guaranteed to be true across all inputs → The quality of your asserts is the quality of your verification
https://twitter.com/0xOwenThurm/status/1614359896350425088?t=dbG9gHFigBX85Rv29lOjIQ&s=19
#0 - c4-pre-sort
2023-07-13T14:56:48Z
141345 marked the issue as low quality report
#1 - c4-judge
2023-08-04T21:14:36Z
alcueca marked the issue as grade-b
🌟 Selected for report: SM3_SS
Also found by: 0x11singh99, 0xAnah, 0xSmartContract, 0xn006e7, 0xprinc, DavidGiladi, ElCid, JCN, K42, MIQUINHO, Raihan, Rolezn, SAAJ, SY_S, Strausses, TheSavageTeddy, bigtone, erebus, hunter_w3b, josephdara, lsaudit, mahdirostami, oakcobalt, peanuts, pfapostol, seth_lawson
58.4732 USDC - $58.47
Issue | Contexts | Estimated Gas Saved | |
---|---|---|---|
GAS‑1 | Consider activating via-ir for deploying | 1 | 250 |
GAS‑2 | Use assembly to emit events | 8 | 304 |
GAS‑3 | Counting down in for statements is more gas efficient | 33 | 8481 |
GAS‑4 | Empty Blocks Should Be Removed Or Emit Something | 3 | 33 |
GAS‑5 | Using delete statement can save gas | 1 | 8 |
GAS‑6 | Use assembly to write address storage values | 1 | 74 |
GAS‑7 | Multiple accesses of a mapping/array should use a local variable cache | 2 | 160 |
GAS‑8 | Using XOR (^) and AND (&) bitwise equivalents | 26 | 338 |
Total: 75 contexts over 8 issues
via-ir
for deployingThe IR-based code generator was introduced with an aim to not only allow code generation to be more transparent and auditable but also to enable more powerful optimization passes that span across functions.
You can enable it on the command line using --via-ir
or with the option {"viaIR": true}
.
This will take longer to compile, but you can just simple test it before deploying and if you got a better benchmark then you can add --via-ir to your deploy command
More on: https://docs.soliditylang.org/en/v0.8.17/ir-breaking-changes.html
We can use assembly to emit events efficiently by utilizing scratch space
and the free memory pointer
. This will allow us to potentially avoid memory expansion costs.
Note: In order to do this optimization safely, we will need to cache and restore the free memory pointer.
For example, for a generic emit
event for eventSentAmountExample
:
// uint256 id, uint256 value, uint256 amount emit eventSentAmountExample(id, value, amount);
We can use the following assembly emit events:
assembly { let memptr := mload(0x40) mstore(0x00, calldataload(0x44)) mstore(0x20, calldataload(0xa4)) mstore(0x40, amount) log1( 0x00, 0x60, // keccak256("eventSentAmountExample(uint256,uint256,uint256)") 0xa622cf392588fbf2cd020ff96b2f4ebd9c76d7a4bc7f3e6b2f18012312e76bc3 ) mstore(0x40, memptr) }
File: Well.sol 238: emit Swap(fromToken, toToken, amountIn, amountOut, recipient);
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L238
File: Well.sol 305: emit Swap(fromToken, toToken, amountIn, amountOut, recipient);
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L305
File: Well.sol 373: emit Shift(reserves, tokenOut, amountOut, recipient);
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L373
File: Well.sol 443: emit AddLiquidity(tokenAmountsIn, lpAmountOut, recipient);
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L443
File: Well.sol 482: emit RemoveLiquidity(lpAmountIn, tokenAmountsOut, recipient);
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L482
File: Well.sol 516: emit RemoveLiquidityOneToken(lpAmountIn, tokenOut, tokenAmountOut, recipient);
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L516
File: Well.sol 569: emit RemoveLiquidity(lpAmountIn, tokenAmountsOut, recipient);
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L569
File: Well.sol 597: emit Sync(reserves);
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L597
</details>for
statements is more gas efficientCounting down is more gas efficient than counting up because neither we are making zero variable to non-zero variable and also we will get gas refund in the last transaction when making non-zero to zero variable.
File: Well.sol 36: for (uint256 i; i < _tokens.length - 1; ++i) { 37: for (uint256 j = i + 1; j < _tokens.length; ++j) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L36-L37
File: Well.sol 101: for (uint256 i; i < _pumps.length; i++) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L101
File: Well.sol 363: for (uint256 i; i < _tokens.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L363
File: Well.sol 382: for (uint256 i; i < _tokens.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L382
File: Well.sol 423: for (uint256 i; i < _tokens.length; ++i) { 423: for (uint256 i; i < _tokens.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L423
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L423
File: Well.sol 452: for (uint256 i; i < _tokens.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L452
File: Well.sol 473: for (uint256 i; i < _tokens.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L473
File: Well.sol 557: for (uint256 i; i < _tokens.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L557
File: Well.sol 579: for (uint256 i; i < _tokens.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L579
File: Well.sol 593: for (uint256 i; i < _tokens.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L593
File: Well.sol 607: for (uint256 i; i < _tokens.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L607
File: Well.sol 633: for (uint256 i; i < reserves.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L633
File: Well.sol 662: for (uint256 i; i < _pumps.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L662
File: Well.sol 738: for (uint256 k; k < _tokens.length; ++k) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L738
File: Well.sol 760: for (j; j < _tokens.length; ++j) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L760
File: LibBytes.sol 48: for (uint256 i; i < maxI; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes.sol#L48
File: LibBytes.sol 92: for (uint256 i = 1; i <= n; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes.sol#L92
File: LibBytes16.sol 28: for (uint256 i; i < maxI; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes16.sol#L28
File: LibBytes16.sol 69: for (uint256 i = 1; i <= n; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes16.sol#L69
File: LibLastReserveBytes.sol 41: for (uint256 i = 1; i < maxI; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibLastReserveBytes.sol#L41
File: LibLastReserveBytes.sol 93: for (uint256 i = 3; i <= n; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibLastReserveBytes.sol#L93
File: LibWellConstructor.sol 43: for (uint256 i; i < _pumps.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibWellConstructor.sol#L43
File: LibWellConstructor.sol 73: for (uint256 i = 1; i < _tokens.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibWellConstructor.sol#L73
File: MultiFlowPump.sol 84: for (uint256 i; i < numberOfReserves; ++i) { 84: for (uint256 i; i < numberOfReserves; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L84
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L84
File: MultiFlowPump.sol 152: for (uint256 i; i < numberOfReserves; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L152
File: MultiFlowPump.sol 178: for (uint256 i; i < numberOfReserves; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L178
File: MultiFlowPump.sol 234: for (uint256 i; i < numberOfReserves; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L234
File: MultiFlowPump.sol 255: for (uint256 i; i < numberOfReserves; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L255
File: MultiFlowPump.sol 301: for (uint256 i; i < cumulativeReserves.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L301
File: MultiFlowPump.sol 322: for (uint256 i; i < byteCumulativeReserves.length; ++i) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L322
</details>contract GasTest is DSTest { Contract0 c0; Contract1 c1; function setUp() public { c0 = new Contract0(); c1 = new Contract1(); } function testGas() public { c0.AddNum(); c1.AddNum(); } } contract Contract0 { uint256 num = 3; function AddNum() public { uint256 _num = num; for(uint i=0;i<=9;i++){ _num = _num +1; } num = _num; } } contract Contract1 { uint256 num = 3; function AddNum() public { uint256 _num = num; for(uint i=9;i>=0;i--){ _num = _num +1; } num = _num; } }
Contract0 contract | |||||
---|---|---|---|---|---|
Deployment Cost | Deployment Size | ||||
77011 | 311 | ||||
Function Name | min | avg | median | max | # calls |
AddNum | 7040 | 7040 | 7040 | 7040 | 1 |
Contract1 contract | |||||
---|---|---|---|---|---|
Deployment Cost | Deployment Size | ||||
73811 | 295 | ||||
Function Name | min | avg | median | max | # calls |
AddNum | 3819 | 3819 | 3819 | 3819 | 1 |
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{...}})
File: Well.sol 114: function wellData() public pure returns (bytes memory) {}
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L114
File: Well.sol 656: try IPump(_pump.target).update(reserves, _pump.data) {}
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L656
File: Well.sol 664: try IPump(_pumps[i].target).update(reserves, _pumps[i].data) {}
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L664
delete
statement can save gasFile: Well.sol 77: uint256 constant LOC_AQUIFER_ADDR = 0;
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L77
assembly
to write address storage valuesFile: LibBytes.sol 24: _bytes = ZERO_BYTES;
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes.sol#L24
Caching a mapping's value in a local storage or calldata variable when the value is accessed multiple times saves ~42 gas per access due to not having to perform the same offset calculation every time. Help the Optimizer by saving a storage variable's reference instead of repeatedly fetching it
To help the optimizer,declare a storage type variable and use it instead of repeatedly fetching the reference in a map or an array. As an example, instead of repeatedly calling someMap[someIndex]
, save its reference like this: SomeStruct storage someStruct = someMap[someIndex]
and use it.
File: LibWellConstructor.sol 74: name = string.concat(name, ":", LibContractInfo.getSymbol(address(_tokens[i]))); 75: symbol = string.concat(symbol, LibContractInfo.getSymbol(address(_tokens[i])));
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibWellConstructor.sol#L74-L75
</details>Given 4 variables a, b, c and d represented as such:
0 0 0 0 0 1 1 0 <- a 0 1 1 0 0 1 1 0 <- b 0 0 0 0 0 0 0 0 <- c 1 1 1 1 1 1 1 1 <- d
To have a == b means that every 0 and 1 match on both variables. Meaning that a XOR (operator ^) would evaluate to 0 ((a ^ b) == 0), as it excludes by definition any equalities.Now, if a != b, this means that there’s at least somewhere a 1 and a 0 not matching between a and b, making (a ^ b) != 0.Both formulas are logically equivalent and using the XOR bitwise operator costs actually the same amount of gas.However, it is much cheaper to use the bitwise OR operator (|) than comparing the truthy or falsy values.These are logically equivalent too, as the OR bitwise operator (|) would result in a 1 somewhere if any value is not 0 between the XOR (^) statements, meaning if any XOR (^) statement verifies that its arguments are different.
File: Well.sol 739: if (iToken == _tokens[k]) { 742: } else if (jToken == _tokens[k]) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L739
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L742
File: Well.sol 761: if (jToken == _tokens[j]) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/Well.sol#L761
File: ConstantProduct2.sol 66: reserve = LibMath.roundUpDiv(reserve, reserves[j == 1 ? 0 : 1] * EXP_PRECISION);
https://github.com/code-423n4/2023-07-basin/tree/main/src/functions/ConstantProduct2.sol#L66
File: ConstantProduct2.sol 85: uint256 i = j == 1 ? 0 : 1;
https://github.com/code-423n4/2023-07-basin/tree/main/src/functions/ConstantProduct2.sol#L85
File: ConstantProduct2.sol 98: uint256 i = j == 1 ? 0 : 1;
https://github.com/code-423n4/2023-07-basin/tree/main/src/functions/ConstantProduct2.sol#L98
File: LibBytes.sol 39: if (reserves.length == 2) { 62: if (reserves.length & 1 == 1) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes.sol#L39
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes.sol#L62
File: LibBytes.sol 83: if (n == 2) { 98: if (i & 1 == 1) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes.sol#L83
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes.sol#L98
File: LibBytes16.sol 21: if (reserves.length == 2) { 40: if (reserves.length & 1 == 1) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes16.sol#L21
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes16.sol#L40
File: LibBytes16.sol 60: if (n == 2) { 75: if (i & 1 == 1) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes16.sol#L60
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibBytes16.sol#L75
File: LibLastReserveBytes.sol 22: if (n == 1) { 53: if (reserves.length & 1 == 1) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibLastReserveBytes.sol#L22
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibLastReserveBytes.sol#L53
File: LibLastReserveBytes.sol 80: if (n == 0) return (n, lastTimestamp, reserves); 86: if (n == 1) return (n, lastTimestamp, reserves); 99: if (i & 1 == 1) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibLastReserveBytes.sol#L80
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibLastReserveBytes.sol#L86
https://github.com/code-423n4/2023-07-basin/tree/main/src/libraries/LibLastReserveBytes.sol#L99
File: MultiFlowPump.sol 83: if (pumpState.lastTimestamp == 0) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L83
File: MultiFlowPump.sol 174: if (numberOfReserves == 0) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L174
File: MultiFlowPump.sol 225: if (numberOfReserves == 0) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L225
File: MultiFlowPump.sol 243: if (numberOfReserves == 0) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L243
File: MultiFlowPump.sol 270: if (numberOfReserves == 0) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L270
File: MultiFlowPump.sol 289: if (numberOfReserves == 0) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L289
File: MultiFlowPump.sol 319: if (deltaTimestamp == bytes16(0)) {
https://github.com/code-423n4/2023-07-basin/tree/main/src/pumps/MultiFlowPump.sol#L319
</details>contract GasTest is DSTest { Contract0 c0; Contract1 c1; function setUp() public { c0 = new Contract0(); c1 = new Contract1(); } function testGas() public { c0.not_optimized(1,2); c1.optimized(1,2); } } contract Contract0 { function not_optimized(uint8 a,uint8 b) public returns(bool){ return ((a==1) || (b==1)); } } contract Contract1 { function optimized(uint8 a,uint8 b) public returns(bool){ return ((a ^ 1) & (b ^ 1)) == 0; } }
Contract0 contract | |||||
---|---|---|---|---|---|
Deployment Cost | Deployment Size | ||||
46099 | 261 | ||||
Function Name | min | avg | median | max | # calls |
not_optimized | 456 | 456 | 456 | 456 | 1 |
Contract1 contract | |||||
---|---|---|---|---|---|
Deployment Cost | Deployment Size | ||||
42493 | 243 | ||||
Function Name | min | avg | median | max | # calls |
optimized | 430 | 430 | 430 | 430 | 1 |
#0 - c4-pre-sort
2023-07-12T09:41:13Z
141345 marked the issue as high quality report
#1 - c4-sponsor
2023-07-17T20:12:18Z
publiuss marked the issue as sponsor confirmed
#2 - c4-sponsor
2023-08-03T22:43:39Z
publiuss marked the issue as sponsor acknowledged
#3 - c4-judge
2023-08-05T11:07:35Z
alcueca marked the issue as grade-b
#4 - c4-judge
2023-08-05T11:07:51Z
alcueca marked the issue as grade-a