Putty contest - z3s's results

An order-book based american options market for NFTs and ERC20s.

General Information

Platform: Code4rena

Start Date: 29/06/2022

Pot Size: $50,000 USDC

Total HM: 20

Participants: 133

Period: 5 days

Judge: hickuphh3

Total Solo HM: 1

Id: 142

League: ETH

Putty

Findings Distribution

Researcher Performance

Rank: 109/133

Findings: 1

Award: $21.18

🌟 Selected for report: 0

🚀 Solo Findings: 0

Gas Optimizations

[G01] state variables should be cached:

Caching will replace each SLOAD (100 gas) with a much cheaper stack read.

cache weth:

PuttyV2.sol::fillOrder() 327,17: if (weth == order.baseAsset && msg.value > 0) { 335,23: IWETH(weth).deposit{value: msg.value}(); 336,23: IWETH(weth).transfer(order.maker, msg.value); 351,17: if (weth == order.baseAsset && msg.value > 0) { 358,18: IWETH(weth).deposit{value: msg.value}();
PuttyV2.sol::exercise() 427,17: if (weth == order.baseAsset && msg.value > 0) { 434,18: IWETH(weth).deposit{value: msg.value}();

cache fee:

PuttyV2.sol 498,17: if (fee > 0) { 499,45: feeAmount = (order.strike * fee) / 1000;

[G02] ++i is cheaper than i++:

actually it's important in iterations. It's better to use unchecked { ++i; }

PuttyV2.sol 556,39: for (uint256 i = 0; i < orders.length; i++) { 594,39: for (uint256 i = 0; i < assets.length; i++) { 611,39: for (uint256 i = 0; i < assets.length; i++) { 627,44: for (uint256 i = 0; i < floorTokens.length; i++) { 637,39: for (uint256 i = 0; i < assets.length; i++) { 647,39: for (uint256 i = 0; i < assets.length; i++) { 658,44: for (uint256 i = 0; i < floorTokens.length; i++) { 670,42: for (uint256 i = 0; i < whitelist.length; i++) { 728,36: for (uint256 i = 0; i < arr.length; i++) { 742,36: for (uint256 i = 0; i < arr.length; i++) {

[G03] uint256 default value is 0 so we can remove = 0 for saving some gas:

PuttyV2.sol 497,31: uint256 feeAmount = 0; 556,24: for (uint256 i = 0; i < orders.length; i++) { 594,24: for (uint256 i = 0; i < assets.length; i++) { 611,24: for (uint256 i = 0; i < assets.length; i++) { 627,24: for (uint256 i = 0; i < floorTokens.length; i++) { 637,24: for (uint256 i = 0; i < assets.length; i++) { 647,24: for (uint256 i = 0; i < assets.length; i++) { 658,24: for (uint256 i = 0; i < floorTokens.length; i++) { 670,24: for (uint256 i = 0; i < whitelist.length; i++) { 728,24: for (uint256 i = 0; i < arr.length; i++) { 742,24: for (uint256 i = 0; i < arr.length; i++) {

[G04] cache <array>.length:

Even memory arrays incur the overhead of bit tests and bit shifts to calculate the array length.

PuttyV2.sol 556,39: for (uint256 i = 0; i < orders.length; i++) { 594,39: for (uint256 i = 0; i < assets.length; i++) { 611,39: for (uint256 i = 0; i < assets.length; i++) { 627,44: for (uint256 i = 0; i < floorTokens.length; i++) { 637,39: for (uint256 i = 0; i < assets.length; i++) { 647,39: for (uint256 i = 0; i < assets.length; i++) { 658,44: for (uint256 i = 0; i < floorTokens.length; i++) { 670,42: for (uint256 i = 0; i < whitelist.length; i++) { 728,36: for (uint256 i = 0; i < arr.length; i++) { 742,36: for (uint256 i = 0; i < arr.length; i++) {

[G05] Expressions for constant values such as a call to keccak256(), should use immutable rather than constant:

See this issue for a detail description of the issue

PuttyV2.sol 90,9: keccak256(abi.encodePacked("ERC721Asset(address token,uint256 tokenId)")); 96,9: keccak256(abi.encodePacked("ERC20Asset(address token,uint256 tokenAmount)")); 102,9: keccak256(

[G06] 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/

PuttyV2.sol 214,9: require(_weth != address(0), "Unset weth address"); 241,9: require(_fee < 30, "fee must be less than 3%"); 278,9: require(SignatureChecker.isValidSignatureNow(order.maker, orderHash, signature), "Invalid signature"); 281,9: require(!cancelledOrders[orderHash], "Order has been cancelled"); 284,9: require(order.whitelist.length == 0 || isWhitelisted(order.whitelist, msg.sender), "Not whitelisted"); 287,9: require(order.duration < 10_000 days, "Duration too long"); 290,9: require(block.timestamp < order.expiration, "Order has expired"); 293,9: require(order.baseAsset.code.length > 0, "baseAsset is not contract"); 297,15: ? require(floorAssetTokenIds.length == order.floorTokens.length, "Wrong amount of floor tokenIds") 298,15: : require(floorAssetTokenIds.length == 0, "Invalid floor tokens length"); 329,17: require(msg.value == order.premium, "Incorrect ETH amount sent"); 353,17: require(msg.value == order.strike, "Incorrect ETH amount sent"); 395,9: require(ownerOf(uint256(orderHash)) == msg.sender, "Not owner"); 398,9: require(order.isLong, "Can only exercise long positions"); 401,9: require(block.timestamp < positionExpirations[uint256(orderHash)], "Position has expired"); 405,15: ? require(floorAssetTokenIds.length == order.floorTokens.length, "Wrong amount of floor tokenIds") 406,15: : require(floorAssetTokenIds.length == 0, "Invalid floor tokenIds length"); 429,17: require(msg.value == order.strike, "Incorrect ETH amount sent"); 470,9: require(!order.isLong, "Must be short position"); 475,9: require(ownerOf(uint256(orderHash)) == msg.sender, "Not owner"); 481,9: require(block.timestamp > positionExpirations[longPositionId] || isExercised, "Must be exercised or expired"); 527,9: require(msg.sender == order.maker, "Not your order"); 551,9: require(orders.length == signatures.length, "Length mismatch in input"); 552,9: require(signatures.length == floorAssetTokenIds.length, "Length mismatch in input"); 598,13: require(token.code.length > 0, "ERC20: Token is not contract"); 599,13: require(tokenAmount > 0, "ERC20: Amount too small"); 765,9: require(_ownerOf[id] != address(0), "URI query for NOT_MINTED token"); PuttyV2Nft.sol 12,9: require(to != address(0), "INVALID_RECIPIENT"); 13,9: require(_ownerOf[id] == address(0), "ALREADY_MINTED"); 26,9: require(from == _ownerOf[id], "WRONG_FROM"); 27,9: require(to != address(0), "INVALID_RECIPIENT"); 28,9: require( 41,9: require(owner != address(0), "ZERO_ADDRESS");
AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter