code-423n4 / 2022-06-putty-findings

5 stars 0 forks source link

Gas Optimizations #335

Open code423n4 opened 2 years ago

code423n4 commented 2 years ago

Unused order.expiration

position expiration value is calculated by adding block.timestamp and duration, order's expiration value is not used

Proof of concept

    positionExpirations[order.isLong ? uint256(orderHash) : positionId] = block.timestamp + order.duration;

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

    bytes32 public constant ERC721ASSET_TYPE_HASH =
        keccak256(abi.encodePacked("ERC721Asset(address token,uint256 tokenId)"));  

https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L95

    bytes32 public constant ERC20ASSET_TYPE_HASH =
        keccak256(abi.encodePacked("ERC20Asset(address token,uint256 tokenAmount)"));

https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L101

    bytes32 public constant ORDER_TYPE_HASH 

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

    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

Proof of concept

https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L481

    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

Proof of concept

https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#

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

Proof of concept

https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L753

    function domainSeparatorV4() public view returns (bytes32) {
        return _domainSeparatorV4();
    }

https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L764

    function tokenURI(uint256 id) public view override returns (string memory) {