Platform: Code4rena
Start Date: 08/01/2024
Pot Size: $83,600 USDC
Total HM: 23
Participants: 116
Period: 10 days
Judge: 0xean
Total Solo HM: 1
Id: 317
League: ETH
Rank: 29/116
Findings: 1
Award: $350.82
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: fouzantanveer
Also found by: 0xA5DF, 0xepley, SAQ, SBSecurity, albahaca, catellatech, clara, hals, hunter_w3b, kaveyjoe, ladboy233, pavankv, peanuts, tala7985, yongskiws
350.8235 USDC - $350.82
The reNFT project introduces a unique concept in the NFT world, allowing NFT owners, or lenders, to rent out their digital assets. This setup offers an opportunity for NFT owners to earn passive income through rentals, without having to sell their assets. It's a smart way for them to make the most out of their digital collections. On the other side are the renters - users who want to use NFTs temporarily. This could be for various reasons, like gaming or temporarily boosting a digital collection. Renting NFTs is a cost-effective solution for them, as it provides access to valuable digital assets without the need for a large upfront investment. What makes reNFT stand out is its integration with the Seaport protocol, ensuring a smooth and secure transaction process. This integration manages the transfer of NFTs between lenders and renters efficiently and safely, providing a reliable platform for both parties to transact. In short, reNFT is transforming how NFTs are utilized, offering innovative solutions for owners and enthusiasts alike.
After a thorough examination of the reNFT codebase, a key observation is the balance between complexity and clarity. For instance, contracts like Create.sol
exhibit a significant level of complexity due to their multifaceted roles in handling asset transfers, interfacing with Seaport, and managing diverse token standards like ERC-721/ERC-1155. This complexity, while necessary for the contract's functionality, suggests a potential area for optimization, especially in terms of gas efficiency and processing loops.
In contrast, the Kernel.sol
contract, acting as the ecosystem's nucleus, orchestrates modules and policies with a high degree of interconnectivity. This complexity is offset by a clear modular structure and well-commented code, enhancing maintainability. The modular structure of the reNFT project, particularly evident in the Kernel.sol
contract, is a standout feature. This contract effectively serves as the central hub, managing various modules and policies. Each module and policy is treated as an independent component, allowing for separation of concerns and easier maintenance. This modular approach is not only evident in the organizational structure of the contracts but also in how they interact with each other. Each module, identified by a unique keycode, can be independently installed, upgraded, or interacted with, while policies can request permissions for specific actions. This design facilitates scalability and flexibility, allowing for seamless integration of new features or updates without disrupting the entire system. The clarity and thoroughness of the code comments further aid in understanding the purpose and functionality of each part, contributing to the overall maintainability of the system.
Here is the tabular analysis of the code files of project
File | Language | Code | Comment | Blank | Total |
---|---|---|---|---|---|
src/policies/Accumulator.sol | Solidity | 52 | 72 | 23 | 147 |
src/policies/Admin.sol | Solidity | 77 | 81 | 19 | 177 |
src/policies/Create.sol | Solidity | 422 | 273 | 82 | 777 |
src/policies/Create2Deployer.sol | Solidity | 53 | 56 | 13 | 122 |
src/policies/Factory.sol | Solidity | 92 | 82 | 21 | 195 |
src/policies/Guard.sol | Solidity | 201 | 144 | 35 | 380 |
src/policies/Kernel.sol | Solidity | 238 | 286 | 94 | 618 |
src/policies/PaymentEscrow.sol | Solidity | 185 | 202 | 47 | 434 |
src/policies/Reclaimer.sol | Solidity | 41 | 49 | 13 | 103 |
src/policies/Signer.sol | Solidity | 233 | 136 | 41 | 410 |
src/policies/Stop.sol | Solidity | 181 | 139 | 46 | 366 |
src/policies/Storage.sol | Solidity | 130 | 193 | 51 | 374 |
These observations reflect a codebase that, while technically sophisticated and functionally rich, still presents opportunities for refinement, especially in enhancing performance and ensuring long-term maintainability.
To audit the reNFT project, I implemented a structured approach that combined a thorough review of the provided documentation, an in-depth code analysis, an understanding of publicly known issues, insights from external reports, and comprehensive testing. Here's the detailed process:
Initial Overview from Code4rena: Began with the project's overview on Code4rena, to understand its objective of creating a decentralized rental market for NFTs. Key insights were the use of Seaport for order processing and Gnosis Safe for rental safe management.
Analyzing the Default Framework: Studied the Default Framework from GitHub. This was pivotal for understanding reNFT's architecture, especially its Kernel-Module-Policy structure, and the interaction of these components as depicted in the documentation images.
Audited the codebase files in this order
File Name | Core Functionality | Technical Characteristics | Importance and Management |
---|---|---|---|
Kernel.sol | Central registry and management of policies and modules. | Implements role-based access control, module installation, and policy activation. | Acts as the backbone, managing permissions and interactions between different parts of the system. |
Create.sol | Interface for creating rentals, integrating with Seaport for order fulfillment. | Extensive use of structs for organizing rental data, EIP-712 signature verification, and careful handling of offer and consideration items. | Serves as the core for initiating and managing rental orders, crucial for the protocol’s operation around rentals. |
Storage.sol | Maintains all protocol storage, including state and data related to rentals. | Efficient data structuring with a focus on integrity and accessibility of rental records. | Essential for data persistence and state maintenance, ensuring the consistency and reliability of the protocol. |
PaymentEscrow.sol | Manages escrowing of rental payments. | Secure handling of funds with mechanisms for deposit management and payment settlements. | Key for managing financial aspects of rentals, ensuring secure and orderly flow of funds. |
Signer.sol | Handles logic related to signature verification for rentals. | Implements robust mechanisms for signature validation to authenticate transactions. | Critical for ensuring the authenticity and integrity of transactions within the protocol. |
Admin.sol | Administrative functions like fee, proxy, and whitelist management. | Clear distinction and secure implementation of administrative roles and actions. | Central to governance, providing tools for protocol management and configuration. |
Guard.sol | Protects transactions originating from rental wallets. | Implements comprehensive checks against unauthorized transfers and function calls. | Vital for ensuring the security of rental wallets, preventing misuse and unauthorized access. |
Factory.sol | Deploys and initializes rental safes. | Efficient deployment and initialization processes for creating secure rental safes. | Streamlines the process of rental safe creation, integral to the rental mechanism. |
Stop.sol | Manages the stopping of rentals. | Implements logic for orderly termination of rentals, including asset and payment settlements. | Crucial for the proper conclusion of rental agreements, handling the return of assets and payments. |
Create2Deployer.sol | Uses create2 for predictable and secure contract deployments. | Innovative use of create2 for deploying contracts with predictable addresses and added security measures. | Enhances the deployment process with predictability and security, beneficial for cross-chain operations. |
Accumulator.sol | Manages dynamically allocated data struct arrays in memory. | Optimized for low gas consumption, enhancing performance in dynamic data handling. | Supports performance and efficiency, particularly in scenarios with variable data structures. |
Zone.sol | (Not directly included but inferred) Manages zone-specific logic for rentals. | Likely handles custom logic for different operational zones or contexts within the rental process. | Assumed to be important for contextual handling and customization within different parts of the rental lifecycle. |
Reviewing Publicly Known Issues: Investigated issues listed on Code4rena, including the potential manipulation via Hook Contracts and limitations of the Guard contract. These helped me focus on specific areas in the code that could be susceptible to exploitation.
Analyzing External Reports (4naly3er report): This report provided an alternate perspective on potential vulnerabilities. Key insights were the emphasis on the robustness of rental wallet security and the importance of accurate rental asset tracking.
Foundry Testing:
Foundry, a modern smart contract testing framework, was utilized to test the reNFT contracts. This involved several key steps:
a. Installation and Setup:
curl -L https://foundry.paradigm.xyz | bash
, followed by foundryup
to ensure the latest version was in use.forge install
, ensuring all necessary components were available for the testing process.b. Execution of Tests:
forge test
, executing a suite of predefined test cases that covered various functionalities and scenarios within the reNFT contracts.forge test --gas-report
. This report provided insights into the gas efficiency of the contracts, which is crucial for optimizing transaction costs on the blockchain.c. Test Coverage and Documentation:
Slither Static Analysis:
Slither, a static analysis tool, was employed to identify vulnerabilities in the Solidity code:
a. Slither Setup:
pip3 install slither-analyzer
, preparing the tool for analysis.b. Analysis Execution:
slither .
on the project directory executed static analysis across all contracts, detecting potential issues and vulnerabilities.c. Review and Response to Findings:
Analysis and Testing Insights:
Through this testing process, several key insights about the reNFT project emerged:
Throughout the audit process, my focus was on identifying discrepancies between the project's intended functionality and its actual implementation, assessing adherence to security best practices, and evaluating the overall robustness of the codebase. The combination of meticulous code review, understanding known vulnerabilities, analyzing external insights, and rigorous testing formed the foundation of a comprehensive audit.
The class diagram for the reNFT project illustrates the relationships between key components. At the top level, there's the Kernel
, which acts as a central registry and controller for policies and modules. Module
and Policy
are abstract classes, with Policy
being extended by specific contracts like Create
, Stop
, Guard
, Admin
, and Factory
. These policies define various functionalities of the system, from rental creation (Create
) to rental termination (Stop
) and security (Guard
). Admin
manages administrative tasks, and Factory
is involved in deploying rental safes. Storage
and PaymentEscrow
are modules used by policies for data storage and payment handling, respectively. Create2Deployer
is a utility for deploying contracts. The diagram demonstrates a structured, modular approach in the reNFT project, emphasizing separation of concerns and clear responsibilities among different components.
The reNFT platform is a comprehensive system for NFT rentals, structured around a series of interconnected smart contracts. Each contract plays a pivotal role in facilitating user interactions and managing the rental process, ensuring a seamless and secure experience.
The Kernel.sol contract acts as the administrative center. Its executeAction
function is pivotal in modifying system configurations, such as installing new modules or updating policies. When users initiate a transaction, this function might be called to ensure that the system's settings align with the current operational requirements.
The diagram depicts the architectural structure of Kernel.sol
and its interaction with other core components within the reNFT ecosystem. The Kernel
acts as the central registry, coordinating between Modules
and Policies
. It shows that Modules
communicate internally with Kernel
, which then orchestrates the policies through the KernelAdapter
. Policies define the rules and behaviors for different operations and interact with Kernel
to carry out those operations, while Kernel
also handles errors through the Errors
contract and logs activities via Events
. The Keycode
facilitates the identification and interaction of specific modules within the system.
Storage.sol is essential for maintaining the integrity of rental records. Functions like addRentals
and removeRentals
are crucial for tracking active rentals and removing them post-completion. The addRentals
and removeRentals
functions in the reNFT architecture play pivotal roles beyond their surface-level code functionality. They are not just about adding or removing data entries; they embody the core dynamics of the rental process within the reNFT ecosystem.
Maintaining Rental State: These functions are crucial in maintaining the state of each NFT within the rental ecosystem. addRentals
marks the initiation of a rental contract, transitioning an NFT from a state of availability to one of active rental. Conversely, removeRentals
signifies the conclusion of the rental agreement, resetting the state of the NFT back to available. This state management is vital for ensuring the integrity and consistency of the rental transactions.
Data Integrity and Security: The implementation of these functions underscores the importance of data integrity and security within the reNFT platform. By securely adding and removing rental agreements, these functions uphold the trustworthiness of the platform. This is particularly crucial given the value and uniqueness of NFTs, which can represent significant monetary and sentimental value.
Smart Contract Optimization: From an architectural standpoint, the efficient handling of these functions can significantly impact the overall gas costs and performance of the platform. Optimizing these functions for minimal gas usage without compromising on security or functionality is a key consideration in smart contract development.
User Experience: The seamless execution of addRentals
and removeRentals
is central to the user experience. For lenders, the assurance that their assets are properly tracked and managed during the rental period is paramount. For renters, the clarity of knowing exactly when their rental period starts and ends is crucial for planning and utilization.
Dynamic Pricing Models: These functions could potentially integrate dynamic pricing models based on demand and supply. For instance, addRentals
could implement a pricing algorithm that adjusts rental rates based on the popularity or scarcity of a particular NFT.
NFT Wear and Tear Concept: An innovative concept could be the introduction of a virtual 'wear and tear' metric for NFTs, managed through addRentals
and removeRentals
. Though NFTs don't degrade physically, a usage metric could introduce a new dynamic in the rental market, affecting pricing and desirability.
Integration with External Platforms: These functions could be designed to interface with external platforms or services, such as insurance protocols for NFTs, providing additional layers of security and trust for users.
In PaymentEscrow.sol, financial transactions are managed. The settlePayment
function is responsible for disbursing funds at the end of a rental period, while increaseDeposit
handles incoming payments at the start of a rental. This ensures that users' funds are securely managed throughout the rental process.
The Signer.sol contract is key for authenticating transactions. It employs _recoverSignerFromPayload
to ascertain the legitimacy of transaction initiators, adding a layer of security and ensuring that only authorized actions are executed within the platform.
Reclaimer.sol ensures the safe return of rented assets. The _reclaimRentedItems
function interacts with the rental wallet to transfer assets back to the rightful owner after the rental period, safeguarding users' interests.
The Create.sol contract is central to starting the rental process. As users initiate a rental, this contract processes the transaction, including the validation of rental terms and the setup of the rental agreement, ensuring a smooth start to the rental period.
Accumulator.sol plays a role in managing dynamically allocated data arrays, crucial for adapting to various rental agreement sizes and terms as users engage with different NFTs.
In Factory.sol, the focus is on deploying rental safes, a key element in the rental process. This contract ensures that each rental transaction has a secure and dedicated environment, enhancing user trust in the platform. The deployRentalSafe()
function in this contract is instrumental for creating rental safes, key to managing rental transactions. This function first ensures the specified threshold, which dictates the number of signatures required for executing transactions on the safe, is valid. It then makes a critical delegate call to initialize the safe with necessary policies, particularly the stop policy and guard policy, by invoking the initializeRentalSafe
function. This step is crucial to equip the rental safe with appropriate safeguards.
Next, the function constructs an initializer payload tailored for a Gnosis Safe setup. This payload encapsulates essential details like owners, threshold, and fallback manager address. Utilizing the Gnosis Safe Proxy Factory, the function then deploys a new safe proxy using this payload and a unique salt nonce, ensuring the safe's address uniqueness across different chains.
UML diagram of deployRentalSafe()
is given below for better understanding:
Post deployment, the safe's address is registered within the Factory
contract's storage. This registration is vital for the protocol's recognition and subsequent management of the safe. Finally, the function broadcasts an event to signal the successful deployment of the rental safe, including relevant details such as the safe's address, its owners, and the threshold. This comprehensive process, governed by the deployRentalSafe()
function, thus ensures a standardized, secure, and efficient setup for rental safes, integral to the functionality of the reNFT ecosystem.
Guard.sol acts as a safeguard for transactions originating from rental wallets, ensuring that assets within these wallets are securely managed and only authorized transactions are processed.
Stop.sol is instrumental in concluding rentals. It handles the cessation of rental agreements, ensuring assets are returned and funds are disbursed correctly, thus bringing the rental process to a secure and satisfactory close.
Admin.sol provides administrative functionalities like fee management and whitelist control, ensuring smooth operational governance as users interact with the platform.
The Create2Deployer.sol
contract facilitates efficient and secure contract deployment through a specific Ethereum feature known as CREATE2. This feature provides predictable and reliable address generation for new smart contracts, making it a powerful tool for advanced deployment strategies in the Ethereum ecosystem.
The mechanism of CREATE2 allows for the computation of an address for a new contract before the contract is actually deployed. This is achieved by using a combination of the deployer's address, a user-provided salt (a unique value), and the bytecode of the contract to be deployed. The Create2Deployer.sol
contract uses this feature to ensure that the same contract can be deployed across different blockchains (like Ethereum Mainnet, Polygon, Avalanche, etc.) at the same address, providing a consistent experience across platforms and enhancing trust and recognition among users.
In practice, the Create2Deployer.sol
contract provides a deploy
function where users specify the salt and the bytecode (init code) of the contract they wish to deploy. The contract first validates the salt by ensuring it includes the address of the sender, preventing front-running and ensuring that only authorized parties can deploy specific contracts. It then calculates the target address for the deployment using the CREATE2 opcode, ensuring that the resulting address is unique and has not been deployed to previously. This process is done via the getCreate2Address
function, which returns the address that would be generated for the given parameters.
Once the address is calculated and validated, the contract deploys the new contract to that address using the provided bytecode and salt. This method of deployment is particularly useful in scenarios where the address of a contract needs to be known in advance, such as in the case of cross-chain operations or when interacting with other contracts that require a predefined address.
As users engage with the reNFT platform, they seamlessly interact with these contracts. For example, initiating a rental activates Create.sol for processing the transaction, with Storage.sol and PaymentEscrow.sol managing records and finances. Throughout the rental, Guard.sol and Reclaimer.sol ensure asset security, and upon conclusion, Stop.sol facilitates the return process. Administrative actions, such as fee adjustments, are managed through Admin.sol, while Factory.sol and Create2Deployer.sol play their part in setting up the necessary infrastructure. The entire process is governed and overseen by Kernel.sol, ensuring compliance with the platform's policies and configurations.
Concluding, reNFT's architecture is a multi-faceted framework where each contract is intricately linked to facilitate various stages of the NFT rental process, from initiation to conclusion, ensuring a secure, transparent, and user-friendly experience.
In analyzing the reNFT project from a software engineering perspective, several considerations stand out:
Modularity and Separation of Concerns: The project's structure demonstrates a clear separation into distinct contracts, such as Storage
, PaymentEscrow
, and various policy contracts like Create
, Stop
, Guard
, etc. This modular approach aids in readability, maintainability, and scalability. Each contract addresses specific functionalities, reducing complexity and potential interactions that could lead to vulnerabilities.
Upgradability and Configuration Management: The project appears to employ upgradable contract patterns. This design choice allows for future improvements and bug fixes without redeploying the entire system. However, it also introduces risks associated with proxy patterns and requires careful management of state and initialization logic.
Dependency Management: The project relies on external contracts and standards (like Seaport, ERC721, ERC1155). Managing these dependencies is crucial, especially considering potential changes or updates in these external systems.
Security Practices: The use of onlyRole
and similar modifiers in contracts like Policy
indicates an emphasis on access control and permissions. The project also seems to incorporate patterns for secure interaction with tokens and user assets. However, this necessitates rigorous testing and auditing to ensure that security measures are robust and effective.
Error Handling and Reversion Patterns: The project employs custom error messages (via the Errors.sol
library), improving debuggability and user experience. This practice is preferable over generic failure messages and should be consistently applied across the project.
In the reNFT project, various risks can be identified:
Admin Abuse Risks:
Functions in Admin.sol
like setting fees or toggling whitelist statuses are powerful. If the ADMIN_ADMIN
role is compromised or misused, it could lead to unfavorable changes in protocol parameters, affecting user experience and trust.
Systemic Risks:
The centralized data management in Storage.sol
implies that issues in this contract (like bugs or downtimes) can have widespread implications across the entire platform.
Technical Risks:
Complex logic, especially in contracts like Create.sol
, which handles intricate rental transactions, is susceptible to bugs or exploits. Create.sol:
This contract is responsible for initializing rental orders. Its complex logic, involving interactions with external contracts like Seaport and handling various item types (ERC-721/ERC-1155), poses a risk. Mismanagement or bugs in the processing of orders, especially in functions that convert Seaport order items to rental items, could lead to incorrect asset handling or vulnerabilities in asset transfer logic.
Stop.sol:
This contract deals with stopping rentals and reclaiming assets. The complexity lies in ensuring that assets are returned correctly and securely to the original owners and managing ERC20 payments. Any flaws in functions that handle these operations, such as asset reclamation or payment settlements, could potentially be exploited, leading to loss of assets or incorrect fund distribution.
Guard.sol:
It guards transactions originating from rental wallets. Vulnerabilities could arise from how it manages whitelists or restrictions on function selectors. For example, incorrect handling of whitelisted addresses or allowed function selectors could open up possibilities for unauthorized asset transfers or malicious module activations.
Integration Risks: Dependencies on external contracts, such as Seaport, introduce risks. Any updates or issues in these external contracts can directly impact the reNFT's functionalities.
Non-standard Token Risks:
The handling of ERC20 tokens in contracts like PaymentEscrow.sol
might not be fully compatible with non-standard tokens (e.g., rebasing or fee-on-transfer tokens), which could lead to incorrect processing of token transfers or balances.
In essence, while each of these risks is manageable, they represent areas where the project should exercise caution and implement robust monitoring and mitigation strategies.
Enhancing validation in Guard.sol
, specifically in the _checkTransaction
function, involves implementing a more robust compliance check for the ERC-721 and ERC-1155 token standards. Here's a technical approach to achieve this:
Interface Compliance Check: Implement a function to check if a token contract implements the ERC-721 or ERC-1155 interface. This can be done by calling the supportsInterface
function, which is a part of the ERC-165 standard that both ERC-721 and ERC-1155 implement. For instance:
function isERC721(address token) internal view returns (bool) { return IERC165(token).supportsInterface(type(IERC721).interfaceId); } function isERC1155(address token) internal view returns (bool) { return IERC165(token).supportsInterface(type(IERC1155).interfaceId); }
Enhancing validation in Guard.sol
, specifically in the _checkTransaction
function, involves implementing a more robust compliance check for the ERC-721 and ERC-1155 token standards. Here's a technical approach to achieve this:
Interface Compliance Check: Implement a function to check if a token contract implements the ERC-721 or ERC-1155 interface. This can be done by calling the supportsInterface
function, which is a part of the ERC-165 standard that both ERC-721 and ERC-1155 implement. For instance:
function isERC721(address token) internal view returns (bool) { return IERC165(token).supportsInterface(type(IERC721).interfaceId); } function isERC1155(address token) internal view returns (bool) { return IERC165(token).supportsInterface(type(IERC1155).interfaceId); }
Enhanced Transaction Validation: In the _checkTransaction
function, use the above compliance checks before processing ERC-721 or ERC-1155 related transactions. For example:
if (selector == e721_safe_transfer_from_selector) { require(isERC721(to), "Invalid ERC721 token"); // existing logic... } else if (selector == e1155_safe_transfer_from_selector) { require(isERC1155(to), "Invalid ERC1155 token"); // existing logic... }
Refactoring the deployRentalSafe
function in Factory.sol
involves splitting its complex logic into smaller, focused functions for enhanced clarity and maintainability. This process includes creating distinct functions for validating the threshold requirement, constructing the initializer payload for the Gnosis safe setup, and handling the actual deployment of the safe proxy. Each function should have a clear, descriptive name and be accompanied by comprehensive documentation. After refactoring, thorough unit testing for each new function is essential to ensure their individual and integrated functionality within the deployRentalSafe
process. This approach makes the codebase more readable, easier to debug, and simplifies future updates or maintenance efforts.
This approach ensures that the Guard.sol
contract only interacts with compliant ERC-721 and ERC-1155 tokens, thus mitigating risks associated with non-standard implementations. Additionally, regular audits and reviews of the contract's interaction with token contracts can further enhance security.
The absence of a pause function (or circuit breaker) in critical contracts like Admin.sol could be a potential point of failure, especially in emergency situations. Integrating circuit breakers or a pause mechanism into Admin.sol
, specifically for functions like freezeStorage
and freezePaymentEscrow
, would enhance security. This can be achieved by adding a paused
state variable and a modifier to check this state. The modifier would prevent function execution when the contract is paused:
bool private paused = false; modifier whenNotPaused() { require(!paused, "Contract is paused"); _; } function pause() external onlyRole("ADMIN_ADMIN") { paused = true; } function unpause() external onlyRole("ADMIN_ADMIN") { paused = false; } function freezeStorage() external onlyRole("ADMIN_ADMIN") whenNotPaused { // existing logic } function freezePaymentEscrow() external onlyRole("ADMIN_ADMIN") whenNotPaused { // existing logic }
This design allows the admin to halt critical functionalities in emergencies, thus preventing potential exploits or damage when vulnerabilities are detected. The implementation should ensure that the pause functionality is well-protected and accessible only to authorized roles to prevent misuse.
In Create.sol
, specifically in the function _processBaseOrderOffer
, there's potential for optimization in the loop that processes each offer item. Here's a technical breakdown and recommendation:
The loop iterates over the offers
array to handle ERC721 and ERC1155 items. One optimization strategy could be pre-computing and storing frequently accessed values, such as itemType
, outside the loop. This reduces the need for repeated calculations or lookups within each iteration, saving gas:
for (uint256 i; i < offers.length; ++i) { SpentItem memory offer = offers[i]; // Potential optimization: Pre-compute common conditions or values here if (offer.isERC721()) { // Logic for ERC721 } else if (offer.isERC1155()) { // Logic for ERC1155 } else { // Error handling } }
This optimization targets the repeated checks within the loop, such as offer.isERC721()
and offer.isERC1155()
, potentially reducing the computational cost of these operations. However, it's crucial to balance readability and maintainability with optimization. Each optimization should be thoroughly tested to ensure it doesn't introduce new issues or complexities.
22 hours
#0 - c4-sponsor
2024-01-25T18:13:32Z
Alec1017 (sponsor) acknowledged
#1 - c4-judge
2024-01-27T20:26:42Z
0xean marked the issue as grade-a
#2 - c4-judge
2024-01-27T20:27:49Z
0xean marked the issue as selected for report