From 61c25489ba59502237eddd5008ee58527c4fb514 Mon Sep 17 00:00:00 2001 From: "jtriley.eth" Date: Fri, 3 May 2024 14:45:29 -0700 Subject: [PATCH] add security review --- .../lightchaser/v0.1.0-response-04-20-2024.md | 67 + .../lightchaser/v0.1.0-review-04-20-2024.md | 1993 +++++++++++++++++ 2 files changed, 2060 insertions(+) create mode 100644 security-review/lightchaser/v0.1.0-response-04-20-2024.md create mode 100644 security-review/lightchaser/v0.1.0-review-04-20-2024.md diff --git a/security-review/lightchaser/v0.1.0-response-04-20-2024.md b/security-review/lightchaser/v0.1.0-response-04-20-2024.md new file mode 100644 index 0000000..21d11b7 --- /dev/null +++ b/security-review/lightchaser/v0.1.0-response-04-20-2024.md @@ -0,0 +1,67 @@ +# Light Chaser V3 Security Review Response + +## Low + +### 1. Solidity version 0.8.20 won't work on all chains due to PUSH0 + +Acknowledged. ERC721 uses `mcopy`, so 0.8.25 is required, as is EVM Cancun. + +## NonCritical + +### 1. Floating pragma should be avoided + +This is a library rather than a final contract, so floating pragma is preferred. + +### 2. Explicitly define visibility of functions to prevent misconceptions on what can access the function + +These are only free functions, so visibility is disallowed by the compiler. + +### 3. Assembly block creates dirty bits + +The lack of 'memory-safe' modifiers to assembly blocks is due to overwriting the upper bits of the free memory pointer. + +The upper bits are restored to zero but truth be told, I have no idea if this techincally violates the memory-safe ruleset because the documentation does not specify this edge case and memory-safe violations is undefined behavior. So in abundance of caution, memory-safe will only be used where it is guaranteed to not violate the ruleset. + +### 4. .call bypasses function existence check, type checking and argument packing + +There are nonzero returndatasize checks on calls to validate the contract's existence (except erc20 due to USDT). There is some indirection here by deferring checks for gas optimization though. + +In either case, acknowledged. + +### 5. Missing events in sensitive functions + +This only triggered once and most functions are technically stateful in that an external call is made, though the types never mutate local storage. This may be a false positive. + +### 6. All verbatim blocks are considered identical by deduplicator and can incorrectly be unified + +There is no verbatim block I'm aware of. + +### 7. Avoid using 'owner' or '\_owner' as a parameter name + +Good point, though `owner` in most cases is a reference to the specification. Will review. + +### 8. Memory-safe annotation missing + +These hits appear to be on assembly blocks with no memory access. Is this still required without memory accesses? The documentation doesn't clearly say one way or the other. + +## Gas + +### 1. Assembly let var only used on once + +There are a few cases of this that went unnoticed, though the optimizer inlines these variables. + +However, it's worth noting that the hit this tool generated points to a free memory pointer access before overwriting it. ie the following procedures _must_ be in this exact order and the variable _must_ be assigned if only once for the sake of restoring the free memory pointer. It may be worth adding a check to handle cases where the expressions between the variable assignment and variable usage affect the data location from which the variable originates. + +```solidity +let fmp := mload(0x40) + +// -- snip + +mstore(0x24, receiver) + +mstore(0x44, tokenId) + +// -- snip + +mstore(0x40, fmp) +``` diff --git a/security-review/lightchaser/v0.1.0-review-04-20-2024.md b/security-review/lightchaser/v0.1.0-review-04-20-2024.md new file mode 100644 index 0000000..75f33ef --- /dev/null +++ b/security-review/lightchaser/v0.1.0-review-04-20-2024.md @@ -0,0 +1,1993 @@ +## LightChaser-V3 + +### Generated for: jtriley : token-types + +### Generated on: 2024-04-20 + +## Total findings: 10 + +### Total Low findings: 1 + +### Total Gas findings: 1 + +### Total NonCritical findings: 8 + +## Disclaimer + +Please read this disclaimer carefully before using the LightChaser-V3 Report provided. By accessing and using this Report, you acknowledge and agree to the terms outlined below: The Report is not a confirmation of security; it is designed to help identify potential vulnerabilities based on automated algorithms and does not cover all issues within your codebase. The presence or absence of issues identified does not guarantee security. Recommendations and resolutions are generated automatically and should not be implemented without expert review. This Report is one aspect of a holistic security approach; we recommend incorporating manual reviews, third-party audits, competitive audit platforms, and bug bounties. We are not responsible for any losses or damages arising from the use of this Report; it is provided "as is" without warranty. Reliance on this Report is at your own risk. + +# Summary for Low findings + +| Number | Details | Instances | +| ------- | ------------------------------------------------------------- | --------- | +| [Low-1] | Solidity version 0.8.20 won't work on all chains due to PUSH0 | 1 | + +# Summary for NonCritical findings + +| Number | Details | Instances | +| --------------- | --------------------------------------------------------------------------------------------------- | --------- | +| [NonCritical-1] | Floating pragma should be avoided | 1 | +| [NonCritical-2] | Explicitly define visibility of functions to prevent misconceptions on what can access the function | 138 | +| [NonCritical-3] | Assembly block creates dirty bits | 12 | +| [NonCritical-4] | .call bypasses function existence check, type checking and argument packing | 16 | +| [NonCritical-5] | Missing events in sensitive functions | 1 | +| [NonCritical-6] | All verbatim blocks are considered identical by deduplicator and can incorrectly be unified | 1 | +| [NonCritical-7] | Avoid using 'owner' or '\_owner' as a parameter name | 13 | +| [NonCritical-8] | Memory-safe annotation missing | 19 | + +# Summary for Gas findings + +| Number | Details | Instances | Gas | +| ------- | ---------------------------------- | --------- | --- | +| [Gas-1] | Assembly let var only used on once | 1 | 0.0 | + +## [Low-1] Solidity version 0.8.20 won't work on all chains due to PUSH0 + +### Resolution + +Solidity version 0.8.20 uses the new Shanghai EVM which introduces the PUSH0 opcode, this may not be implemented on all chains and L2 thus reducing the portability and compatability of the code. Consider using a earlier solidity version. + +Num of instances: 1 + +### Findings + +
Click to show findings + +['[2](ERC165.sol: 2-2)'] + +```solidity +2: pragma solidity ^0.8.25; // <= FOUND +``` + +
+ +## [NonCritical-1] Floating pragma should be avoided + +Num of instances: 1 + +### Findings + +
Click to show findings + +['[2](ERC165.sol: 2-2)'] + +```solidity +2: pragma solidity ^0.8.25; // <= FOUND +``` + +
+ +## [NonCritical-2] Explicitly define visibility of functions to prevent misconceptions on what can access the function + +### Resolution + +Such functions should be marked as public as this is the default visibility + +Num of instances: 138 + +### Findings + +
Click to show findings + +['[42](ERC165.sol: 42-42)'] + +```solidity +42: function supportsInterface(ERC165 erc165, bytes4 interfaceId) view returns (bool output) +``` + +['[60](ERC165.sol: 60-60)'] + +```solidity +60: function eq(ERC165 lhs, ERC165 rhs) pure returns (bool output) +``` + +['[68](ERC165.sol: 68-68)'] + +```solidity +68: function neq(ERC165 lhs, ERC165 rhs) pure returns (bool output) +``` + +['[76](ERC165.sol: 76-76)'] + +```solidity +76: function gt(ERC165 lhs, ERC165 rhs) pure returns (bool output) +``` + +['[84](ERC165.sol: 84-84)'] + +```solidity +84: function gte(ERC165 lhs, ERC165 rhs) pure returns (bool output) +``` + +['[92](ERC165.sol: 92-92)'] + +```solidity +92: function lt(ERC165 lhs, ERC165 rhs) pure returns (bool output) +``` + +['[100](ERC165.sol: 100-100)'] + +```solidity +100: function lte(ERC165 lhs, ERC165 rhs) pure returns (bool output) +``` + +['[108](ERC165.sol: 108-108)'] + +```solidity +108: function add(ERC165 lhs, ERC165 rhs) pure returns (ERC165 output) +``` + +['[117](ERC165.sol: 117-117)'] + +```solidity +117: function sub(ERC165 lhs, ERC165 rhs) pure returns (ERC165 output) +``` + +['[126](ERC165.sol: 126-126)'] + +```solidity +126: function mul(ERC165 lhs, ERC165 rhs) pure returns (ERC165 output) +``` + +['[137](ERC165.sol: 137-137)'] + +```solidity +137: function div(ERC165 lhs, ERC165 rhs) pure returns (ERC165 output) +``` + +['[146](ERC165.sol: 146-146)'] + +```solidity +146: function mod(ERC165 lhs, ERC165 rhs) pure returns (ERC165 output) +``` + +['[155](ERC165.sol: 155-155)'] + +```solidity +155: function and(ERC165 lhs, ERC165 rhs) pure returns (ERC165 output) +``` + +['[163](ERC165.sol: 163-163)'] + +```solidity +163: function or(ERC165 lhs, ERC165 rhs) pure returns (ERC165 output) +``` + +['[171](ERC165.sol: 171-171)'] + +```solidity +171: function xor(ERC165 lhs, ERC165 rhs) pure returns (ERC165 output) +``` + +['[179](ERC165.sol: 179-179)'] + +```solidity +179: function not(ERC165 lhs) pure returns (ERC165 output) +``` + +['[46](ERC20.sol: 46-46)'] + +```solidity +46: function totalSupply(ERC20 erc20) view returns (uint256 output) +``` + +['[70](ERC20.sol: 70-70)'] + +```solidity +70: function balanceOf(ERC20 erc20, address owner) view returns (uint256 output) +``` + +['[97](ERC20.sol: 97-97)'] + +```solidity +97: function allowance(ERC20 erc20, address owner, address spender) view returns (uint256 output) +``` + +['[128](ERC20.sol: 128-128)'] + +```solidity +128: function transfer(ERC20 erc20, address receiver, uint256 amount) +``` + +['[160](ERC20.sol: 160-160)'] + +```solidity +160: function transferFrom(ERC20 erc20, address sender, address receiver, uint256 amount) +``` + +['[195](ERC20.sol: 195-195)'] + +```solidity +195: function approve(ERC20 erc20, address spender, uint256 amount) +``` + +['[215](ERC20.sol: 215-215)'] + +```solidity +215: function eq(ERC20 lhs, ERC20 rhs) pure returns (bool output) +``` + +['[223](ERC20.sol: 223-223)'] + +```solidity +223: function neq(ERC20 lhs, ERC20 rhs) pure returns (bool output) +``` + +['[231](ERC20.sol: 231-231)'] + +```solidity +231: function gt(ERC20 lhs, ERC20 rhs) pure returns (bool output) +``` + +['[239](ERC20.sol: 239-239)'] + +```solidity +239: function gte(ERC20 lhs, ERC20 rhs) pure returns (bool output) +``` + +['[247](ERC20.sol: 247-247)'] + +```solidity +247: function lt(ERC20 lhs, ERC20 rhs) pure returns (bool output) +``` + +['[255](ERC20.sol: 255-255)'] + +```solidity +255: function lte(ERC20 lhs, ERC20 rhs) pure returns (bool output) +``` + +['[263](ERC20.sol: 263-263)'] + +```solidity +263: function add(ERC20 lhs, ERC20 rhs) pure returns (ERC20 output) +``` + +['[272](ERC20.sol: 272-272)'] + +```solidity +272: function sub(ERC20 lhs, ERC20 rhs) pure returns (ERC20 output) +``` + +['[281](ERC20.sol: 281-281)'] + +```solidity +281: function mul(ERC20 lhs, ERC20 rhs) pure returns (ERC20 output) +``` + +['[292](ERC20.sol: 292-292)'] + +```solidity +292: function div(ERC20 lhs, ERC20 rhs) pure returns (ERC20 output) +``` + +['[301](ERC20.sol: 301-301)'] + +```solidity +301: function mod(ERC20 lhs, ERC20 rhs) pure returns (ERC20 output) +``` + +['[310](ERC20.sol: 310-310)'] + +```solidity +310: function and(ERC20 lhs, ERC20 rhs) pure returns (ERC20 output) +``` + +['[318](ERC20.sol: 318-318)'] + +```solidity +318: function or(ERC20 lhs, ERC20 rhs) pure returns (ERC20 output) +``` + +['[326](ERC20.sol: 326-326)'] + +```solidity +326: function xor(ERC20 lhs, ERC20 rhs) pure returns (ERC20 output) +``` + +['[334](ERC20.sol: 334-334)'] + +```solidity +334: function not(ERC20 lhs) pure returns (ERC20 output) +``` + +['[62](ERC4626.sol: 62-62)'] + +```solidity +62: function asset(ERC4626 erc4626) view returns (address output) +``` + +['[85](ERC4626.sol: 85-85)'] + +```solidity +85: function totalAssets(ERC4626 erc4626) view returns (uint256 output) +``` + +['[109](ERC4626.sol: 109-109)'] + +```solidity +109: function convertToShares(ERC4626 erc4626, uint256 assets) view returns (uint256 output) +``` + +['[135](ERC4626.sol: 135-135)'] + +```solidity +135: function convertToAssets(ERC4626 erc4626, uint256 shares) view returns (uint256 output) +``` + +['[161](ERC4626.sol: 161-161)'] + +```solidity +161: function maxDeposit(ERC4626 erc4626, address receiver) view returns (uint256 output) +``` + +['[187](ERC4626.sol: 187-187)'] + +```solidity +187: function previewDeposit(ERC4626 erc4626, uint256 assets) view returns (uint256 output) +``` + +['[215](ERC4626.sol: 215-215)'] + +```solidity +215: function deposit(ERC4626 erc4626, uint256 assets, address receiver) returns (uint256 output) +``` + +['[245](ERC4626.sol: 245-245)'] + +```solidity +245: function maxMint(ERC4626 erc4626, address receiver) view returns (uint256 output) +``` + +['[271](ERC4626.sol: 271-271)'] + +```solidity +271: function previewMint(ERC4626 erc4626, uint256 shares) view returns (uint256 output) +``` + +['[299](ERC4626.sol: 299-299)'] + +```solidity +299: function mint(ERC4626 erc4626, uint256 shares, address receiver) returns (uint256 output) +``` + +['[329](ERC4626.sol: 329-329)'] + +```solidity +329: function maxWithdraw(ERC4626 erc4626, address owner) view returns (uint256 output) +``` + +['[355](ERC4626.sol: 355-355)'] + +```solidity +355: function previewWithdraw(ERC4626 erc4626, uint256 assets) view returns (uint256 output) +``` + +['[386](ERC4626.sol: 386-386)'] + +```solidity +386: function withdraw(ERC4626 erc4626, uint256 assets, address receiver, address owner) returns (uint256 output) +``` + +['[422](ERC4626.sol: 422-422)'] + +```solidity +422: function maxRedeem(ERC4626 erc4626, address owner) view returns (uint256 output) +``` + +['[448](ERC4626.sol: 448-448)'] + +```solidity +448: function previewRedeem(ERC4626 erc4626, uint256 shares) view returns (uint256 output) +``` + +['[479](ERC4626.sol: 479-479)'] + +```solidity +479: function redeem(ERC4626 erc4626, uint256 shares, address receiver, address owner) returns (uint256 output) +``` + +['[514](ERC4626.sol: 514-514)'] + +```solidity +514: function totalSupply(ERC4626 erc4626) view returns (uint256 output) +``` + +['[538](ERC4626.sol: 538-538)'] + +```solidity +538: function balanceOf(ERC4626 erc4626, address owner) view returns (uint256 output) +``` + +['[566](ERC4626.sol: 566-566)'] + +```solidity +566: function allowance(ERC4626 erc4626, address owner, address spender) view returns (uint256 output) +``` + +['[597](ERC4626.sol: 597-597)'] + +```solidity +597: function transfer(ERC4626 erc4626, address receiver, uint256 amount) +``` + +['[629](ERC4626.sol: 629-629)'] + +```solidity +629: function transferFrom(ERC4626 erc4626, address sender, address receiver, uint256 amount) +``` + +['[664](ERC4626.sol: 664-664)'] + +```solidity +664: function approve(ERC4626 erc4626, address spender, uint256 amount) +``` + +['[684](ERC4626.sol: 684-684)'] + +```solidity +684: function eq(ERC4626 lhs, ERC4626 rhs) pure returns (bool output) +``` + +['[692](ERC4626.sol: 692-692)'] + +```solidity +692: function neq(ERC4626 lhs, ERC4626 rhs) pure returns (bool output) +``` + +['[700](ERC4626.sol: 700-700)'] + +```solidity +700: function gt(ERC4626 lhs, ERC4626 rhs) pure returns (bool output) +``` + +['[708](ERC4626.sol: 708-708)'] + +```solidity +708: function gte(ERC4626 lhs, ERC4626 rhs) pure returns (bool output) +``` + +['[716](ERC4626.sol: 716-716)'] + +```solidity +716: function lt(ERC4626 lhs, ERC4626 rhs) pure returns (bool output) +``` + +['[724](ERC4626.sol: 724-724)'] + +```solidity +724: function lte(ERC4626 lhs, ERC4626 rhs) pure returns (bool output) +``` + +['[732](ERC4626.sol: 732-732)'] + +```solidity +732: function add(ERC4626 lhs, ERC4626 rhs) pure returns (ERC4626 output) +``` + +['[741](ERC4626.sol: 741-741)'] + +```solidity +741: function sub(ERC4626 lhs, ERC4626 rhs) pure returns (ERC4626 output) +``` + +['[750](ERC4626.sol: 750-750)'] + +```solidity +750: function mul(ERC4626 lhs, ERC4626 rhs) pure returns (ERC4626 output) +``` + +['[761](ERC4626.sol: 761-761)'] + +```solidity +761: function div(ERC4626 lhs, ERC4626 rhs) pure returns (ERC4626 output) +``` + +['[770](ERC4626.sol: 770-770)'] + +```solidity +770: function mod(ERC4626 lhs, ERC4626 rhs) pure returns (ERC4626 output) +``` + +['[779](ERC4626.sol: 779-779)'] + +```solidity +779: function and(ERC4626 lhs, ERC4626 rhs) pure returns (ERC4626 output) +``` + +['[787](ERC4626.sol: 787-787)'] + +```solidity +787: function or(ERC4626 lhs, ERC4626 rhs) pure returns (ERC4626 output) +``` + +['[795](ERC4626.sol: 795-795)'] + +```solidity +795: function xor(ERC4626 lhs, ERC4626 rhs) pure returns (ERC4626 output) +``` + +['[803](ERC4626.sol: 803-803)'] + +```solidity +803: function not(ERC4626 lhs) pure returns (ERC4626 output) +``` + +['[49](ERC6909.sol: 49-49)'] + +```solidity +49: function supportsInterface(ERC6909 erc6909, bytes4 interfaceId) view returns (bool output) +``` + +['[77](ERC6909.sol: 77-77)'] + +```solidity +77: function balanceOf(ERC6909 erc6909, address owner, uint256 id) view returns (uint256 output) +``` + +['[112](ERC6909.sol: 112-112)'] + +```solidity +112: function allowance(ERC6909 erc6909, address owner, address spender, uint256 id) view returns (uint256 output) +``` + +['[150](ERC6909.sol: 150-150)'] + +```solidity +150: function isOperator(ERC6909 erc6909, address owner, address spender) view returns (bool output) +``` + +['[185](ERC6909.sol: 185-185)'] + +```solidity +185: function transfer(ERC6909 erc6909, address receiver, uint256 id, uint256 amount) +``` + +['[229](ERC6909.sol: 229-229)'] + +```solidity +229: function transferFrom(ERC6909 erc6909, address sender, address receiver, uint256 id, uint256 amount) +``` + +['[276](ERC6909.sol: 276-276)'] + +```solidity +276: function approve(ERC6909 erc6909, address spender, uint256 id, uint256 amount) +``` + +['[314](ERC6909.sol: 314-314)'] + +```solidity +314: function setOperator(ERC6909 erc6909, address spender, bool approved) +``` + +['[336](ERC6909.sol: 336-336)'] + +```solidity +336: function eq(ERC6909 lhs, ERC6909 rhs) pure returns (bool output) +``` + +['[344](ERC6909.sol: 344-344)'] + +```solidity +344: function neq(ERC6909 lhs, ERC6909 rhs) pure returns (bool output) +``` + +['[352](ERC6909.sol: 352-352)'] + +```solidity +352: function gt(ERC6909 lhs, ERC6909 rhs) pure returns (bool output) +``` + +['[360](ERC6909.sol: 360-360)'] + +```solidity +360: function gte(ERC6909 lhs, ERC6909 rhs) pure returns (bool output) +``` + +['[368](ERC6909.sol: 368-368)'] + +```solidity +368: function lt(ERC6909 lhs, ERC6909 rhs) pure returns (bool output) +``` + +['[376](ERC6909.sol: 376-376)'] + +```solidity +376: function lte(ERC6909 lhs, ERC6909 rhs) pure returns (bool output) +``` + +['[384](ERC6909.sol: 384-384)'] + +```solidity +384: function add(ERC6909 lhs, ERC6909 rhs) pure returns (ERC6909 output) +``` + +['[393](ERC6909.sol: 393-393)'] + +```solidity +393: function sub(ERC6909 lhs, ERC6909 rhs) pure returns (ERC6909 output) +``` + +['[402](ERC6909.sol: 402-402)'] + +```solidity +402: function mul(ERC6909 lhs, ERC6909 rhs) pure returns (ERC6909 output) +``` + +['[413](ERC6909.sol: 413-413)'] + +```solidity +413: function div(ERC6909 lhs, ERC6909 rhs) pure returns (ERC6909 output) +``` + +['[422](ERC6909.sol: 422-422)'] + +```solidity +422: function mod(ERC6909 lhs, ERC6909 rhs) pure returns (ERC6909 output) +``` + +['[431](ERC6909.sol: 431-431)'] + +```solidity +431: function and(ERC6909 lhs, ERC6909 rhs) pure returns (ERC6909 output) +``` + +['[439](ERC6909.sol: 439-439)'] + +```solidity +439: function or(ERC6909 lhs, ERC6909 rhs) pure returns (ERC6909 output) +``` + +['[447](ERC6909.sol: 447-447)'] + +```solidity +447: function xor(ERC6909 lhs, ERC6909 rhs) pure returns (ERC6909 output) +``` + +['[455](ERC6909.sol: 455-455)'] + +```solidity +455: function not(ERC6909 lhs) pure returns (ERC6909 output) +``` + +['[50](ERC721.sol: 50-50)'] + +```solidity +50: function supportsInterface(ERC721 erc721, bytes4 interfaceId) view returns (bool output) +``` + +['[76](ERC721.sol: 76-76)'] + +```solidity +76: function getApproved(ERC721 erc721, uint256 tokenId) view returns (address output) +``` + +['[104](ERC721.sol: 104-104)'] + +```solidity +104: function isApprovedForAll(ERC721 erc721, address owner, address operator) view returns (bool output) +``` + +['[134](ERC721.sol: 134-134)'] + +```solidity +134: function balanceOf(ERC721 erc721, address owner) view returns (uint256 output) +``` + +['[160](ERC721.sol: 160-160)'] + +```solidity +160: function ownerOf(ERC721 erc721, uint256 tokenId) view returns (address output) +``` + +['[205](ERC721.sol: 205-205)'] + +```solidity +205: function safeTransferFrom(ERC721 erc721, address sender, address receiver, uint256 tokenId, bytes memory data) +``` + +['[257](ERC721.sol: 257-257)'] + +```solidity +257: function transferFrom(ERC721 erc721, address sender, address receiver, uint256 tokenId) +``` + +['[286](ERC721.sol: 286-286)'] + +```solidity +286: function approve(ERC721 erc721, address operator, uint256 tokenId) +``` + +['[309](ERC721.sol: 309-309)'] + +```solidity +309: function setApprovalForAll(ERC721 erc721, address operator, bool approved) +``` + +['[325](ERC721.sol: 325-325)'] + +```solidity +325: function eq(ERC721 lhs, ERC721 rhs) pure returns (bool output) +``` + +['[333](ERC721.sol: 333-333)'] + +```solidity +333: function neq(ERC721 lhs, ERC721 rhs) pure returns (bool output) +``` + +['[341](ERC721.sol: 341-341)'] + +```solidity +341: function gt(ERC721 lhs, ERC721 rhs) pure returns (bool output) +``` + +['[349](ERC721.sol: 349-349)'] + +```solidity +349: function gte(ERC721 lhs, ERC721 rhs) pure returns (bool output) +``` + +['[357](ERC721.sol: 357-357)'] + +```solidity +357: function lt(ERC721 lhs, ERC721 rhs) pure returns (bool output) +``` + +['[365](ERC721.sol: 365-365)'] + +```solidity +365: function lte(ERC721 lhs, ERC721 rhs) pure returns (bool output) +``` + +['[373](ERC721.sol: 373-373)'] + +```solidity +373: function add(ERC721 lhs, ERC721 rhs) pure returns (ERC721 output) +``` + +['[383](ERC721.sol: 383-383)'] + +```solidity +383: function sub(ERC721 lhs, ERC721 rhs) pure returns (ERC721 output) +``` + +['[393](ERC721.sol: 393-393)'] + +```solidity +393: function mul(ERC721 lhs, ERC721 rhs) pure returns (ERC721 output) +``` + +['[405](ERC721.sol: 405-405)'] + +```solidity +405: function div(ERC721 lhs, ERC721 rhs) pure returns (ERC721 output) +``` + +['[414](ERC721.sol: 414-414)'] + +```solidity +414: function mod(ERC721 lhs, ERC721 rhs) pure returns (ERC721 output) +``` + +['[424](ERC721.sol: 424-424)'] + +```solidity +424: function and(ERC721 lhs, ERC721 rhs) pure returns (ERC721 output) +``` + +['[432](ERC721.sol: 432-432)'] + +```solidity +432: function or(ERC721 lhs, ERC721 rhs) pure returns (ERC721 output) +``` + +['[440](ERC721.sol: 440-440)'] + +```solidity +440: function xor(ERC721 lhs, ERC721 rhs) pure returns (ERC721 output) +``` + +['[448](ERC721.sol: 448-448)'] + +```solidity +448: function not(ERC721 lhs) pure returns (ERC721 output) +``` + +['[55](ERC721Receiver.sol: 55-55)'] + +```solidity +55: function onERC721Received(ERC721Receiver receiver, address operator, address sender, uint256 id) +``` + +['[105](ERC721Receiver.sol: 105-105)'] + +```solidity +105: function onERC721ReceivedWithData( +106: ERC721Receiver receiver, +107: address operator, +108: address sender, +109: uint256 id, +110: bytes calldata data +111: ) +``` + +['[143](ERC721Receiver.sol: 143-143)'] + +```solidity +143: function eq(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (bool output) +``` + +['[151](ERC721Receiver.sol: 151-151)'] + +```solidity +151: function neq(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (bool output) +``` + +['[159](ERC721Receiver.sol: 159-159)'] + +```solidity +159: function gt(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (bool output) +``` + +['[167](ERC721Receiver.sol: 167-167)'] + +```solidity +167: function gte(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (bool output) +``` + +['[175](ERC721Receiver.sol: 175-175)'] + +```solidity +175: function lt(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (bool output) +``` + +['[183](ERC721Receiver.sol: 183-183)'] + +```solidity +183: function lte(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (bool output) +``` + +['[191](ERC721Receiver.sol: 191-191)'] + +```solidity +191: function add(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (ERC721Receiver output) +``` + +['[200](ERC721Receiver.sol: 200-200)'] + +```solidity +200: function sub(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (ERC721Receiver output) +``` + +['[209](ERC721Receiver.sol: 209-209)'] + +```solidity +209: function mul(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (ERC721Receiver output) +``` + +['[220](ERC721Receiver.sol: 220-220)'] + +```solidity +220: function div(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (ERC721Receiver output) +``` + +['[229](ERC721Receiver.sol: 229-229)'] + +```solidity +229: function mod(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (ERC721Receiver output) +``` + +['[238](ERC721Receiver.sol: 238-238)'] + +```solidity +238: function and(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (ERC721Receiver output) +``` + +['[246](ERC721Receiver.sol: 246-246)'] + +```solidity +246: function or(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (ERC721Receiver output) +``` + +['[254](ERC721Receiver.sol: 254-254)'] + +```solidity +254: function xor(ERC721Receiver lhs, ERC721Receiver rhs) pure returns (ERC721Receiver output) +``` + +['[262](ERC721Receiver.sol: 262-262)'] + +```solidity +262: function not(ERC721Receiver lhs) pure returns (ERC721Receiver output) +``` + +
+ +## [NonCritical-3] Assembly block creates dirty bits + +### Resolution + +Manipulating data directly at the free memory pointer location without subsequently adjusting the pointer can lead to unwanted data remnants, or "dirty bits", in that memory spot. This can cause challenges for the Solidity optimizer, making it difficult to determine if memory cleaning is required before reuse, potentially resulting in less efficient optimization. To mitigate this issue, it's advised to always update the free memory pointer following any data write operation. Furthermore, using the `assembly ("memory-safe") { ... }` annotation will clearly indicate to the optimizer the sections of your code that are memory-safe, improving code efficiency and reducing the potential for errors. + +Num of instances: 12 + +### Findings + +
Click to show findings + +['[161](ERC20.sol: 161-178)'] + +```solidity +161: assembly { +162: let fmp := mload(0x40) // <= FOUND +163: +164: mstore(0x00, 0x23b872dd00000000000000000000000000000000000000000000000000000000) +165: +166: mstore(0x04, sender) +167: +168: mstore(0x24, receiver) +169: +170: mstore(0x44, amount) +171: +172: let ok := call(gas(), erc20, 0x00, 0x00, 0x64, 0x00, 0x20) +173: +174: ok := and(ok, or(iszero(returndatasize()), and(eq(returndatasize(), 0x20), mload(0x00)))) +175: +176: if iszero(ok) { revert(0x00, 0x00) } +177: +178: mstore(0x40, fmp) // <= FOUND +179: +180: mstore(0x60, 0x00) +181: } +``` + +['[387](ERC4626.sol: 387-406)'] + +```solidity +387: assembly { +388: let fmp := mload(0x40) // <= FOUND +389: +390: mstore(0x00, 0xb460af9400000000000000000000000000000000000000000000000000000000) +391: +392: mstore(0x04, assets) +393: +394: mstore(0x24, receiver) +395: +396: mstore(0x44, owner) +397: +398: let ok := call(gas(), erc4626, 0x00, 0x00, 0x64, 0x00, 0x20) +399: +400: ok := and(ok, eq(returndatasize(), 0x20)) +401: +402: if iszero(ok) { revert(0x00, 0x00) } +403: +404: output := mload(0x00) +405: +406: mstore(0x40, fmp) // <= FOUND +407: +408: mstore(0x60, 0x00) +409: } +``` + +['[480](ERC4626.sol: 480-499)'] + +```solidity +480: assembly { +481: let fmp := mload(0x40) // <= FOUND +482: +483: mstore(0x00, 0xba08765200000000000000000000000000000000000000000000000000000000) +484: +485: mstore(0x04, shares) +486: +487: mstore(0x24, receiver) +488: +489: mstore(0x44, owner) +490: +491: let ok := call(gas(), erc4626, 0x00, 0x00, 0x64, 0x00, 0x20) +492: +493: ok := and(ok, eq(returndatasize(), 0x20)) +494: +495: if iszero(ok) { revert(0x00, 0x00) } +496: +497: output := mload(0x00) +498: +499: mstore(0x40, fmp) // <= FOUND +500: +501: mstore(0x60, 0x00) +502: } +``` + +['[630](ERC4626.sol: 630-647)'] + +```solidity +630: assembly { +631: let fmp := mload(0x40) // <= FOUND +632: +633: mstore(0x00, 0x23b872dd00000000000000000000000000000000000000000000000000000000) +634: +635: mstore(0x04, sender) +636: +637: mstore(0x24, receiver) +638: +639: mstore(0x44, amount) +640: +641: let ok := call(gas(), erc4626, 0x00, 0x00, 0x64, 0x00, 0x20) +642: +643: ok := and(ok, or(iszero(returndatasize()), and(eq(returndatasize(), 0x20), mload(0x00)))) +644: +645: if iszero(ok) { revert(0x00, 0x00) } +646: +647: mstore(0x40, fmp) // <= FOUND +648: +649: mstore(0x60, 0x00) +650: } +``` + +['[113](ERC6909.sol: 113-132)'] + +```solidity +113: assembly { +114: let fmp := mload(0x40) // <= FOUND +115: +116: mstore(0x00, 0x598af9e700000000000000000000000000000000000000000000000000000000) +117: +118: mstore(0x04, owner) +119: +120: mstore(0x24, spender) +121: +122: mstore(0x44, id) +123: +124: let ok := staticcall(gas(), erc6909, 0x00, 0x64, 0x00, 0x20) +125: +126: ok := and(ok, eq(returndatasize(), 0x20)) +127: +128: if iszero(ok) { revert(0x00, 0x00) } +129: +130: output := mload(0x00) +131: +132: mstore(0x40, fmp) // <= FOUND +133: +134: mstore(0x60, 0x00) +135: } +``` + +['[186](ERC6909.sol: 186-205)'] + +```solidity +186: assembly { +187: let fmp := mload(0x40) // <= FOUND +188: +189: mstore(0x00, 0x095bcdb600000000000000000000000000000000000000000000000000000000) +190: +191: mstore(0x04, receiver) +192: +193: mstore(0x24, id) +194: +195: mstore(0x44, amount) +196: +197: let ok := call(gas(), erc6909, 0x00, 0x00, 0x64, 0x00, 0x20) +198: +199: ok := and(ok, eq(returndatasize(), 0x20)) +200: +201: ok := and(ok, mload(0x00)) +202: +203: if iszero(ok) { revert(0x00, 0x00) } +204: +205: mstore(0x40, fmp) // <= FOUND +206: +207: mstore(0x60, 0x00) +208: } +``` + +['[230](ERC6909.sol: 230-253)'] + +```solidity +230: assembly { +231: let fmp := mload(0x40) // <= FOUND +232: +233: let allocatedWord := mload(0x80) +234: +235: mstore(0x00, 0xfe99049a00000000000000000000000000000000000000000000000000000000) +236: +237: mstore(0x04, sender) +238: +239: mstore(0x24, receiver) +240: +241: mstore(0x44, id) +242: +243: mstore(0x64, amount) +244: +245: let ok := call(gas(), erc6909, 0x00, 0x00, 0x84, allocatedWord, 0x20) +246: +247: ok := and(ok, eq(returndatasize(), 0x20)) +248: +249: ok := and(ok, mload(allocatedWord)) +250: +251: if iszero(ok) { revert(0x00, 0x00) } +252: +253: mstore(0x40, fmp) // <= FOUND +254: +255: mstore(0x60, 0x00) +256: +257: mstore(0x80, allocatedWord) +258: } +``` + +['[277](ERC6909.sol: 277-296)'] + +```solidity +277: assembly { +278: let fmp := mload(0x40) // <= FOUND +279: +280: mstore(0x00, 0x426a849300000000000000000000000000000000000000000000000000000000) +281: +282: mstore(0x04, spender) +283: +284: mstore(0x24, id) +285: +286: mstore(0x44, amount) +287: +288: let ok := call(gas(), erc6909, 0x00, 0x00, 0x64, 0x00, 0x20) +289: +290: ok := and(ok, eq(returndatasize(), 0x20)) +291: +292: ok := and(ok, mload(0x00)) +293: +294: if iszero(ok) { revert(0x00, 0x00) } +295: +296: mstore(0x40, fmp) // <= FOUND +297: +298: mstore(0x60, 0x00) +299: } +``` + +['[206](ERC721.sol: 206-223)'] + +```solidity +206: assembly { +207: let fmp := mload(0x40) // <= FOUND +208: +209: let dataLength := mload(data) +210: +211: switch dataLength +212: case 0x00 { +213: mstore(0x00, 0x42842e0e00000000000000000000000000000000000000000000000000000000) +214: +215: mstore(0x04, sender) +216: +217: mstore(0x24, receiver) +218: +219: mstore(0x44, tokenId) +220: +221: if iszero(call(gas(), erc721, 0x00, 0x00, 0x64, 0x00, 0x00)) { revert(0x00, 0x00) } +222: +223: mstore(0x40, fmp) // <= FOUND +224: +225: mstore(0x60, 0x00) +226: } +227: default { +228: mstore(add(fmp, 0x00), 0xb88d4fde00000000000000000000000000000000000000000000000000000000) +229: +230: mstore(add(fmp, 0x04), sender) +231: +232: mstore(add(fmp, 0x24), receiver) +233: +234: mstore(add(fmp, 0x44), tokenId) +235: +236: mstore(add(fmp, 0x64), 0x80) +237: +238: mcopy(add(fmp, 0x84), data, add(dataLength, 0x20)) +239: +240: if iszero(call(gas(), erc721, 0x00, fmp, add(0xa4, dataLength), 0x00, 0x00)) { revert(0x00, 0x00) } +241: } +242: } +``` + +['[258](ERC721.sol: 258-271)'] + +```solidity +258: assembly { +259: let fmp := mload(0x40) // <= FOUND +260: +261: mstore(0x00, 0x23b872dd00000000000000000000000000000000000000000000000000000000) +262: +263: mstore(0x04, sender) +264: +265: mstore(0x24, receiver) +266: +267: mstore(0x44, tokenId) +268: +269: if iszero(call(gas(), erc721, 0x00, 0x00, 0x64, 0x00, 0x00)) { revert(0x00, 0x00) } +270: +271: mstore(0x40, fmp) // <= FOUND +272: +273: mstore(0x60, 0x00) +274: } +``` + +['[56](ERC721Receiver.sol: 56-58)'] + +```solidity +56: assembly ("memory-safe") { +57: if extcodesize(receiver) { +58: let fmp := mload(0x40) // <= FOUND +59: +60: mstore(add(fmp, 0x00), 0x150b7a0200000000000000000000000000000000000000000000000000000000) +61: +62: mstore(add(fmp, 0x04), operator) +63: +64: mstore(add(fmp, 0x24), sender) +65: +66: mstore(add(fmp, 0x44), id) +67: +68: mstore(add(fmp, 0x64), 0x80) +69: +70: mstore(add(fmp, 0x84), 0x00) +71: +72: let ok := call(gas(), receiver, 0x00, fmp, 0xa4, 0x00, 0x20) +73: +74: ok := and(ok, eq(returndatasize(), 0x20)) +75: +76: ok := and(ok, eq(mload(0x00), 0x150b7a0200000000000000000000000000000000000000000000000000000000)) +77: +78: if iszero(ok) { revert(0x00, 0x00) } +79: } +80: } +``` + +['[112](ERC721Receiver.sol: 112-114)'] + +```solidity +112: assembly ("memory-safe") { +113: if extcodesize(receiver) { +114: let fmp := mload(0x40) // <= FOUND +115: +116: mstore(add(fmp, 0x00), 0x150b7a0200000000000000000000000000000000000000000000000000000000) +117: +118: mstore(add(fmp, 0x04), operator) +119: +120: mstore(add(fmp, 0x24), sender) +121: +122: mstore(add(fmp, 0x44), id) +123: +124: mstore(add(fmp, 0x64), 0x80) +125: +126: mstore(add(fmp, 0x84), data.length) +127: +128: calldatacopy(add(fmp, 0xa4), data.offset, data.length) +129: +130: let ok := call(gas(), receiver, 0x00, fmp, add(0xa4, data.length), 0x00, 0x20) +131: +132: ok := and(ok, eq(returndatasize(), 0x20)) +133: +134: ok := and(ok, eq(mload(0x00), 0x150b7a0200000000000000000000000000000000000000000000000000000000)) +135: +136: if iszero(ok) { revert(0x00, 0x00) } +137: } +138: } +``` + +
+ +## [NonCritical-4] .call bypasses function existence check, type checking and argument packing + +### Resolution + +Using the `.call` method in Solidity enables direct communication with an address, bypassing function existence checks, type checking, and argument packing. While this can save gas and provide flexibility, it can also introduce security risks and potential errors. The absence of these checks can lead to unexpected behavior if the callee contract's interface changes or if the input parameters are not crafted with care. The resolution to these issues is to use Solidity's high-level interface for calling functions when possible, as it automatically manages these aspects. If using `.call` is necessary, ensure that the inputs are carefully validated and that awareness of the called contract's behavior is maintained. + +Num of instances: 16 + +### Findings + +
Click to show findings + +['[130](ERC20.sol: 130-136)'] + +```solidity +130: mstore(0x00, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) +131: +132: mstore(0x04, receiver) +133: +134: mstore(0x24, amount) +135: +136: let ok := call(gas(), erc20, 0x00, 0x00, 0x44, 0x00, 0x20) // <= FOUND +137: +138: ok := and(ok, or(iszero(returndatasize()), and(eq(returndatasize(), 0x20), mload(0x00)))) +139: +140: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[162](ERC20.sol: 162-172)'] + +```solidity +162: let fmp := mload(0x40) +163: +164: mstore(0x00, 0x23b872dd00000000000000000000000000000000000000000000000000000000) +165: +166: mstore(0x04, sender) +167: +168: mstore(0x24, receiver) +169: +170: mstore(0x44, amount) +171: +172: let ok := call(gas(), erc20, 0x00, 0x00, 0x64, 0x00, 0x20) // <= FOUND +173: +174: ok := and(ok, or(iszero(returndatasize()), and(eq(returndatasize(), 0x20), mload(0x00)))) +175: +176: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[197](ERC20.sol: 197-203)'] + +```solidity +197: mstore(0x00, 0x095ea7b300000000000000000000000000000000000000000000000000000000) +198: +199: mstore(0x04, spender) +200: +201: mstore(0x24, amount) +202: +203: let ok := call(gas(), erc20, 0x00, 0x00, 0x44, 0x00, 0x20) // <= FOUND +204: +205: ok := and(ok, or(iszero(returndatasize()), and(eq(returndatasize(), 0x20), mload(0x00)))) +206: +207: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[217](ERC4626.sol: 217-223)'] + +```solidity +217: mstore(0x00, 0x6e553f6500000000000000000000000000000000000000000000000000000000) +218: +219: mstore(0x04, assets) +220: +221: mstore(0x24, receiver) +222: +223: let ok := call(gas(), erc4626, 0x00, 0x00, 0x44, 0x00, 0x20) // <= FOUND +224: +225: ok := and(ok, eq(returndatasize(), 0x20)) +226: +227: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[301](ERC4626.sol: 301-307)'] + +```solidity +301: mstore(0x00, 0x94bf804d00000000000000000000000000000000000000000000000000000000) +302: +303: mstore(0x04, shares) +304: +305: mstore(0x24, receiver) +306: +307: let ok := call(gas(), erc4626, 0x00, 0x00, 0x44, 0x00, 0x20) // <= FOUND +308: +309: ok := and(ok, eq(returndatasize(), 0x20)) +310: +311: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[388](ERC4626.sol: 388-398)'] + +```solidity +388: let fmp := mload(0x40) +389: +390: mstore(0x00, 0xb460af9400000000000000000000000000000000000000000000000000000000) +391: +392: mstore(0x04, assets) +393: +394: mstore(0x24, receiver) +395: +396: mstore(0x44, owner) +397: +398: let ok := call(gas(), erc4626, 0x00, 0x00, 0x64, 0x00, 0x20) // <= FOUND +399: +400: ok := and(ok, eq(returndatasize(), 0x20)) +401: +402: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[481](ERC4626.sol: 481-491)'] + +```solidity +481: let fmp := mload(0x40) +482: +483: mstore(0x00, 0xba08765200000000000000000000000000000000000000000000000000000000) +484: +485: mstore(0x04, shares) +486: +487: mstore(0x24, receiver) +488: +489: mstore(0x44, owner) +490: +491: let ok := call(gas(), erc4626, 0x00, 0x00, 0x64, 0x00, 0x20) // <= FOUND +492: +493: ok := and(ok, eq(returndatasize(), 0x20)) +494: +495: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[599](ERC4626.sol: 599-605)'] + +```solidity +599: mstore(0x00, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) +600: +601: mstore(0x04, receiver) +602: +603: mstore(0x24, amount) +604: +605: let ok := call(gas(), erc4626, 0x00, 0x00, 0x44, 0x00, 0x20) // <= FOUND +606: +607: ok := and(ok, or(iszero(returndatasize()), and(eq(returndatasize(), 0x20), mload(0x00)))) +608: +609: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[631](ERC4626.sol: 631-641)'] + +```solidity +631: let fmp := mload(0x40) +632: +633: mstore(0x00, 0x23b872dd00000000000000000000000000000000000000000000000000000000) +634: +635: mstore(0x04, sender) +636: +637: mstore(0x24, receiver) +638: +639: mstore(0x44, amount) +640: +641: let ok := call(gas(), erc4626, 0x00, 0x00, 0x64, 0x00, 0x20) // <= FOUND +642: +643: ok := and(ok, or(iszero(returndatasize()), and(eq(returndatasize(), 0x20), mload(0x00)))) +644: +645: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[666](ERC4626.sol: 666-672)'] + +```solidity +666: mstore(0x00, 0x095ea7b300000000000000000000000000000000000000000000000000000000) +667: +668: mstore(0x04, spender) +669: +670: mstore(0x24, amount) +671: +672: let ok := call(gas(), erc4626, 0x00, 0x00, 0x44, 0x00, 0x20) // <= FOUND +673: +674: ok := and(ok, or(iszero(returndatasize()), and(eq(returndatasize(), 0x20), mload(0x00)))) +675: +676: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[187](ERC6909.sol: 187-197)'] + +```solidity +187: let fmp := mload(0x40) +188: +189: mstore(0x00, 0x095bcdb600000000000000000000000000000000000000000000000000000000) +190: +191: mstore(0x04, receiver) +192: +193: mstore(0x24, id) +194: +195: mstore(0x44, amount) +196: +197: let ok := call(gas(), erc6909, 0x00, 0x00, 0x64, 0x00, 0x20) // <= FOUND +198: +199: ok := and(ok, eq(returndatasize(), 0x20)) +200: +201: ok := and(ok, mload(0x00)) +202: +203: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[231](ERC6909.sol: 231-245)'] + +```solidity +231: let fmp := mload(0x40) +232: +233: let allocatedWord := mload(0x80) +234: +235: mstore(0x00, 0xfe99049a00000000000000000000000000000000000000000000000000000000) +236: +237: mstore(0x04, sender) +238: +239: mstore(0x24, receiver) +240: +241: mstore(0x44, id) +242: +243: mstore(0x64, amount) +244: +245: let ok := call(gas(), erc6909, 0x00, 0x00, 0x84, allocatedWord, 0x20) // <= FOUND +246: +247: ok := and(ok, eq(returndatasize(), 0x20)) +248: +249: ok := and(ok, mload(allocatedWord)) +250: +251: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[278](ERC6909.sol: 278-288)'] + +```solidity +278: let fmp := mload(0x40) +279: +280: mstore(0x00, 0x426a849300000000000000000000000000000000000000000000000000000000) +281: +282: mstore(0x04, spender) +283: +284: mstore(0x24, id) +285: +286: mstore(0x44, amount) +287: +288: let ok := call(gas(), erc6909, 0x00, 0x00, 0x64, 0x00, 0x20) // <= FOUND +289: +290: ok := and(ok, eq(returndatasize(), 0x20)) +291: +292: ok := and(ok, mload(0x00)) +293: +294: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[316](ERC6909.sol: 316-322)'] + +```solidity +316: mstore(0x00, 0x558a729700000000000000000000000000000000000000000000000000000000) +317: +318: mstore(0x04, spender) +319: +320: mstore(0x24, approved) +321: +322: let ok := call(gas(), erc6909, 0x00, 0x00, 0x44, 0x00, 0x20) // <= FOUND +323: +324: ok := and(ok, eq(returndatasize(), 0x20)) +325: +326: ok := and(ok, mload(0x00)) +327: +328: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[58](ERC721Receiver.sol: 58-72)'] + +```solidity +58: let fmp := mload(0x40) +59: +60: mstore(add(fmp, 0x00), 0x150b7a0200000000000000000000000000000000000000000000000000000000) +61: +62: mstore(add(fmp, 0x04), operator) +63: +64: mstore(add(fmp, 0x24), sender) +65: +66: mstore(add(fmp, 0x44), id) +67: +68: mstore(add(fmp, 0x64), 0x80) +69: +70: mstore(add(fmp, 0x84), 0x00) +71: +72: let ok := call(gas(), receiver, 0x00, fmp, 0xa4, 0x00, 0x20) // <= FOUND +73: +74: ok := and(ok, eq(returndatasize(), 0x20)) +75: +76: ok := and(ok, eq(mload(0x00), 0x150b7a0200000000000000000000000000000000000000000000000000000000)) +77: +78: if iszero(ok) { revert(0x00, 0x00) } +``` + +['[114](ERC721Receiver.sol: 114-130)'] + +```solidity +114: let fmp := mload(0x40) +115: +116: mstore(add(fmp, 0x00), 0x150b7a0200000000000000000000000000000000000000000000000000000000) +117: +118: mstore(add(fmp, 0x04), operator) +119: +120: mstore(add(fmp, 0x24), sender) +121: +122: mstore(add(fmp, 0x44), id) +123: +124: mstore(add(fmp, 0x64), 0x80) +125: +126: mstore(add(fmp, 0x84), data.length) +127: +128: calldatacopy(add(fmp, 0xa4), data.offset, data.length) +129: +130: let ok := call(gas(), receiver, 0x00, fmp, add(0xa4, data.length), 0x00, 0x20) // <= FOUND +131: +132: ok := and(ok, eq(returndatasize(), 0x20)) +133: +134: ok := and(ok, eq(mload(0x00), 0x150b7a0200000000000000000000000000000000000000000000000000000000)) +135: +136: if iszero(ok) { revert(0x00, 0x00) } +``` + +
+ +## [NonCritical-5] Missing events in sensitive functions + +### Resolution + +Sensitive setter functions in smart contracts often alter critical state variables. Without events emitted in these functions, external observers or dApps cannot easily track or react to these state changes. Missing events can obscure contract activity, hampering transparency and making integration more challenging. To resolve this, incorporate appropriate event emissions within these functions. Events offer an efficient way to log crucial changes, aiding in real-time tracking and post-transaction verification. + +Num of instances: 1 + +### Findings + +
Click to show findings + +['[314](ERC6909.sol: 314-314)'] + +```solidity +314: function setOperator(ERC6909 erc6909, address spender, bool approved) { // <= FOUND +315: assembly { +316: mstore(0x00, 0x558a729700000000000000000000000000000000000000000000000000000000) +317: +318: mstore(0x04, spender) +319: +320: mstore(0x24, approved) +321: +322: let ok := call(gas(), erc6909, 0x00, 0x00, 0x44, 0x00, 0x20) +323: +324: ok := and(ok, eq(returndatasize(), 0x20)) +325: +326: ok := and(ok, mload(0x00)) +327: +328: if iszero(ok) { revert(0x00, 0x00) } +329: +330: mstore(0x24, 0x00) +331: } +332: } +``` + +
+ +## [NonCritical-6] All verbatim blocks are considered identical by deduplicator and can incorrectly be unified + +### Resolution + +The Solidity Team reported a bug on October 24, 2023, affecting Yul code using the verbatim builtin, specifically in the Block Deduplicator optimizer step. This bug, present since Solidity version 0.8.5, caused incorrect deduplication of verbatim assembly items surrounded by identical opcodes, considering them identical regardless of their data. The bug was confined to pure Yul compilation with optimization enabled and was unlikely to be exploited as an attack vector. + +Num of instances: 1 + +### Findings + +
Click to show findings + +['[2](ERC165.sol: 2-2)'] + +```solidity +2: pragma solidity ^0.8.25; // <= FOUND +``` + +
+ +## [NonCritical-7] Avoid using 'owner' or '\_owner' as a parameter name + +### Resolution + +Using 'owner' or '\_owner' as a parameter name in functions, especially in contracts inheriting from or interacting with OpenZeppelin's `Ownable` contract, can lead to confusion and potential bugs. These contracts often have a state variable named `owner`, managed by the `Ownable` pattern for access control. Using the same name for function parameters may obscure the contract's `owner` state variable, complicating code readability and maintenance. Prefer alternative descriptive names for parameters to maintain clarity and prevent conflicts with established ownership patterns. + +Num of instances: 13 + +### Findings + +
Click to show findings + +['[70](ERC20.sol: 70-70)'] + +```solidity +70: function balanceOf(ERC20 erc20, address owner) view returns (uint256 output) // <= FOUND +``` + +['[97](ERC20.sol: 97-97)'] + +```solidity +97: function allowance(ERC20 erc20, address owner, address spender) view returns (uint256 output) // <= FOUND +``` + +['[329](ERC4626.sol: 329-329)'] + +```solidity +329: function maxWithdraw(ERC4626 erc4626, address owner) view returns (uint256 output) // <= FOUND +``` + +['[386](ERC4626.sol: 386-386)'] + +```solidity +386: function withdraw(ERC4626 erc4626, uint256 assets, address receiver, address owner) returns (uint256 output) // <= FOUND +``` + +['[422](ERC4626.sol: 422-422)'] + +```solidity +422: function maxRedeem(ERC4626 erc4626, address owner) view returns (uint256 output) // <= FOUND +``` + +['[479](ERC4626.sol: 479-479)'] + +```solidity +479: function redeem(ERC4626 erc4626, uint256 shares, address receiver, address owner) returns (uint256 output) // <= FOUND +``` + +['[538](ERC4626.sol: 538-538)'] + +```solidity +538: function balanceOf(ERC4626 erc4626, address owner) view returns (uint256 output) // <= FOUND +``` + +['[566](ERC4626.sol: 566-566)'] + +```solidity +566: function allowance(ERC4626 erc4626, address owner, address spender) view returns (uint256 output) // <= FOUND +``` + +['[77](ERC6909.sol: 77-77)'] + +```solidity +77: function balanceOf(ERC6909 erc6909, address owner, uint256 id) view returns (uint256 output) // <= FOUND +``` + +['[112](ERC6909.sol: 112-112)'] + +```solidity +112: function allowance(ERC6909 erc6909, address owner, address spender, uint256 id) view returns (uint256 output) // <= FOUND +``` + +['[150](ERC6909.sol: 150-150)'] + +```solidity +150: function isOperator(ERC6909 erc6909, address owner, address spender) view returns (bool output) // <= FOUND +``` + +['[104](ERC721.sol: 104-104)'] + +```solidity +104: function isApprovedForAll(ERC721 erc721, address owner, address operator) view returns (bool output) // <= FOUND +``` + +['[134](ERC721.sol: 134-134)'] + +```solidity +134: function balanceOf(ERC721 erc721, address owner) view returns (uint256 output) // <= FOUND +``` + +
+ +## [NonCritical-8] Memory-safe annotation missing + +### Resolution + +Tagging assembly blocks as "memory safe" in Solidity helps maintainers and auditors quickly identify areas of the code less likely to introduce vulnerabilities due to improper memory access. This practice promotes safer contract development by clearly communicating assumptions about memory handling, aiding in the review process, and reducing the risk of introducing memory-related bugs. It's a part of best coding practices, enhancing code clarity and security, especially in complex, low-level operations where Solidity's safety checks are bypassed. + +Num of instances: 19 + +### Findings + +
Click to show findings + +['[61](ERC165.sol: 61-61)'] + +```solidity +61: assembly { +62: output := eq(lhs, rhs) +63: } +``` + +['[69](ERC165.sol: 69-69)'] + +```solidity +69: assembly { +70: output := iszero(eq(lhs, rhs)) +71: } +``` + +['[77](ERC165.sol: 77-77)'] + +```solidity +77: assembly { +78: output := gt(lhs, rhs) +79: } +``` + +['[85](ERC165.sol: 85-85)'] + +```solidity +85: assembly { +86: output := iszero(lt(lhs, rhs)) +87: } +``` + +['[93](ERC165.sol: 93-93)'] + +```solidity +93: assembly { +94: output := lt(lhs, rhs) +95: } +``` + +['[101](ERC165.sol: 101-101)'] + +```solidity +101: assembly { +102: output := iszero(gt(lhs, rhs)) +103: } +``` + +['[109](ERC165.sol: 109-109)'] + +```solidity +109: assembly { +110: output := add(lhs, rhs) +111: if gt(output, 0xffffffffffffffffffffffffffffffffffffffff) { revert(0x00, 0x00) } +112: } +``` + +['[118](ERC165.sol: 118-118)'] + +```solidity +118: assembly { +119: output := sub(lhs, rhs) +120: if gt(output, 0xffffffffffffffffffffffffffffffffffffffff) { revert(0x00, 0x00) } +121: } +``` + +['[127](ERC165.sol: 127-127)'] + +```solidity +127: assembly { +128: if lhs { +129: output := and(mul(lhs, rhs), 0xffffffffffffffffffffffffffffffffffffffff) +130: if iszero(eq(div(output, lhs), rhs)) { revert(0x00, 0x00) } +131: } +132: } +``` + +['[138](ERC165.sol: 138-138)'] + +```solidity +138: assembly { +139: if iszero(rhs) { revert(0x00, 0x00) } +140: output := div(lhs, rhs) +141: } +``` + +['[147](ERC165.sol: 147-147)'] + +```solidity +147: assembly { +148: if iszero(rhs) { revert(0x00, 0x00) } +149: output := mod(lhs, rhs) +150: } +``` + +['[156](ERC165.sol: 156-156)'] + +```solidity +156: assembly { +157: output := and(lhs, rhs) +158: } +``` + +['[164](ERC165.sol: 164-164)'] + +```solidity +164: assembly { +165: output := or(lhs, rhs) +166: } +``` + +['[172](ERC165.sol: 172-172)'] + +```solidity +172: assembly { +173: output := xor(lhs, rhs) +174: } +``` + +['[180](ERC165.sol: 180-180)'] + +```solidity +180: assembly { +181: output := and(not(lhs), 0xffffffffffffffffffffffffffffffffffffffff) +182: } +``` + +['[109](ERC165.sol: 109-109)'] + +```solidity +109: assembly { +110: output := add(lhs, rhs) +111: +112: if gt(output, 0xffffffffffffffffffffffffffffffffffffffff) { revert(0x00, 0x00) } +113: } +``` + +['[118](ERC165.sol: 118-118)'] + +```solidity +118: assembly { +119: output := sub(lhs, rhs) +120: +121: if gt(output, 0xffffffffffffffffffffffffffffffffffffffff) { revert(0x00, 0x00) } +122: } +``` + +['[127](ERC165.sol: 127-127)'] + +```solidity +127: assembly { +128: if lhs { +129: output := and(mul(lhs, rhs), 0xffffffffffffffffffffffffffffffffffffffff) +130: +131: if iszero(eq(div(output, lhs), rhs)) { revert(0x00, 0x00) } +132: } +133: } +``` + +['[415](ERC721.sol: 415-415)'] + +```solidity +415: assembly { +416: if iszero(rhs) { revert(0x00, 0x00) } +417: +418: output := mod(lhs, rhs) +419: } +``` + +
+ +## [Gas-1] Assembly let var only used on once + +### Resolution + +If a variable is only once, it makes more sense to use the value the variable holds directly + +Num of instances: 1 + +### Findings + +
Click to show findings + +['[258](ERC721.sol: 258-258)'] + +```solidity +258: assembly { +259: let fmp := mload(0x40) +260: +261: mstore(0x00, 0x23b872dd00000000000000000000000000000000000000000000000000000000) +262: +263: mstore(0x04, sender) +264: +265: mstore(0x24, receiver) +266: +267: mstore(0x44, tokenId) +268: +269: if iszero(call(gas(), erc721, 0x00, 0x00, 0x64, 0x00, 0x00)) { revert(0x00, 0x00) } +270: +271: mstore(0x40, fmp) +272: +273: mstore(0x60, 0x00) +274: } +``` + +