Platform: Code4rena
Start Date: 23/05/2022
Pot Size: $50,000 USDC
Total HM: 44
Participants: 99
Period: 5 days
Judge: hickuphh3
Total Solo HM: 11
Id: 129
League: ETH
Rank: 85/99
Findings: 1
Award: $50.15
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x4non, 0xDjango, 0xNazgul, 0xf15ers, 0xkatana, Chom, DavidGialdi, Dravee, ElKu, FSchmoede, Fitraldys, Funen, GimelSec, JC, Kaiziron, MaratCerby, Metatron, MiloTruck, Picodes, Randyyy, RoiEvenHaim, SmartSek, Tomio, UnusualTurtle, WatchPug, Waze, _Adam, antonttc, asutorufos, berndartmueller, blackscale, blockdev, c3phas, catchup, csanuragjain, defsec, delfin454000, ellahi, fatherOfBlocks, gzeon, hansfriese, ilan, joestakey, minhquanym, oyc_109, pauliax, pedroais, reassor, rfa, rotcivegaf, sach1r0, samruna, sashik_eth, simon135, z3s
50.1514 USDC - $50.15
Using a prefix increment (++i) instead of a postfix increment (i++) saves gas for each loop cycle and so can have a big gas impact when the loop executes on a large number of elements.
There are many examples of this in for loops https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L635 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L733 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L206 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L311 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L427 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L480 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L582 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L85 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L169 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L227 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L436 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1165 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1197
Use prefix not postfix to increment in a loop
Solidity does not recognize null as a value, so uint variables are initialized to zero. Setting a uint variable to zero is redundant and can waste gas.
There were many places where an int is initialized to zero https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L635 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L311 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L427 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L480 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L582 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L82 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L83 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L85 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L168 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L169 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L226 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L227 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L990
Remove the redundant zero initialization
uint256 i;
instead of uint256 i = 0;
Combining require statement conditions with && logic uses unnecessary gas. It is better to split up each part of the logical statement into a separate require statements
One example is
require(_bathAssetAddress != address(0) && _bathQuoteAddress != address(0), "tokenToBathToken error");
This can be improved to
require(_bathAssetAddress != address(0)); require(_bathQuoteAddress != address(0));
Several places had require statements with many logical "and"s. Instead, split into two to save gas https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L741 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L122 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L333 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L334 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L347 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L420 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L421 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L472 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L473 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L474 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L507 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L716 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L717 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1178
Use separate require statements instead of concatenating with &&
Caching the array length outside a loop saves reading it on each iteration, as long as the array's length is not changed during the loop. This saves gas.
This was found in many places https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L635 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L311 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L582 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L169 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L227
Cache the array length before the for loop
Using > 0
uses slightly more gas than using != 0
. Use != 0
when comparing uint variables to zero, which cannot hold values below zero
Locations where this was found include https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/peripheral_contracts/BathBuddy.sol#L102 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L634 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L232 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L252 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L333 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L334 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L515 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L523 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L597 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L611 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathHouse.sol#L111 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathHouse.sol#L281 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L354 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/proxy/UpgradeableProxy.sol#L30 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/proxy/Address.sol#L36 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/proxy/Address.sol#L240 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L233 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L400 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L402 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L837 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L876 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L918 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L942 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L985 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1002 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1063 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1099 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1100 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1175 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1217
Replace > 0
with != 0
to save gas
The value 2**256 - 1
is used for some variables but using type(uint256).max
uses less gas than this constant value.
Source https://forum.openzeppelin.com/t/using-the-maximum-integer-in-solidity/3000/13
There are five places where this change can save gas https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L214 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L256 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L421 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L451 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L157
Use type(uint256).max
For loops that use i++ do not need to use safemath for this operation because the loop would run out of gas long before this point. Making this addition operation unsafe using unchecked saves gas.
Sample code to make the for loop increment unsafe
for (uint i = 0; i < length; i = unchecked_inc(i)) { // do something that doesn't change the value of i } function unchecked_inc(uint i) returns (uint) { unchecked { return i + 1; } }
Idea borrowed from https://gist.github.com/hrkrshnn/ee8fabd532058307229d65dcd5836ddc#the-increment-in-for-loop-post-condition-can-be-made-unchecked
There are many for loops and that can use this change https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L635 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L311 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L427 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L480 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L582 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L85 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L169 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L227
Make the increment in for loops unsafe to save gas
Comparing a value to zero can be done using the iszero
EVM opcode. This can save gas
Source from t11s https://twitter.com/transmissions11/status/1474465495243898885
There are many places where a value is compared to zero https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/peripheral_contracts/SafeMathE.sol#L17 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L315 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L317 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L399 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L457 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L480 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L494 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L569 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L86 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L171 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L229 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L236 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L464 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L54 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L287 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L288 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L341 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1009 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1093 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1137 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1178
Use the assembly iszero
evm opcode to compare values to zero
Use unchecked math when there is no overflow risk to save gas. Before index is decreased in remove it is checked for zero condition. This means index will not underflow and can be unchecked.
These subtractions do not need to be checked for underflows because they are in if statements or while loops that confirm the underflow will not happen https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L852 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L891 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L917 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L941
Add unchecked around math that can't overflow for gas savings. In Solidity before 0.8.0, use the normal math operators instead of safe math functions.
Identifying a function as payable saves gas. Functions that have a modifier like onlyOwner or auth cannot be called by normal users and will not mistakenly receive ETH. These functions can be payable to save gas.
There are many functions that have the auth modifier in the contracts. Some examples are https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L22 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L479 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L733 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L747 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L762 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1231 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1239 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1249 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L1256
Add payable to these functions for gas savings
An internal function can save gas vs. a modifier. A modifier inlines the code of the original function but an internal function does not.
Many modifiers can use this change https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L226 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L234 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L142 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L147 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathHouse.sol#L87 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/proxy/TransparentUpgradeableProxy.sol#L66 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L27 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L209 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L215 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L221 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L225 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L452 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L458 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L465 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L494 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L570
Use internal functions in place of modifiers to save gas.
A solidity version before 0.8.X is used. The latest release of solidity includes changes that can provide gas savings. The improvements include:
The advantages of versions 0.8.*
over <0.8.0
are:
0.8.0
(can be more gas efficient than some library based safemath).0.8.2
, leads to cheaper runtime gas. Especially relevant when the contract has small functions. For example, OpenZeppelin libraries typically have a lot of small helper functions and if they are not inlined, they cost an additional 20 to 40 gas because of 2 extra jump
instructions and additional stack operations needed for function calls.0.8.3
, storing packed structs, in some cases used an additional storage read operation. After EIP-2929, if the slot was already cold, this means unnecessary stack operations and extra deploy time costs. However, if the slot was already warm, this means additional cost of 100
gas alongside the same unnecessary stack operations and extra deploy time costs.0.8.4
, leads to cheaper deploy time cost and run time cost. Note: the run time cost is only relevant when the revert condition is met. In short, replace revert strings by custom errors.Source https://gist.github.com/hrkrshnn/ee8fabd532058307229d65dcd5836ddc#upgrade-to-at-least-084
Use solidity release 0.8.13 with Yul IR pipeline and other improvements for gas savings
The comparison operators >= and <= use more gas than >, <, or ==. Replacing the >= and ≤ operators with a comparison operator that has an opcode in the EVM saves gas
The existing code is https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L62 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L70
return x >= y ? x : y;
A simple comparison can be used for gas savings by reversing the logic
return x < y ? y : x;
Other places with this https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L58 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L66
Replace the comparison operator and reverse the logic to save gas using the suggestions above
The comparison operators >= and <= use more gas than >, <, or ==. Replacing the >= and ≤ operators with a comparison operator that has an opcode in the EVM saves gas
The existing code is https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L849
if (pay_amt >= offers[offerId].buy_amt) { //If amount to sell is higher or equal than current offer amount to buy fill_amt = add(fill_amt, offers[offerId].pay_amt); //Add amount bought to acumulator pay_amt = sub(pay_amt, offers[offerId].buy_amt); //Decrease amount to sell take(bytes32(offerId), uint128(offers[offerId].pay_amt)); //We take the whole offer } else { // if lower uint256 baux = rmul( pay_amt * 10**9, rdiv(offers[offerId].pay_amt, offers[offerId].buy_amt) ) / 10**9; fill_amt = add(fill_amt, baux); //Add amount bought to acumulator take(bytes32(offerId), uint128(baux)); //We take the portion of the offer that we need pay_amt = 0; //All amount is sold }
A simple comparison can be used for gas savings by reversing the logic
if (pay_amt < offers[offerId].buy_amt) { // if lower uint256 baux = rmul( pay_amt * 10**9, rdiv(offers[offerId].pay_amt, offers[offerId].buy_amt) ) / 10**9; fill_amt = add(fill_amt, baux); //Add amount bought to acumulator take(bytes32(offerId), uint128(baux)); //We take the portion of the offer that we need pay_amt = 0; //All amount is sold } else { //If amount to sell is higher or equal than current offer amount to buy fill_amt = add(fill_amt, offers[offerId].pay_amt); //Add amount bought to acumulator pay_amt = sub(pay_amt, offers[offerId].buy_amt); //Decrease amount to sell take(bytes32(offerId), uint128(offers[offerId].pay_amt)); //We take the whole offer }
Other places with this https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L888
Replace the comparison operator and reverse the logic to save gas using the suggestions above
When multiply or dividing by a power of two, it is cheaper to bitshift than to use standard math operations.
There is a divide by 2 operation on these lines https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L77 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L81 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L85 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L89
Bitshift right by one bit instead of dividing by 2 to save gas
Many constant variables are public, but changing the visibility of these variables to private or internal can save gas.
https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/peripheral_contracts/TokenWithFaucet.sol#L16 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/peripheral_contracts/SafeMathE.sol#L23 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/peripheral_contracts/SafeMathE.sol#L24 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathToken.sol#L70 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L73 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L74
Declare some public variables as private or internal to save gas
Using calldata instead of memory for function arguments saves gas sometimes. This can happen when a function is called externally and the memory array values are kept in calldata
and copied to memory
during ABI decoding (using the opcode calldataload
and mstore
). If the array is used in a for loop, arr[i]
accesses the value in memory using a mload
. If calldata is used instead, then instead of going via memory, the value is directly read from calldata
using calldataload
. That is, there are no intermediate memory operations that carries this value.
Many cases of function arguments using memory instead of calldata can use this improvement to save gas https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L413-L417 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L464-L469 https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/rubiconPools/BathPair.sol#L578
Change function arguments from memory to calldata
The contracts are all written entirely in solidity. Writing contracts with vyper instead of solidity can save gas.
Source https://twitter.com/eiber_david/status/1515737811881807876 doggo demonstrates https://twitter.com/fubuloubu/status/1528179581974417414?t=-hcq_26JFDaHdAQZ-wYxCA&s=19
Write some or all of the contracts in vyper to save gas