For external function's dynamic params, calldata is the cheapest location to use.
MerkleDropFactory.sol
88,82: function withdraw(uint treeIndex, address destination, uint value, bytes32[] memory proof) public {
MerkleEligibility.sol
70,66: function isEligible(uint index, address recipient, bytes32[] memory proof) public override view returns (bool eligible) {
85,68: function passThruGate(uint index, address recipient, bytes32[] memory proof) external override {
MerkleIdentity.sol
116,62: function withdraw(uint merkleIndex, uint tokenId, string memory uri, bytes32[] memory addressProof, bytes32[] memory metadataProof) external payable {
116,84: function withdraw(uint merkleIndex, uint tokenId, string memory uri, bytes32[] memory addressProof, bytes32[] memory metadataProof) external payable {
116,115: function withdraw(uint merkleIndex, uint tokenId, string memory uri, bytes32[] memory addressProof, bytes32[] memory metadataProof) external payable {
152,72: function isEligible(uint merkleIndex, address recipient, bytes32[] memory proof) public view returns (bool) {
163,64: function verifyMetadata(bytes32 root, uint tokenId, string memory uri, bytes32[] memory proof) public pure returns (bool) {
163,86: function verifyMetadata(bytes32 root, uint tokenId, string memory uri, bytes32[] memory proof) public pure returns (bool) {
MerkleLib.sol
17,64: function verifyProof(bytes32 root, bytes32 leaf, bytes32[] memory proof) public pure returns (bool) {
MerkleResistor.sol
134,136: function initialize(uint treeIndex, address destination, uint vestingTime, uint minTotalPayments, uint maxTotalPayments, bytes32[] memory proof) external {
MerkleVesting.sol
104,143: function initialize(uint treeIndex, address destination, uint totalCoins, uint startTime, uint endTime, uint lockPeriodEndTime, bytes32[] memory proof) external {
interfaces/IEligibility.sol
17,50: function isEligible(uint, address, bytes32[] memory) external view returns (bool eligible);
21,52: function passThruGate(uint, address, bytes32[] memory) external;
Recommended Mitigation Steps:
Change params memory to calldata
[G02] uint default value is 0 so we can remove = 0:
MerkleDropFactory.sol
17,26: uint public numTrees = 0;
MerkleEligibility.sol
31,26: uint public numGates = 0;
MerkleLib.sol
22,21: for (uint i = 0; i < proof.length; i += 1) {
MerkleResistor.sol
24,26: uint public numTrees = 0;
176,32: uint currentWithdrawal = 0;
MerkleVesting.sol
16,26: uint public numTrees = 0;
150,32: uint currentWithdrawal = 0;
PermissionlessBasicPoolFactory.sol
115,21: for (uint i = 0; i < rewardTokenAddresses.length; i++) {
141,21: for (uint i = 0; i < pool.rewardFunding.length; i++) {
168,21: for (uint i = 0; i < pool.rewardsWeiPerSecondPerToken.length; i++) {
224,21: for (uint i = 0; i < rewards.length; i++) {
249,21: for (uint i = 0; i < pool.rewardTokens.length; i++) {
266,21: for (uint i = 0; i < pool.rewardTokens.length; i++) {
VoterID.sol
69,31: uint public numIdentities = 0;
[G03] ++i use less gas than i++ or i += 1:
++i costs less gas compared to i++. about 5 gas per iteration.
PermissionlessBasicPoolFactory.sol
115,59: for (uint i = 0; i < rewardTokenAddresses.length; i++) {
141,57: for (uint i = 0; i < pool.rewardFunding.length; i++) {
168,71: for (uint i = 0; i < pool.rewardsWeiPerSecondPerToken.length; i++) {
224,46: for (uint i = 0; i < rewards.length; i++) {
249,56: for (uint i = 0; i < pool.rewardTokens.length; i++) {
266,56: for (uint i = 0; i < pool.rewardTokens.length; i++) {
MerkleLib.sol
22,21: for (uint i = 0; i < proof.length; i += 1) {
Gas Optimizations
[G01] Use
calldata
instead ofmemory
:For external function's dynamic params, calldata is the cheapest location to use.
Recommended Mitigation Steps:
Change params
memory
tocalldata
[G02]
uint
default value is0
so we can remove= 0
:[G03]
++i
use less gas thani++
ori += 1
:++i
costs less gas compared toi++
. about 5 gas per iteration.[G04] Use Custom Errors to save Gas:
Custom errors from Solidity 0.8.4 are cheaper than
require
messages. https://blog.soliditylang.org/2021/04/21/custom-errors/