2. State variables should be cached in stack variables rather than re-reading them from storage
The instances below point to the second+ access of a state variable within a function. Caching will replace each Gwarmaccess (100 gas) with a much cheaper stack read.
Less obvious fixes/optimizations include having local storage variables of mappings within state variable mappings or mappings within state variable structs, having local storage variables of structs within mappings, having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
4. require()/revert() strings longer than 32 bytes cost extra gas
File: solidity/contracts/Gravity.sol #1
117 require(
118 whitelisted[msg.sender] || cudosAccessControls.hasAdminRole(msg.sender) ,
119 "The caller is not whitelisted for this operation"
120 );
File: solidity/contracts/Gravity.sol #4
289 require(
290 _newValset.valsetNonce > _currentValset.valsetNonce,
291 "New valset nonce must be greater than the current nonce"
292 );
File: solidity/contracts/Gravity.sol #5
310 require(
311 makeCheckpoint(_currentValset, state_gravityId) == state_lastValsetCheckpoint,
312 "Supplied current validators and powers do not match checkpoint."
313 );
File: solidity/contracts/Gravity.sol #6
315 require(
316 isOrchestrator(_currentValset, msg.sender),
317 "The sender of the transaction is not validated orchestrator"
318 );
File: solidity/contracts/Gravity.sol #7
384 require(
385 state_lastBatchNonces[_tokenContract] < _batchNonce,
386 "New batch nonce must be greater than the current nonce"
387 );
File: solidity/contracts/Gravity.sol #8
390 require(
391 block.number < _batchTimeout,
392 "Batch timeout must be greater than the current block height"
393 );
File: solidity/contracts/Gravity.sol #9
405 require(
406 makeCheckpoint(_currentValset, state_gravityId) == state_lastValsetCheckpoint,
407 "Supplied current validators and powers do not match checkpoint."
408 );
File: solidity/contracts/Gravity.sol #10
416 require(
417 isOrchestrator(_currentValset, msg.sender),
418 "The sender of the transaction is not validated orchestrator"
419 );
File: solidity/contracts/Gravity.sol #11
494 require(
495 state_invalidationMapping[_args.invalidationId] < _args.invalidationNonce,
496 "New invalidation nonce must be greater than the current nonce"
497 );
File: solidity/contracts/Gravity.sol #12
509 require(
510 makeCheckpoint(_currentValset, state_gravityId) == state_lastValsetCheckpoint,
511 "Supplied current validators and powers do not match checkpoint."
512 );
File: solidity/contracts/Gravity.sol #14
525 require(
526 isOrchestrator(_currentValset, msg.sender),
527 "The sender of the transaction is not validated orchestrator"
528 );
// 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.
Use a solidity version of at least 0.8.0 to get overflow protection without SafeMath
Use a solidity version of at least 0.8.2 to get compiler automatic inlining
Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads
Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require() strings
Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value
10. Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead
When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.
File: solidity/contracts/Gravity.sol #3
405 require(
406 makeCheckpoint(_currentValset, state_gravityId) == state_lastValsetCheckpoint,
407 "Supplied current validators and powers do not match checkpoint."
408 );
File: solidity/contracts/Gravity.sol #4
416 require(
417 isOrchestrator(_currentValset, msg.sender),
418 "The sender of the transaction is not validated orchestrator"
419 );
12. Functions guaranteed to revert when called by normal users can be marked payable
If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are
CALLVALUE(2),DUP1(3),ISZERO(3),PUSH2(3),JUMPI(10),PUSH1(3),DUP1(3),REVERT(0),JUMPDEST(1),POP(2), which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost
File: solidity/contracts/Gravity.sol #1
124 function manageWhitelist(
125 address[] memory _users,
126 bool _isWhitelisted
127 ) public onlyWhitelisted {
File: solidity/contracts/Gravity.sol #6
276 function updateValset(
277 // The new version of the validator set
278 ValsetArgs memory _newValset,
279 // The current validators that approve the change
280 ValsetArgs memory _currentValset,
281 // These are arrays of the parts of the current validator's signatures
282 uint8[] memory _v,
283 bytes32[] memory _r,
284 bytes32[] memory _s
285 ) public nonReentrant {
File: solidity/contracts/Gravity.sol #7
364 function submitBatch (
365 // The validators that approve the batch
366 ValsetArgs memory _currentValset,
367 // These are arrays of the parts of the validators signatures
368 uint8[] memory _v,
369 bytes32[] memory _r,
370 bytes32[] memory _s,
371 // The batch of transactions
372 uint256[] memory _amounts,
373 address[] memory _destinations,
374 uint256[] memory _fees,
375 uint256 _batchNonce,
376 address _tokenContract,
377 // a block height beyond which this batch is not valid
378 // used to provide a fee-free timeout
379 uint256 _batchTimeout
380 ) public nonReentrant {
File: solidity/contracts/Gravity.sol #8
479 function submitLogicCall(
480 // The validators that approve the call
481 ValsetArgs memory _currentValset,
482 // These are arrays of the parts of the validators signatures
483 uint8[] memory _v,
484 bytes32[] memory _r,
485 bytes32[] memory _s,
486 LogicCallArgs memory _args
487 ) public nonReentrant {
14. Return from function rather than breaking out of loop
Using return rather than break saves gas because the require() outside of the for-loop has the same condition that caused the loop to be broken out of
File: solidity/contracts/Gravity.sol #1
246 // Break early to avoid wasting gas
247 if (cumulativePower > _powerThreshold) {
248 break;
249 }
250 }
251 }
252
253 // Check that there was enough power
254 require(
255 cumulativePower > _powerThreshold,
256 "Submitted validator set signatures do not have enough power."
257 );
258 // Success
259 }
File: solidity/contracts/Gravity.sol #2
514 // Check that the token transfer list is well-formed
515 require(
516 _args.transferAmounts.length == _args.transferTokenContracts.length,
517 "Malformed list of token transfers"
518 );
File: solidity/contracts/Gravity.sol #3
520 // Check that the fee list is well-formed
521 require(
522 _args.feeAmounts.length == _args.feeTokenContracts.length,
523 "Malformed list of fees"
524 );
File: solidity/contracts/Gravity.sol #1
138 // TEST FIXTURES
139 // These are here to make it easier to measure gas usage. They should be removed before production
140 function testMakeCheckpoint(ValsetArgs memory _valsetArgs, bytes32 _gravityId) public pure {
141 makeCheckpoint(_valsetArgs, _gravityId);
142 }
143
144 function testCheckValidatorSignatures(
145 address[] memory _currentValidators,
146 uint256[] memory _currentPowers,
147 uint8[] memory _v,
148 bytes32[] memory _r,
149 bytes32[] memory _s,
150 bytes32 _theHash,
151 uint256 _powerThreshold
152 ) public pure {
153 checkValidatorSignatures(
154 _currentValidators,
155 _currentPowers,
156 _v,
157 _r,
158 _s,
159 _theHash,
160 _powerThreshold
161 );
162 }
163
164 // END TEST FIXTURES
Gas Optimizations
Summary
immutable
<array>.length
should not be looked up in every loop of afor
-looprequire()
/revert()
strings longer than 32 bytes cost extra gasbool
s for storage incurs overhead++i
costs less gas than++i
, especially when it's used infor
-loops (--i
/i--
too)require()
statements that use&&
saves gasuints
/ints
smaller than 32 bytes (256 bits) incurs overheadrequire()
/revert()
checks should be refactored to a modifier or functionpayable
public
functions not called by the contract should be declaredexternal
insteadrequire()
orrevert()
statements that check input arguments should be at the top of the functionTotal: 81 instances over 16 classes
1. State variables only set in the constructor should be declared
immutable
Avoids a Gsset (20000 gas) in the constructor, and replaces each Gwarmacces (100 gas) with a
PUSH32
(3 gas).https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L60
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L61
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L63
2. State variables should be cached in stack variables rather than re-reading them from storage
The instances below point to the second+ access of a state variable within a function. Caching will replace each Gwarmaccess (100 gas) with a much cheaper stack read. Less obvious fixes/optimizations include having local storage variables of mappings within state variable mappings or mappings within state variable structs, having local storage variables of structs within mappings, having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
state_lastEventNonce https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L352
state_lastEventNonce https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L466
state_lastEventNonce https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L590
state_lastEventNonce https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L607
state_lastEventNonce https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L628
state_gravityId https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L321
state_gravityId https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L431
state_gravityId https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L533
3.
<array>.length
should not be looked up in every loop of afor
-loopThe overheads outlined below are PER LOOP, excluding the first loop
MLOAD
(3 gas)CALLDATALOAD
(3 gas)Caching the length changes each of these to a
DUP<N>
(3 gas), and gets rid of the extraDUP<N>
needed to store the stack offsethttps://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L128
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L233
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L263
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L453
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L568
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L579
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L660
4.
require()
/revert()
strings longer than 32 bytes cost extra gashttps://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L117-L120
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L238-L241
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L254-L257
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L289-L292
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L310-L313
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L315-L318
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L384-L387
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L390-L393
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L405-L408
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L416-L419
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L494-L497
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L509-L512
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L515-L518
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L525-L528
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L655
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L666-L669
5. Using
bool
s for storage incurs overheadhttps://github.com/OpenZeppelin/openzeppelin-contracts/blob/58f635312aa21f947cae5f8578638a85aa2519f5/contracts/security/ReentrancyGuard.sol#L23-L27 Use
uint256(1)
anduint256(2)
for true/falsehttps://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L65
6. Use a more recent version of solidity
Use a solidity version of at least 0.8.0 to get overflow protection without
SafeMath
Use a solidity version of at least 0.8.2 to get compiler automatic inlining Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment thanrevert()/require()
strings Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return valuehttps://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/CosmosToken.sol#L1
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L1
7. It costs more gas to initialize variables to zero than to let the default of zero be applied
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L128
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L231
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L233
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L263
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L453
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L568
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L579
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L659
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L660
8.
++i
costs less gas than++i
, especially when it's used infor
-loops (--i
/i--
too)Saves 6 gas PER LOOP
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L128
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L233
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L263
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L453
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L568
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L579
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L660
9. Splitting
require()
statements that use&&
saves gasSee this issue which describes the fact that there is a larger deployment gas cost, but with enough runtime calls, the change ends up being cheaper
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L301-L307
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L396-L402
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L411-L414
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L500-L506
10. Usage of
uints
/ints
smaller than 32 bytes (256 bits) incurs overheadhttps://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Use a larger size then downcast where needed
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/CosmosToken.sol#L11
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L91
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L178
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L615
11. Duplicated
require()
/revert()
checks should be refactored to a modifier or functionSaves deployment costs
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L666-L669
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L396-L402
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L405-L408
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L416-L419
12. Functions guaranteed to revert when called by normal users can be marked
payable
If a function modifier such as
onlyOwner
is used, the function will revert if a normal user tries to pay the function. Marking the function aspayable
will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided areCALLVALUE
(2),DUP1
(3),ISZERO
(3),PUSH2
(3),JUMPI
(10),PUSH1
(3),DUP1
(3),REVERT
(0),JUMPDEST
(1),POP
(2), which costs an average of about 21 gas per call to the function, in addition to the extra deployment costhttps://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L124-L127
13.
public
functions not called by the contract should be declaredexternal
insteadContracts are allowed to override their parents' functions and change the visibility from
external
topublic
and can save gas by doing so.https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L124-L127
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L140
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L144-L151
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L166
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L170
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L276-L285
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L364-L380
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L479-L487
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L595-L599
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L611-L615
14. Return from function rather than breaking out of loop
Using
return
rather thanbreak
saves gas because therequire()
outside of thefor
-loop has the same condition that caused the loop to be broken out ofhttps://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L246-L259
15.
require()
orrevert()
statements that check input arguments should be at the top of the functionChecks that involve constants should come before checks that involve state variables
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L411-L414
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L514-L518
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L520-L524
16. Remove test code to save deployment gas
https://github.com/code-423n4/2022-05-cudos/blob/de39cf3cd1f1e1cf211819b06d4acf6a043acda0/solidity/contracts/Gravity.sol#L138-L164