In the WardenPledge.sol contract, the minDelegationTime variable is not modifiable and is defined as a simple variable whereas it could be defined as a constant in order to save some gas.
In Solidity, we can pack multiple contract and struct variables into the same 32 bytes slot in storage. With this pattern, we can greatly optimize gas consumption when storing or loading statically-sized variables.
So, these 3 variables are using a total of 29 bytes (20 + 8 + 1). However, we can easily make them use a full 32 bytes storage slot by changing the uint64 to an uint88 (11 bytes) => 20 + 11 + 1 = 32. With this, the EVM doesn't have to fill the remaining bytes anymore, so we save gas.
The new Struct would look like this:
struct Pledge{
// Target amount of veCRV (balance scaled by Boost v2, fetched as adjusted_balance)
uint256 targetVotes;
// Difference of votes between the target and the receiver balance at the start of the Pledge
// (used for later extend/increase of some parameters the Pledge)
uint256 votesDifference;
// Price per vote per second, set by the owner
uint256 rewardPerVote;
// Address to receive the Boosts
address receiver;
// Address of the token given as rewards to Boosters
address rewardToken;
// Timestamp of end of the Pledge
uint88 endTimestamp;
// Set to true if the Pledge is canceled, or when closed after the endTimestamp
bool closed;
}
In addition to the use of a constant for the minDelegationTime variable, we can pack 2 variables into the same slot: protocalFeeRatio and chestAddress. The fee ratio is expressed in basis points and therefore will never exceed 10000, which means we can change its uint256 type into an uint96 (12 bytes). So the address and the uint96 will take one single full 32 bytes slot (20 + 12) instead of 2 slots.
/** @notice Address to receive protocol fees */
address public chestAddress;
/** @notice ratio of fees to pay the protocol (in BPS) */
uint96 public protocalFeeRatio = 250; //bps
Define Uneditable Variable As Constant
In the
WardenPledge.sol
contract, theminDelegationTime
variable is not modifiable and is defined as a simple variable whereas it could be defined as a constant in order to save some gas.Here is the recommendation at lines 21 : https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L21
Therefore, when this variable is called later in contract's functions at lines 320 and 386, some changes are required:
As follows:
Finally, the previous variable declared at line 79 can be removed : https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L79
Tight Variable Packing
In Solidity, we can pack multiple contract and struct variables into the same 32 bytes slot in storage. With this pattern, we can greatly optimize gas consumption when storing or loading statically-sized variables.
Pledge Struct
Under this Struct defined from line 28 to line 44 : https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L28:L44 , we can pack the last 3 variables into a full 32 bytes slot:
rewardToken
,endTimestamp
andclosed
.Here are the bytes used per these types:
address
= 20 bytesuint64
= 8 bytesbool
= 1So, these 3 variables are using a total of 29 bytes (20 + 8 + 1). However, we can easily make them use a full 32 bytes storage slot by changing the
uint64
to anuint88
(11 bytes) => 20 + 11 + 1 = 32. With this, the EVM doesn't have to fill the remaining bytes anymore, so we save gas.The new Struct would look like this:
Of course, we must change the content and the name of the
safe64
function to match the newuint88
pattern : https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L665:L668With that being applied, we also must change the lines where this function is called as we renamed it, this happens at those lines:
Finally, the revert error name must be changed in this file: https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/utils/Errors.sol#L46
Contract Variables
In addition to the use of a constant for the
minDelegationTime
variable, we can pack 2 variables into the same slot:protocalFeeRatio
andchestAddress
. The fee ratio is expressed in basis points and therefore will never exceed 10000, which means we can change itsuint256
type into anuint96
(12 bytes). So the address and the uint96 will take one single full 32 bytes slot (20 + 12) instead of 2 slots.https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L71
Of course, the update function of the
protocalFeeRatio
must be changed accordingly with this new variable type: https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L625:L631Finally, the
PlatformFeeUpdated
definition must be updated : https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L117