Platform: Code4rena
Start Date: 27/11/2023
Pot Size: $36,500 USDC
Total HM: 0
Participants: 22
Period: 8 days
Judge: 0xA5DF
Id: 308
League: ETH
Rank: 9/22
Findings: 2
Award: $641.36
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: hunter_w3b
Also found by: 0x11singh99, 0xVolcano, IllIllI, Sathish9098
72.7885 USDC - $72.79
The EVM uses 32-byte words, allowing variables smaller than 32 bytes to be packed together in one storage slot if their combined size is ≤32 bytes. Accessing these packed variables saves roughly 2000 gas per SLOAD, costing only 100 gas ('Gwarmaccess') compared to 2100 gas ('Gcoldsload') for separate slots.
_ERC1155InteractionStatus
, _ERC721InteractionStatus
can be packed with same SLOT : Saves 2000 GAS
, 1 SLOT
The value of _ERC1155InteractionStatus
and _ERC721InteractionStatus
values always interchanged between NOT_INTERACTION
, INTERACTION
constant values . So uint128 perfectly safe instead of uint256. This will not harm protocol and perfectly safe conversion.
FILE: 2023-11-shellprotocol/src/ocean/Ocean.sol 106: uint256 constant NOT_INTERACTION = 1; 107: uint256 constant INTERACTION = 2; - 108: uint256 _ERC1155InteractionStatus; - 109: uint256 _ERC721InteractionStatus; + 108: uint128 _ERC1155InteractionStatus; + 109: uint128 _ERC721InteractionStatus;
There are a few instances where state variables are assigned to local variables but are only used once. These can be optimized by directly using the state variable in the expression.
FILE: 2023-11-shellprotocol/src/adapters/Curve2PoolAdapter.sol function wrapToken(uint256 tokenId, uint256 amount) internal override { - address tokenAddress = underlying[tokenId]; Interaction memory interaction = Interaction({ - interactionTypeAndAddress: _fetchInteractionId(tokenAddress, + interactionTypeAndAddress: _fetchInteractionId(underlying[tokenId], uint256(InteractionType.WrapErc20)), inputToken: 0, outputToken: 0, specifiedAmount: amount, metadata: bytes32(0) }); IOceanInteractions(ocean).doInteraction(interaction); }
Modulus operations should be unchecked to save gas since they cannot overflow or underflow. Execution of modulus operations outside unchecked blocks adds nothing but overhead. Saves about 30 gas.
FILE: 2023-11-shellprotocol/src/ocean/Ocean.sol 1145: truncatedAmount = amountToConvert % shift;
We can use assembly to efficiently validate msg.sender with the least amount of opcodes necessary. For more details check the following report Here
FILE : 2023-11-shellprotocol/src/adapters/OceanAdapter.sol 39: require(msg.sender == ocean);
#0 - c4-pre-sort
2023-12-10T17:21:53Z
raymondfam marked the issue as sufficient quality report
#1 - c4-judge
2023-12-17T09:35:50Z
0xA5DF marked the issue as grade-b
#2 - IllIllI000
2023-12-18T16:06:28Z
G-3 is invalid
#3 - 0xA5DF
2023-12-18T16:30:54Z
It seems that it is:
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; contract ControlContract{ function control(uint a, uint b) public returns (uint256) { return a % b; } } contract TestContract{ function control(uint a, uint b) public returns (uint256) { unchecked{ return a % b; } } }
#4 - IllIllI000
2023-12-18T16:41:11Z
If it were specific to the modulo operator, it would have gas savings every time. This is an example where there is no difference: https://gist.github.com/IllIllI000/e00053e60f1a528b33e6e5a6fa59ee35
#5 - 0xA5DF
2023-12-18T16:49:14Z
Got it, I've marked this off, it doesn't make a significant difference
🌟 Selected for report: Sathish9098
Also found by: 0xSmartContract, 0xepley, LinKenji, Myd, ZanyBonzy, albahaca, alexbabits, clara, foxb868, invitedtea, oakcobalt, peanuts
568.5719 USDC - $568.57
Shell Protocol is a decentralized finance (DeFi) platform designed to simplify and enhance the DeFi experience for both users and developers
One-Click Transactions
: Shell Protocol aims to streamline the user experience by offering powerful, one-click transactions. This feature is particularly beneficial for those new to DeFi or those seeking a more efficient and less complex interaction with DeFi services.
Capital-Efficient Automated Market Makers (AMMs)
: At the heart of Shell Protocol is its set of Automated Market Makers, which are touted for their exceptional capital efficiency. This means that liquidity providers can expect better returns on their assets, and traders can enjoy lower slippage and more stable prices. The AMMs are designed to be robust and flexible, catering to a wide range of financial assets.
Modular Developer Experience
: Recognizing the diverse needs of DeFi developers, Shell Protocol offers a modular design. This approach allows developers to easily integrate Shell's features into their projects or to build on top of the platform. The modular design also facilitates customization and scalability, enabling developers to create tailored DeFi solutions.
196: function changeUnwrapFee(uint256 nextUnwrapFeeDivisor) external override onlyOwner {
This modifier restricts the execution of the function to the owner of the contract.
Risk
: If the owner account is compromised, the attacker could manipulate the unwrap fee, potentially causing financial loss to users or destabilizing the protocol. Additionally, even without malicious intent, the owner has significant power to alter contract parameters, which can lead to a lack of trust if changes are made arbitrarily or without community consensus.
289: onlyApprovedForwarder(userAddress)
This modifier likely allows only an approved forwarder address, linked to the userAddress, to execute the function.
Risk
: The implementation details of how a forwarder is approved are crucial. If the process of approving forwarders is not decentralized or transparent, it can lead to centralization risks where the administrator could favor certain forwarders. Also, if the mechanism for approval is not secure, it might be susceptible to manipulation, allowing unauthorized entities to act as forwarders.
64: onlyOcean
This modifier restricts function execution to addresses authorized by the Ocean protocol.
Risk
: Similar to onlyOwner, this creates a single point of failure. If the Ocean authority is compromised or acts maliciously, they could potentially manipulate these functions for personal gain or disrupt the protocol's operations. This risk is compounded if the Ocean authority has a broad range of powers over many aspects of the protocol.
Decentralized Governance
: Transitioning from a single owner model to a decentralized governance structure can mitigate risks associated with the onlyOwner modifier. This would involve community members or token holders voting on critical decisions, thus distributing power.
Transparent Approval Process
: For the onlyApprovedForwarder modifier, ensuring a transparent and secure process for approving forwarders is essential. This might include community oversight or stringent security checks.
Role Rotation and Multi-Signature Controls
: Implementing multi-signature wallets and regularly rotating the roles responsible for critical functions can reduce risks associated with the onlyOcean modifier. This ensures that no single entity has prolonged, unchecked control.
The contract manages fees for wrapping and unwrapping tokens, particularly with ERC-20 and ERC-1155 tokens. Any miscalculation or manipulation in fee management can lead to economic vulnerabilities, affecting user incentives and the protocol's sustainability.
The forwardedDoInteraction and forwardedDoMultipleInteractions functions, which use onlyApprovedForwarder, introduce additional risks. If the logic for approving forwarders is flawed or if a forwarder is compromised, it could lead to unauthorized or malicious transactions.
The contract checks for slippage limits (SLIPPAGE_LIMIT_EXCEEDED). If the actual output amount of a swap, deposit, or withdrawal is lower than the user's expected minimum, the transaction is reverted. This mechanism can protect users from high slippage, but if not calibrated correctly, it could also lead to failed transactions during high volatility, impacting the user experience and trust in the protocol.
The contract grants maximum (type(uint256).max) approval to the ocean and primitive addresses for ERC20 tokens. While this is a common pattern to reduce transaction costs, it also means that if either of these addresses is compromised, it could lead to the loss of user funds.
The contract uses _convertDecimals for normalizing token amounts to the Ocean's 18-decimal standard. Inaccuracies or rounding errors in these conversions could lead to financial discrepancies, especially for tokens with different decimal standards.
The logic for wrapping and unwrapping tokens is intricate, with multiple points of interaction with the contract's state and external tokens. Bugs or flaws here could lead to incorrect token balances or loss of funds.
The contract's apparent lack of upgradeability means that addressing any discovered vulnerabilities or design issues could be challenging, posing long-term systemic risks in a rapidly evolving DeFi landscape.
The complex operations of the contract may lead to high gas costs, affecting its usability and performance, especially during times of network congestion.
The contract interacts with multiple token standards, each with its own set of rules and potential edge cases. This complexity increases the risk of bugs or security vulnerabilities, especially when dealing with the intricacies of each standard, like ERC721 and ERC1155's safe transfer mechanisms.
The _determineComputeType function determines the action (swap, deposit, withdraw) based on input and output tokens. Incorrect implementation or manipulation of this logic could lead to unintended contract behaviors, affecting liquidity operations and user funds.
Given the interconnected nature of DeFi, changes or updates in other protocols that interact with the Curve 2pool could inadvertently affect the adapter's functionality, leading to systemic risks in the broader ecosystem.
The contract uses indexOf mapping to associate Ocean IDs with their corresponding Curve pool indices. Any incorrect mapping or updates to these indices could result in failed transactions or incorrect swaps, impacting liquidity and user funds.
Protocol interoperability, especially in the context of the Curve2PoolAdapter and Ocean contracts within the DeFi ecosystem, refers to the ability of these systems to work together seamlessly. Given that DeFi protocols often rely on each other's functionalities and data, interoperability is crucial for their collective success and user trust.
Smart Contract Interface Compatibility:
Data Format and Standardization:
Handling Protocol-Specific Logic:
Curve Finance pools, like the 2pool, have unique mechanics, such as variable fees, slippage calculations, and liquidity dynamics.
The Curve2PoolAdapter must accurately incorporate these mechanics into its logic to ensure that operations like token swaps or liquidity management reflect the underlying Curve pool's state.
State Synchronization and Updates:
The state of one protocol (like liquidity levels in Curve pools) can affect the decisions and operations in another (like optimal routing in the Ocean contract).
Ensuring real-time or near-real-time synchronization of state information across protocols is vital for maintaining operational accuracy.
--------------------------------------|----------|----------|----------|----------|----------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Lines |
---|---|---|---|---|---|
adapters\ | 0 | 0 | 0 | 0 | |
Curve2PoolAdapter.sol | 0 | 0 | 0 | 0 | ... 213,215,217 |
CurveTricryptoAdapter.sol | 0 | 0 | 0 | 0 | ... 281,285,287 |
ICurve2Pool.sol | 100 | 100 | 100 | 100 | |
ICurveTricrypto.sol | 100 | 100 | 100 | 100 | |
OceanAdapter.sol | 0 | 0 | 0 | 0 | ... 153,156,157 |
forwarder\ | 100 | 100 | 100 | 100 | |
VestingFractionalizerForwarder.sol | 100 | 100 | 100 | 100 | |
mock\ | 92.16 | 70 | 90 | 95.6 | |
ConstantSum.sol | 100 | 100 | 100 | 100 | |
ERC1155MintsToDeployer.sol | 100 | 100 | 100 | 100 | |
ERC20MintsToDeployer.sol | 100 | 100 | 100 | 100 | |
ERC721MintsToDeployer.sol | 100 | 100 | 100 | 100 | |
Forwarder.sol | 100 | 100 | 100 | 100 | |
Interfaces.sol | 100 | 100 | 100 | 100 | |
MaliciousPrimitive.sol | 50 | 50 | 71.43 | 75 | 59,85 |
MockPrimitive.sol | 91.67 | 50 | 87.5 | 95.83 | 128 |
Receive1155.sol | 100 | 100 | 100 | 100 | |
RecursiveMaliciousPrimitive.sol | 92.86 | 70 | 87.5 | 96.55 | 139 |
ocean\ | 100 | 94.77 | 100 | 100 | |
BalanceDelta.sol | 100 | 83.33 | 100 | 100 | |
ERC1155PermitSignatureExtension.sol | 100 | 100 | 100 | 100 | |
IOceanFeeChange.sol | 100 | 100 | 100 | 100 | |
IOceanPrimitive.sol | 100 | 100 | 100 | 100 | |
IOceanToken.sol | 100 | 100 | 100 | 100 | |
Interactions.sol | 100 | 100 | 100 | 100 | |
Ocean.sol | 100 | 100 | 100 | 100 | |
OceanERC1155.sol | 100 | 91.3 | 100 | 100 | |
proteus\ | 58.41 | 45 | 64.38 | 62.83 | |
EvolvingProteus.sol | 0 | 0 | 0 | 0 | ... 818,820,823 |
ILiquidityPoolImplementation.sol | 100 | 100 | 100 | 100 | |
LiquidityPool.sol | 100 | 93.33 | 100 | 100 | |
LiquidityPoolProxy.sol | 100 | 69.44 | 100 | 100 | |
Proteus.sol | 95.58 | 57.84 | 95.45 | 85.55 | ... 691,695,697 |
Slices.sol | 100 | 50 | 100 | 100 | |
script\ | 0 | 100 | 0 | 0 | |
DeployCurve2PoolAdapter.s.sol | 0 | 100 | 0 | 0 | 13,15,16 |
DeployCurveTricryptoAdapter.s.sol | 0 | 100 | 0 | 0 | 13,15,16 |
DeployOcean.s.sol | 0 | 100 | 0 | 0 | 13,15,16 |
test\fork\ | 0 | 0 | 0 | 0 | |
TestCurve2PoolAdapter.t.sol | 0 | 0 | 0 | 0 | ... 225,226,227 |
TestCurveTricryptoAdapter.t.sol | 0 | 0 | 0 | 0 | ... 429,430,431 |
-------------------------------------- | ---------- | ---------- | ---------- | ---------- | ---------------- |
All files | 54.76 | 51.9 | 68.02 | 56.39 | |
-------------------------------------- | ---------- | ---------- | ---------- | ---------- | ---------------- |
The Ocean contract, as provided, is a comprehensive Solidity contract designed for DeFi applications, primarily focusing on the management and interaction of various token standards
The contract supports interactions with multiple token types including ERC-20, ERC-721, and ERC-1155. It provides functionalities for wrapping and unwrapping these tokens. Wrapping converts tokens into a standard format within the contract, while unwrapping allows users to extract their original tokens.
Functions like doInteraction and doMultipleInteractions allow the contract to process both individual and batch interactions. These interactions involve executing calls to external contracts and updating the contract's state (like minting and burning tokens) based on these interactions.
The contract includes a mechanism to handle fees, particularly for unwrapping tokens. This is managed through the unwrapFeeDivisor, which calculates the fee for unwrapping operations.
The contract inherits from OceanERC1155 and implements interfaces such as IOceanInteractions, IOceanFeeChange, IERC721Receiver, and IERC1155Receiver. This indicates a modular design approach and compliance with ERC standards. It uses OpenZeppelin contracts for standard functionalities related to ERC token interfaces, indicating a reliance on established and tested implementations.
The contract appears to incorporate reentrancy guards, as indicated by the use of constants like NOT_INTERACTION and INTERACTION and related state variables. It includes access control mechanisms, though the specific implementation details are not fully provided in the snippet.
Several events are declared, which are crucial for logging and tracking transactions within the contract. Custom modifiers, like onlyApprovedForwarder, are used for controlling access to certain functions.
Modularity and Reusability:
The contract exhibits modularity by inheriting from several interfaces and contracts, suggesting components are designed for reuse and extension. This approach aligns with solid software engineering principles, promoting maintainability and scalability.
Design Patterns and Best Practices:
Utilization of established design patterns, such as interface-based programming and reentrancy guards, indicates adherence to industry best practices. These patterns enhance the contract’s robustness and security.
Code Readability and Maintainability:
The contract's structure, naming conventions, and comments suggest an emphasis on readability and maintainability, crucial for long-term management and updates.
Security:
Security is a critical aspect, especially given the DeFi context. The contract shows awareness of common vulnerabilities (like reentrancy attacks) and includes mechanisms to mitigate them. Continuous security audits and reviews are essential due to the evolving nature of smart contract exploits.
Efficiency and Optimization:
Functions like doMultipleInteractions suggest a focus on optimizing transactions, likely to reduce gas costs. However, given the contract's complexity, there's a need for thorough analysis and testing to ensure efficiency, especially in gas usage.
Error Handling and Input Validation:
The use of custom error messages and checks indicates a proactive approach to error handling and input validation, critical for robustness and user trust.
Interoperability and Standards Compliance:
Compliance with ERC standards and the ability to interact with multiple token types demonstrate a high level of interoperability, a significant factor in the Ethereum ecosystem.
Testing and Documentation:
Given the complexity, comprehensive testing (unit tests, integration tests) and detailed documentation are vital for ensuring the contract works as intended and to facilitate future development.
Upgradeability:
The potential for future upgrades and modifications should be considered, especially in a rapidly evolving domain like DeFi. However, the contract doesn’t explicitly mention upgrade mechanisms.
Dependency Management:
Reliance on external libraries like OpenZeppelin means the contract's security and functionality are partly dependent on these external components. Keeping these dependencies updated and secure is crucial.
20 Hours
20 hours
#0 - c4-pre-sort
2023-12-10T16:56:24Z
raymondfam marked the issue as sufficient quality report
#1 - c4-judge
2023-12-17T11:42:57Z
0xA5DF marked the issue as selected for report