Arbitrum Security Council Election System - LeoS's results

A suite of scaling solutions providing environments with high-throughput, low-cost smart contracts, backed by industry-leading proving technology rooted in Ethereum.

General Information

Platform: Code4rena

Start Date: 03/08/2023

Pot Size: $90,500 USDC

Total HM: 6

Participants: 36

Period: 7 days

Judge: 0xean

Total Solo HM: 1

Id: 273

League: ETH

Arbitrum Foundation

Findings Distribution

Researcher Performance

Rank: 15/36

Findings: 1

Award: $462.24

🌟 Selected for report: 1

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: LeoS

Also found by: 0xAnah, JCK, K42, SAAJ, Sathish9098, Udsen, caventa, dharma09, ernestognw, naman1778, petrichor, rektthecode

Labels

bug
G (Gas Optimization)
high quality report
selected for report
sponsor confirmed
edited-by-warden
G-12

Awards

462.2414 USDC - $462.24

External Links

Summary

IssueInstancesGas Saved
[G-01]Use calldata instead of memory4-341 522
[G-02]The creation of an intermediary array can be avoided1-323 094
[G-03]Combine multiple for loop2-285 015
[G-04]Optimize array comparison1-136 722
[G-05]Activating the --via-ir with foundry--19 932 210
[G-06]Set the number of optimizer runs individually--

The gas saved column simply adds up the evolution in the snapshot, using the method described in the next section.

Benchmark

A benchmark is performed on each optimization, using the tests snapshot provided by foundry. This snapshot is based on tests and therefore does not take into account all functions, this loss is accepted. But it is also subject to intrinsic variance. This means that some tests are not relevant to the comparison because they vary too much and are thus not taken into account. These are listed below:

testNoopUpdate testRemoveOne testAddOne testUpdateCohort testCantDropBelowThreshhold

[G-01] Use calldata instead of memory

Using calldata instead of memory for function parameters can save gas if the argument is only read in the function. Only instances compilable with a simple type swap are considered valid.

4 instances

Applying this optimisation, those changes appear in the snapshot:

testCantUpdateCohortWithADup() (gas: 20 (0.016%)) testE2E() (gas: -51950 (-0.062%)) testSecurityCouncilManagerDeployment() (gas: -47927 (-0.160%)) testNomineeElectionGovDeployment() (gas: -47927 (-0.160%)) testRemovalGovDeployment() (gas: -47927 (-0.160%)) testMemberElectionGovDeployment() (gas: -47927 (-0.160%)) testOnlyOwnerCanDeploy() (gas: -49346 (-0.196%)) testInvalidInit() (gas: -25509 (-0.364%)) testInitialization() (gas: -1263 (-0.626%)) testUpdateSecondCohort() (gas: -2014 (-0.657%)) testUpdateFirstCohort() (gas: -2014 (-0.657%)) testReplaceMemberInSecondCohort() (gas: -2034 (-0.744%)) testRotateMember() (gas: -2034 (-0.753%)) testReplaceMemberInFirstCohort() (gas: -2034 (-0.754%)) testAddMemberAffordances() (gas: -1892 (-0.758%)) testRemoveMember() (gas: -1892 (-0.872%)) testAddMemberToSecondCohort() (gas: -3926 (-1.109%)) testAddMemberToFirstCohort() (gas: -3926 (-1.119%)) Overall gas change: -341522 (-0.024%)

[G-02] The creation of an intermediary array can be avoided

Sometimes, it's not necessary to create an intermediate array to store values.

1 instance

In this case, an array of maximum size is created because we don't yet know what size the final array will be. This is not useful, as it's more efficient to keep this maximum-size array, fill it and then reduce its size using assembly.

The function can be changed like that:

