++i costs less gas compared to i++ or i += 1 for unsigned integer, as pre-increment is cheaper (about 5 gas per iteration). This statement is true even with the optimizer enabled. i++ increments i and returns the initial value of i. Which means:
uint i = 1; i++; // == 1 but i == 2
But ++i returns the actual incremented value:
uint i = 1; ++i; // == 2 and i == 2 too, so no need for a temporary variable In the first case, the compiler has to create a temporary variable (when used) for returning 1 instead of 2
uint256 i = 0; i < depositedTokens.values.length; i++)
556: for (uint256 i = 0; i < orders.length; i++) {
594: for (uint256 i = 0; i < assets.length; i++) {
611: for (uint256 i = 0; i < assets.length; i++) {
627: for (uint256 i = 0; i < floorTokens.length; i++) {
637: for (uint256 i = 0; i < assets.length; i++) {
647: for (uint256 i = 0; i < assets.length; i++) {
658: for (uint256 i = 0; i < floorTokens.length; i++) {
670: for (uint256 i = 0; i < whitelist.length; i++) {
728: for (uint256 i = 0; i < arr.length; i++) {
742: for (uint256 i = 0; i < arr.length; i++) {
Use Custom Errors instead of Revert Strings to save Gas
Custom errors from Solidity 0.8.4 are cheaper than revert strings (cheaper deployment cost and runtime cost when the revert condition is met) Source Custom Errors in Solidity: Starting from Solidity v0.8.4, there is a convenient and gas-efficient way to explain to users why an operation failed through the use of custom errors. Until now, you could already use strings to give more information about failures (e.g., revert("Insufficient funds.");), but they are rather expensive, especially when it comes to deploy cost, and it is difficult to use dynamic information in them. Custom errors are defined using the error statement, which can be used inside and outside of contracts (including interfaces and libraries).
instances include:
214: require(_weth != address(0), "Unset weth address");
241: require(_fee < 30, "fee must be less than 3%");
278: require(SignatureChecker.isValidSignatureNow(order.maker, orderHash, signature), "Invalid signature");
281: require(!cancelledOrders[orderHash], "Order has been cancelled");
284: require(order.whitelist.length == 0 || isWhitelisted(order.whitelist, msg.sender), "Not whitelisted");
287: require(order.duration < 10_000 days, "Duration too long");
290: require(block.timestamp < order.expiration, "Order has expired");
293: require(order.baseAsset.code.length > 0, "baseAsset is not contract");
297: ? require(floorAssetTokenIds.length == order.floorTokens.length, "Wrong amount of floor tokenIds")
298: : require(floorAssetTokenIds.length == 0, "Invalid floor tokens length");
329: require(msg.value == order.premium, "Incorrect ETH amount sent");
353: require(msg.value == order.strike, "Incorrect ETH amount sent");
395: require(ownerOf(uint256(orderHash)) == msg.sender, "Not owner");
398: require(order.isLong, "Can only exercise long positions");
401: require(block.timestamp < positionExpirations[uint256(orderHash)], "Position has expired");
405: ? require(floorAssetTokenIds.length == order.floorTokens.length, "Wrong amount of floor tokenIds")
406: : require(floorAssetTokenIds.length == 0, "Invalid floor tokenIds length");
429: require(msg.value == order.strike, "Incorrect ETH amount sent");
470: require(!order.isLong, "Must be short position");
475: require(ownerOf(uint256(orderHash)) == msg.sender, "Not owner");
481: require(block.timestamp > positionExpirations[longPositionId] || isExercised, "Must be exercised or expired");
527: require(msg.sender == order.maker, "Not your order");
551: require(orders.length == signatures.length, "Length mismatch in input");
552: require(signatures.length == floorAssetTokenIds.length, "Length mismatch in input");
598: require(token.code.length > 0, "ERC20: Token is not contract");
599: require(tokenAmount > 0, "ERC20: Amount too small");
765: require(_ownerOf[id] != address(0), "URI query for NOT_MINTED token");
make variables uninitlized to save gas
beause a variable of 0 is uninlized and saves gas instead of initizling the variable and not saving gas atall and it being the same value.
556: for (uint256 i = 0; i < orders.length; i++) {
594: for (uint256 i = 0; i < assets.length; i++) {
611: for (uint256 i = 0; i < assets.length; i++) {
627: for (uint256 i = 0; i < floorTokens.length; i++) {
637: for (uint256 i = 0; i < assets.length; i++) {
647: for (uint256 i = 0; i < assets.length; i++) {
658: for (uint256 i = 0; i < floorTokens.length; i++) {
670: for (uint256 i = 0; i < whitelist.length; i++) {
728: for (uint256 i = 0; i < arr.length; i++) {
742: for (uint256 i = 0; i < arr.length; i++) {
dont use abi.encode instead use abi.encodepacked to save gas
make require statement != 0 instead of > 0 with a uint
598: require(token.code.length > 0, "ERC20: Token is not contract");
599: require(tokenAmount > 0, "ERC20: Amount too small");
293: require(order.baseAsset.code.length > 0, "baseAsset is not contract");
instead of address(0) write it out, it saves gas
use : 0x00000000000000000000000
instead of of : address(0)
Unchecking arithmetics operations that can’t underflow/overflow
Solidity version 0.8+ comes with implicit overflow and underflow checks on unsigned integers. When an overflow or an underflow isn’t possible (as an example, when a comparison is made before the arithmetic operation), some gas can be saved by using an unchecked block: Checked or Unchecked Arithmetic. I suggest wrapping with an unchecked block:
Same thing with second unchecked because total can't overflow amount cant overflow
556: for (uint256 i = 0; i < orders.length; i++) {
594: for (uint256 i = 0; i < assets.length; i++) {
611: for (uint256 i = 0; i < assets.length; i++) {
627: for (uint256 i = 0; i < floorTokens.length; i++) {
637: for (uint256 i = 0; i < assets.length; i++) {
647: for (uint256 i = 0; i < assets.length; i++) {
658: for (uint256 i = 0; i < floorTokens.length; i++) {
670: for (uint256 i = 0; i < whitelist.length; i++) {
728: for (uint256 i = 0; i < arr.length; i++) {
742: for (uint256 i = 0; i < arr.length; i++) {
cache arrays into a variable to save gas instead of geting it length put in to variable
ex: uint line=arr.lenght;
556: for (uint256 i = 0; i < orders.length; i++) {
594: for (uint256 i = 0; i < assets.length; i++) {
611: for (uint256 i = 0; i < assets.length; i++) {
627: for (uint256 i = 0; i < floorTokens.length; i++) {
637: for (uint256 i = 0; i < assets.length; i++) {
647: for (uint256 i = 0; i < assets.length; i++) {
658: for (uint256 i = 0; i < floorTokens.length; i++) {
670: for (uint256 i = 0; i < whitelist.length; i++) {
728: for (uint256 i = 0; i < arr.length; i++) {
742: for (uint256 i = 0; i < arr.length; i++) {
1. when using keccak hash into a variable make it immutable
https://github.com/code-423n4/2022-06-putty/blob/main/contracts/src/PuttyV2.sol#L89-L101
3. make the constants private or internal to save gas when there only used in this contract
https://github.com/code-423n4/2022-06-putty/blob/main/contracts/src/PuttyV2.sol#L89-L101
dont use abi.encode or abi.encodepacked, instead use string.concat
to save gas
++i costs less gas compared to i++ or i += 1
++i costs less gas compared to i++ or i += 1 for unsigned integer, as pre-increment is cheaper (about 5 gas per iteration). This statement is true even with the optimizer enabled. i++ increments i and returns the initial value of i. Which means: uint i = 1; i++; // == 1 but i == 2 But ++i returns the actual incremented value: uint i = 1; ++i; // == 2 and i == 2 too, so no need for a temporary variable In the first case, the compiler has to create a temporary variable (when used) for returning 1 instead of 2 uint256 i = 0; i < depositedTokens.values.length; i++)
Use Custom Errors instead of Revert Strings to save Gas
Custom errors from Solidity 0.8.4 are cheaper than revert strings (cheaper deployment cost and runtime cost when the revert condition is met) Source Custom Errors in Solidity: Starting from Solidity v0.8.4, there is a convenient and gas-efficient way to explain to users why an operation failed through the use of custom errors. Until now, you could already use strings to give more information about failures (e.g., revert("Insufficient funds.");), but they are rather expensive, especially when it comes to deploy cost, and it is difficult to use dynamic information in them. Custom errors are defined using the error statement, which can be used inside and outside of contracts (including interfaces and libraries). instances include:
make variables uninitlized to save gas
beause a variable of 0 is uninlized and saves gas instead of initizling the variable and not saving gas atall and it being the same value.
dont use abi.encode instead use abi.encodepacked to save gas
make require statement != 0 instead of > 0 with a uint
instead of address(0) write it out, it saves gas
use : 0x00000000000000000000000 instead of of : address(0)
Using bools for storage incurs overhead
// 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. https://github.com/code-423n4/2022-06-putty/blob/1ddbec4a5242e0160da832cb46b2b3cdbb49a8af/contracts/src/PuttyV2.sol#L143 https://github.com/code-423n4/2022-06-putty/blob/1ddbec4a5242e0160da832cb46b2b3cdbb49a8af/contracts/src/PuttyV2.sol#L153
make memory array, instead use calldata to save gas
https://github.com/code-423n4/2022-06-putty/blob/1ddbec4a5242e0160da832cb46b2b3cdbb49a8af/contracts/src/PuttyV2.sol#L271
Unchecking arithmetics operations that can’t underflow/overflow
Solidity version 0.8+ comes with implicit overflow and underflow checks on unsigned integers. When an overflow or an underflow isn’t possible (as an example, when a comparison is made before the arithmetic operation), some gas can be saved by using an unchecked block: Checked or Unchecked Arithmetic. I suggest wrapping with an unchecked block: Same thing with second unchecked because total can't overflow amount cant overflow
cache arrays into a variable to save gas instead of geting it length put in to variable
ex: uint line=arr.lenght;