bytes32 orderHash = hashOrder(order);
// check user owns the position
require(ownerOf(uint256(orderHash)) == msg.sender, "Not owner");
// check position is long
require(order.isLong, "Can only exercise long positions");
Re-order conditions in require statements
Conditions in require statement can be re-ordered so that if position is exercised it consumes less gas
require(block.timestamp > positionExpirations[longPositionId] || isExercised, "Must be exercised or expired");
can be changed to
require(isExercised || block.timestamp > positionExpirations[longPositionId], "Must be exercised or expired");
Optimize for loops
variables initialization with default values(0) can be avoided as it already contains default values,
order length can be cached in a variables and re-used instead of querying length in every iteration,
post-increment can be replaced with pre-increment ++i and unchecked can be added to save gas
L556: for (uint256 i = 0; i < orders.length; i++) {
L594: for (uint256 i = 0; i < assets.length; i++) {
L611: for (uint256 i = 0; i < assets.length; i++) {
L627: for (uint256 i = 0; i < floorTokens.length; i++) {
L637: for (uint256 i = 0; i < assets.length; i++) {
L647: for (uint256 i = 0; i < floorTokens.length; i++) {
L658: for (uint256 i = 0; i < floorTokens.length; i++) {
L670: for (uint256 i = 0; i < whitelist.length; i++) {
L728: for (uint256 i = 0; i < arr.length; i++) {
L742: for (uint256 i = 0; i < arr.length; i++) {
Public function can be external
Public functions that are not called inside the contract can be converted to external
Unused
order.expiration
position expiration value is calculated by adding block.timestamp and duration, order's expiration value is not used
Proof of concept
https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L290
https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L710
constant variables can be changed to private
constant variable can be changed from public to internal visibility to avoid getter function
Proof of concept
https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L89
https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L95
https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L101
Re-order require statements
require statements can be reordered to save gas on revert
Proof of concept
https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L398
isLong condition can be placed on the top
Re-order conditions in require statements
Conditions in require statement can be re-ordered so that if position is exercised it consumes less gas
Proof of concept
https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L481
can be changed to
Optimize for loops
variables initialization with default values(0) can be avoided as it already contains default values, order length can be cached in a variables and re-used instead of querying length in every iteration, post-increment can be replaced with pre-increment ++i and unchecked can be added to save gas
Proof of concept
https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#
Public function can be external
Public functions that are not called inside the contract can be converted to external
Proof of concept
https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L753
https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L764