function filterAddressesWithExcludeList(
address[]  memory input,
mapping(address => bool)  storage excludeList
)  internal  view  returns  (address[]  memory)  {
- /* */
+	address[]  memory output =  new  address[](input.length);
+	uint256 outputLength =  0;
+	for  (uint256 i =  0; i < input.length; i++)  {
+		if  (!excludeList[input[i]])  {
+			output[outputLength]  = input[i];
+			outputLength++;
+		}
+	}
+	assembly {
+		mstore(output, outputLength) //Set the appropriate size
+	}
+	return output;
}

Applying this optimisation, those changes appear in the snapshot:

testE2E() (gas: -31712 (-0.038%)) testSecurityCouncilManagerDeployment() (gas: -30294 (-0.101%)) testNomineeElectionGovDeployment() (gas: -30294 (-0.101%)) testRemovalGovDeployment() (gas: -30294 (-0.101%)) testMemberElectionGovDeployment() (gas: -30294 (-0.101%)) testOnlyOwnerCanDeploy() (gas: -30294 (-0.120%)) testInvalidInit() (gas: -30293 (-0.433%)) testTopNomineesGas() (gas: -109619 (-2.434%)) Overall gas change: -323094 (-0.023%)

[G-03] Combine multiple for loop

Whenever possible, it's best to avoid running several for loops one after the other. Most of the time, they can be combined. This avoids certain initialization and counting operations. It's even more interesting when you can take advantage of values that have already been calculated (in this case, a sum of lengths).

2 instances

+		uint256 totalCohortLength = dp.firstCohort.length + dp.secondCohort.length;
-       if (owners.length != (dp.firstCohort.length + dp.secondCohort.length)) {
+       if  (owners.length !=  (totalCohortLength))  {
            revert InvalidCohortsSize(owners.length, dp.firstCohort.length, dp.secondCohort.length);
        }

-        for (uint256 i = 0; i < dp.firstCohort.length; i++) {
-            if (!govChainEmergencySCSafe.isOwner(dp.firstCohort[i])) {
-                revert AddressNotInCouncil(owners, dp.firstCohort[i]);
-            }
-        }

-        for (uint256 i = 0; i < dp.secondCohort.length; i++) {
-            if (!govChainEmergencySCSafe.isOwner(dp.secondCohort[i])) {
-                revert AddressNotInCouncil(owners, dp.secondCohort[i]);
-           }
-       }
+		for (uint256 i = 0; i < totalCohortLength; i++) {
+			address cohortMember; 
+			if (i < dp.firstCohort.length) { 
+				cohortMember = dp.firstCohort[i]; 
+			} 
+			else { 
+				cohortMember = dp.secondCohort[i - dp.firstCohort.length];
+			} 
+			if (!govChainEmergencySCSafe.isOwner(cohortMember)) { 
+				revert AddressNotInCouncil(owners, cohortMember); 
+			} 
+		}

Applying this optimisation, those changes appear in the snapshot:

testE2E() (gas: -38080 (-0.046%)) testSecurityCouncilManagerDeployment() (gas: -38605 (-0.129%)) testNomineeElectionGovDeployment() (gas: -38605 (-0.129%)) testRemovalGovDeployment() (gas: -38605 (-0.129%)) testMemberElectionGovDeployment() (gas: -38605 (-0.129%)) testOnlyOwnerCanDeploy() (gas: -38667 (-0.154%)) Overall gas change: -231167 (-0.016%)
-        for (uint256 i = 0; i < _updatedMembers.length; i++) {
-            address member = _updatedMembers[i];
-            if (!securityCouncil.isOwner(member)) {
-                _addMember(securityCouncil, member, threshold);
-            }
-        }
-        
-        for (uint256 i = 0; i < previousOwners.length; i++) {
-            address owner = previousOwners[i];
-            if (!SecurityCouncilMgmtUtils.isInArray(owner, _updatedMembers)) {
-                _removeMember(securityCouncil, owner, threshold);
-            }
-        }

+        for (uint256 i = 0; i < _updatedMembers.length || i < previousOwners.length; i++) {
+            if (i < _updatedMembers.length) {
+                address member = _updatedMembers[i];
+                if (!securityCouncil.isOwner(member)) {
+                    _addMember(securityCouncil, member, threshold);
+                }
+            }
+            
+            if (i < previousOwners.length) {
+                address owner = previousOwners[i];
+                if (!SecurityCouncilMgmtUtils.isInArray(owner, _updatedMembers)) {
+                    _removeMember(securityCouncil, owner, threshold);
+                }
+            }
+        }

Applying this optimisation, those changes appear in the snapshot:

testNonces() (gas: -944 (-0.011%)) testE2E() (gas: -52904 (-0.064%)) Overall gas change: -53848 (-0.004%)

[G-04] Optimize array comparison

The following function is not well optimized. First of all, there's no need to check the array twice. This alone reduces the cost by half.

1 instance

function areAddressArraysEqual(address[] memory array1, address[] memory array2) 
	public 
	pure 
	returns (bool)
{
	if (array1.length != array2.length) {
		return false;
	} 
	 for (uint256 i = 0; i < array1.length; i++) {  
		 bool found = false;  
		 for (uint256 j = 0; j < array2.length; j++) {  
			 if (array1[i] == array2[j]) {  
				 found = true;  
				 break;  
			 }  
		 }  
		 if (!found) {  
			 return false;  
		 }  
	 } 
-	 for (uint256 i = 0; i < array2.length; i++) {  
-		 bool found = false;  
-		 for (uint256 j = 0; j < array1.length; j++) {  
-			 if (array2[i] == array1[j]) {  
-				 found = true;  
-				 break;  
-			 }  
-		 }  
-		 if (!found) {  
-			 return false;  
-		 } 
-	 } 
	 return true; 

Applying this optimisation, those changes appear in the snapshot:

testE2E() (gas: -136722 (-0.164%)) Overall gas change: -136722 (-0.010%)

But at this point the function is not yet perfectly optimized. it has a complexity of O(n^2). This can be increased by hashing the arrays, but the elements must be ordered. For this, quicksort is the best algorythm (this is obviously not recalled) (address can be compared by converting them to uint160).

function areAddressArraysEqual(address[] memory array1, address[] memory array2){
-    /* */
+  	 quicksort(array1);
+        quicksort(array2);
+	 bytes32 hash1 = keccak256(abi.encode(array1));  
+	 bytes32 hash2 = keccak256(abi.encode(array2));
+	 return hash1 == hash2; 
+ }

In this way, the function would have a theoretical complexity of O(n log n). But in reality this will be more expensive for small arrays than the first alternative. Another way would be to introduce a hash table to compare elements more efficiently without looping (only one array need to be hashed), but this is again uneconomical on small arrays. That's why only a benchmark for the simplest optimization is provided. On tests, the other two worsen costs. But it's useful to know that they exist and could be implemented if this function were to become more important.

[G-05] Activating the --via-ir with foundry

This option allows YUL optimization. It is currently in heavy development and will allow the biggest gain.

With this activated, those changes appear in the snapshot:

testNoVoteForNonCompliantNominee() (gas: 87 (0.070%)) testMiscVotesViews() (gas: 183 (0.080%)) testIncludeNominee() (gas: 978 (0.152%)) testExecute() (gas: -1396 (-0.210%)) testProposalCreationCallRestriction() (gas: -108 (-0.217%)) testProposalExpirationDeadline() (gas: -297 (-0.220%)) testAddContender() (gas: -483 (-0.224%)) testForceSupport() (gas: 500 (0.302%)) testNoZeroWeightVotes() (gas: 568 (0.335%)) testUpdateRouter() (gas: -266 (-0.349%)) testProposalCreationTargetRestriction() (gas: -169 (-0.360%)) testForceSupport() (gas: -638 (-0.361%)) testCannotUseMoreVotesThanAvailable() (gas: -927 (-0.377%)) testAddSC() (gas: 493 (0.417%)) testInvalidParams() (gas: 721 (0.436%)) testProposalCreationUnexpectedCallDataLen() (gas: -191 (-0.459%)) testProposalCreationValuesRestriction() (gas: -301 (-0.486%)) testUpdateSecondCohort() (gas: -1516 (-0.495%)) testRegisterTokenOnL2NotEnoughVal() (gas: 22178 (0.501%)) testUpdateFirstCohort() (gas: -1547 (-0.505%)) testRegisterTokenOnL2() (gas: 23576 (0.516%)) testReplaceMemberInFirstCohort() (gas: -1405 (-0.521%)) testReplaceMemberInSecondCohort() (gas: -1449 (-0.530%)) testSelectTopNomineesFails() (gas: -1613 (-0.598%)) testRemoveAllOutboxes() (gas: 4345 (0.627%)) testZeroToken() (gas: 509 (0.708%)) testCantUpdateCohortWithADup() (gas: 903 (0.733%)) testProposalCreationTargetLen() (gas: 297 (0.839%)) testCountVote() (gas: 5034 (0.934%)) testRotateMember() (gas: -2537 (-0.940%)) testSetRecipientsTwice() (gas: 60317 (0.944%)) testSuccessfulProposalAndCantAbstain() (gas: -1351 (-0.947%)) testProposalCreationCallParamRestriction() (gas: -630 (-1.122%)) testClaimAndDelegate() (gas: 67720 (1.157%)) testClaimAndDelegateFailsWrongNonce() (gas: 67376 (1.161%)) testClaimAndDelegateFailsForWrongSender() (gas: 67642 (1.166%)) testSetRecipientsFailsWhenAddingTwice() (gas: 66686 (1.167%)) testSetRecipientsFailsNotEnoughDeposit() (gas: 66676 (1.176%)) testClaimAndDelegateFailsForExpired() (gas: 67870 (1.181%)) testSweepFailsTwice() (gas: 67968 (1.182%)) testSetRecipients() (gas: 67564 (1.185%)) testClaimFailsBeforeStart() (gas: 67688 (1.187%)) testSweepAfterClaim() (gas: 68723 (1.187%)) testWithdrawFailsNotOwner() (gas: 68257 (1.189%)) testWithdraw() (gas: 68257 (1.189%)) testSweep() (gas: 68426 (1.190%)) testClaimFailsForTwice() (gas: 68459 (1.192%)) testSetSweepReceiver() (gas: 68050 (1.193%)) testClaimFailsForUnknown() (gas: 68198 (1.195%)) testSetSweepReceiverFailsNullAddress() (gas: 68221 (1.196%)) testClaimFailsForFalseTransfer() (gas: 68071 (1.197%)) testClaimFailsAfterEnd() (gas: 68372 (1.199%)) testClaim() (gas: 68864 (1.199%)) testSweepFailsBeforeClaimPeriodEnd() (gas: 68404 (1.199%)) testSweepFailsForFailedTransfer() (gas: 68586 (1.202%)) testWithdrawFailsTransfer() (gas: 68731 (1.205%)) testSetSweepReceiverFailsOwner() (gas: 68791 (1.206%)) testSetRecipientsFailsWrongAmountCount() (gas: 68869 (1.270%)) testSetRecipientsFailsWrongRecipientCount() (gas: 69167 (1.276%)) testSetRecipientsFailsNotOwner() (gas: 69302 (1.279%)) testSuccessNumeratorSufficientVotes() (gas: -4743 (-1.313%)) testReplaceMemberAffordances() (gas: -2763 (-1.325%)) testDoesDeployAndDeposit() (gas: 73458 (1.359%)) testSuccessNumeratorInsufficientVotes() (gas: -4916 (-1.372%)) testExecutorPermissions() (gas: -191009 (-1.394%)) testDoesDeploy() (gas: 74634 (1.398%)) testExecutorPermissionsFail() (gas: -191646 (-1.401%)) testPastCirculatingSupplyExclude() (gas: -195020 (-1.412%)) testPastCirculatingSupplyMint() (gas: -194775 (-1.418%)) testCantReinit() (gas: -194401 (-1.422%)) testPastCirculatingSupply() (gas: -194587 (-1.423%)) testProperlyInitialized() (gas: -194591 (-1.424%)) testProposalDoesExpire() (gas: -3916 (-1.437%)) testRemoveSeC() (gas: -602 (-1.581%)) testVotesToWeight() (gas: 2467 (1.614%)) testCastVoteReverts() (gas: 544 (1.634%)) testE2E() (gas: -1367483 (-1.645%)) testOnlyNomineeElectionGovernorCanPropose() (gas: 1859 (1.687%)) testSetFullWeightDuration() (gas: 593 (1.697%)) testCohortMethods() (gas: 3006 (1.922%)) testNonces() (gas: -162554 (-1.955%)) testAddMemberToSecondCohort() (gas: -6982 (-1.972%)) testRemoveMember() (gas: -4312 (-1.987%)) testAddMemberToFirstCohort() (gas: -7523 (-2.144%)) testUpgraderCanCancel() (gas: -665066 (-2.321%)) testSanityCheckValues() (gas: -659682 (-2.322%)) testRoles() (gas: -662154 (-2.332%)) testSetMinDelay() (gas: -662603 (-2.336%)) testContractsDeployed() (gas: -662956 (-2.338%)) testContractsInitialized() (gas: -664183 (-2.339%)) testDeploySteps() (gas: -663740 (-2.340%)) testProxyAdminOwnership() (gas: -663818 (-2.340%)) testSetMinDelayRevertsForCoreAddress() (gas: -673708 (-2.371%)) testGetPrevOwner() (gas: -189384 (-2.392%)) testGetPrevOwner() (gas: -189429 (-2.393%)) testExcludeNominee() (gas: 10353 (2.396%)) testAddressRegistryAddress() (gas: 1162 (2.470%)) testUpgradeAndCall() (gas: 3567 (2.494%)) testCreateElection() (gas: 6424 (2.572%)) testRelay() (gas: 1133 (2.683%)) testBridgeBurnNotGateway() (gas: -91388 (-2.696%)) testBridgeBurn() (gas: -91715 (-2.701%)) testBridgeMint() (gas: -91658 (-2.703%)) testInit() (gas: -91270 (-2.720%)) testProposeReverts() (gas: 873 (2.724%)) testBridgeMintNotGateway() (gas: -91691 (-2.744%)) testInitialization() (gas: 5564 (2.757%)) testAction() (gas: 17747 (2.820%)) testInitZeroNovaGateway() (gas: -91312 (-2.874%)) testInitZeroNovaRouter() (gas: -91425 (-2.878%)) testInitZeroGateway() (gas: -91430 (-2.878%)) testL2() (gas: 20363 (2.956%)) testProperlyInits() (gas: -498030 (-3.048%)) testRelease() (gas: -501792 (-3.051%)) testMigrationTargetMustBeContract() (gas: -498768 (-3.053%)) testBeneficiaryCanSetBeneficiary() (gas: -498785 (-3.054%)) testOnlyOwnerCanMigrate() (gas: -498812 (-3.055%)) testOwnerCanSetBeneficiary() (gas: -498941 (-3.055%)) testRandomAddressCantSetBeneficiary() (gas: -499262 (-3.057%)) testOnlyBeneficiaryCanRelease() (gas: -499210 (-3.057%)) testRelay() (gas: 1304 (3.083%)) testUpgrade() (gas: 4253 (3.102%)) testInitFails() (gas: -310887 (-3.154%)) testAddOutbxesAction() (gas: -21773 (-3.342%)) testAddSCAffordances() (gas: -3777 (-3.377%)) testNoLogicContractInit() (gas: 92072 (3.419%)) testTopNomineesGas() (gas: 155981 (3.464%)) testCastVote() (gas: -572625 (-3.534%)) testCastVoteFailsForNonBeneficiary() (gas: -571395 (-3.538%)) testDelegate() (gas: -571417 (-3.553%)) testClaim() (gas: -570936 (-3.567%)) testDelegateFailsForNonBeneficiary() (gas: -571142 (-3.568%)) testReleaseAffordance() (gas: -571476 (-3.570%)) testDoesDeploy() (gas: -570820 (-3.574%)) testClaimFailsForNonBeneficiary() (gas: -571228 (-3.577%)) testVestedAmountStart() (gas: -579489 (-3.605%)) testCastVoteReverts() (gas: 1205 (3.620%)) testCanTransferAndCallContract() (gas: 155618 (3.695%)) testAIP1Point2() (gas: -50235 (-3.798%)) testRemoveMemberAffordances() (gas: -3991 (-4.028%)) testCannotTransferAndCallReverter() (gas: 168980 (4.067%)) testOldClaimStart() (gas: 168880 (4.084%)) testZeroOwner() (gas: 169312 (4.097%)) testClaimStartAfterClaimEnd() (gas: 169462 (4.098%)) testZeroDelegateTo() (gas: 169641 (4.105%)) testZeroReceiver() (gas: 169664 (4.105%)) testCanMintLessThan2Percent() (gas: 168658 (4.112%)) testCanTransferAndCallEmpty() (gas: 168579 (4.115%)) testCanMintTwiceWithWarp() (gas: 337439 (4.120%)) testCanMint2Percent() (gas: 169018 (4.121%)) testCanMintZero() (gas: 168505 (4.128%)) testCannotMintTwice() (gas: 337579 (4.138%)) testCannotTransferAndCallNonReceiver() (gas: 169517 (4.140%)) testCanBurn() (gas: 168585 (4.145%)) testCannotMintWithoutFastForward() (gas: 169207 (4.158%)) testCannotMintNotOwner() (gas: 169434 (4.164%)) testCannotMintMoreThan2Percent() (gas: 169620 (4.166%)) testMigrateEthToNewWalletWithSlowerVesting() (gas: -804645 (-4.181%)) testMigrateTokensToNewWalletWithSlowerVesting() (gas: -804858 (-4.182%)) testMigrateTokensToNewWalletWithFasterVesting() (gas: -804957 (-4.182%)) testIsInitialised() (gas: 170701 (4.191%)) testAddressRegistryAddress() (gas: 2294 (4.197%)) testAdminCanChangeExecutor() (gas: 109468 (4.237%)) testTransfer() (gas: 253081 (4.266%)) testAddMemberAffordances() (gas: -10695 (-4.286%)) testTransferNotOwner() (gas: 253427 (4.297%)) testCantAddEOA() (gas: -41996 (-4.333%)) testInitZeroToken() (gas: 252706 (4.344%)) testCantReAddOutbox() (gas: -42359 (-4.346%)) testInit() (gas: 253551 (4.355%)) testExecuteFailsForAdmin() (gas: 118121 (4.435%)) testExecuteFailsForNobody() (gas: 118350 (4.439%)) testDoesNotInitialiseZeroL1Token() (gas: 169811 (4.468%)) testDoesNotInitialiseZeroInitialSup() (gas: 169869 (4.469%)) testDoesNotInitialiseZeroOwner() (gas: 170361 (4.482%)) testSetNomineeVetter() (gas: 1813 (4.545%)) testRemoveOutboxes() (gas: -39070 (-4.574%)) testInit() (gas: 111581 (4.596%)) testCantExecuteEOA() (gas: 112213 (4.599%)) testSetVoteSuccessNumeratorAffordance() (gas: 2198 (4.615%)) testProposeFails() (gas: 925 (4.708%)) testUpdateRouterAffordacnes() (gas: -5340 (-4.752%)) testSetVoteSuccessNumerator() (gas: 1429 (4.759%)) testExecute() (gas: 127628 (4.766%)) testSeparateSelector() (gas: 1142 (4.852%)) testInitFailsZeroAdmin() (gas: 112840 (4.931%)) testRemoveSCAffordances() (gas: -4049 (-5.047%)) testRelay() (gas: 2143 (5.053%)) testIsInArray() (gas: 107 (5.090%)) testSelectTopNominees(uint256) (gas: 18748 (5.516%)) testProperInitialization() (gas: 2735 (5.535%)) testUpdateCohortAffordances() (gas: -4660 (-5.615%)) testProperInitialization() (gas: 4756 (6.087%)) testExecuteInbox() (gas: 369596 (6.436%)) testRouteBuilderErrors() (gas: -72037 (-6.451%)) testCancelFailsBadSender() (gas: 352395 (6.568%)) testSchedule() (gas: 361753 (6.757%)) testExecuteInboxNotEnoughVal() (gas: 369341 (6.784%)) testCancel() (gas: 362558 (6.814%)) testExecuteInboxInvalidData() (gas: 370823 (6.839%)) testExecute() (gas: 370566 (6.861%)) testScheduleFailsBadL2Timelock() (gas: 362455 (6.862%)) testScheduleFailsBadSender() (gas: 362652 (6.872%)) testDoesDeploy() (gas: 363553 (6.900%)) testDoesNotDeployZeroL2Timelock() (gas: 363572 (7.311%)) testDoesNotDeployZeroInbox() (gas: 363824 (7.313%)) testSecurityCouncilManagerDeployment() (gas: -2297814 (-7.671%)) testNomineeElectionGovDeployment() (gas: -2298257 (-7.677%)) testRemovalGovDeployment() (gas: -2298788 (-7.679%)) testMemberElectionGovDeployment() (gas: -2298868 (-7.680%)) testOwnerCanSetHashTwice() (gas: 21267 (8.061%)) testOwnerCanSetHash() (gas: 21075 (8.070%)) testMonOwnerCannotSetHash() (gas: 21303 (8.105%)) testConstructor() (gas: 21188 (8.169%)) testAddAndRemoveSequencer() (gas: 39930 (8.261%)) testCantAddZeroAddress() (gas: 20311 (8.620%)) testOnlyOwnerCanDeploy() (gas: -2410046 (-9.571%)) testL1() (gas: 30668 (11.800%)) testSetMinDelayRevertsForCoreAddress() (gas: 1356671 (12.572%)) testL1GovernanceFactory() (gas: 1368102 (12.711%)) testSetMinDelay() (gas: 1367888 (12.739%)) testInvalidInit() (gas: -902461 (-12.888%)) testInitReverts() (gas: -845212 (-17.426%)) testOnlyOwnerCanCreateWallets() (gas: -305406 (-20.314%)) testPauseAndUpauseInbox() (gas: 78574 (21.217%)) testDeploy() (gas: -1148592 (-25.025%)) Overall gas change: -19932210 (-1.389%)

Not all tests have lower costs, so this change can be widely discussed.

[G-06] Set the number of optimizer runs individually

Some development environments allow the number of optimizer runs to be defined individually for each contract. This is difficult to achieve in foundry. But hardhat is the best example. The main limitation to the number of runs in the case of contracts that will be heavily executed is the size of the deployment, which is limited. With foundry, a single contract completely blocks this number. Here, the maximum number is 1915 (set to 1900 in foundry) for the SecurityCouncilNomineeElectionGovernor.sol contract. By only setting this one to this value and greatly increase for the other, a huge saving can be achieved.

We therefore suggest moving to a development/deployment environment where this option is available. No contract in scope expects the limit, even for 100,000 runs.

This optimization certainly has the biggest impact, but as the tests are written with foundry, it's impossible to provide a benchmark in a short space of time.

#0 - c4-pre-sort

2023-08-13T19:13:29Z

0xSorryNotSorry marked the issue as high quality report

#1 - c4-sponsor

2023-08-15T14:54:12Z

yahgwai marked the issue as sponsor confirmed

#2 - yahgwai

2023-08-15T14:56:19Z

All good findings, much appreciated

G-01: Ack G-02: Ack G-03: Ack G-04: Confirm G-05: Ack G-06: Nice info, ty

#4 - c4-judge

2023-08-18T14:27:27Z

0xean marked the issue as selected for report

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter