Platform: Code4rena
Start Date: 23/02/2024
Pot Size: $92,000 USDC
Total HM: 0
Participants: 47
Period: 10 days
Judge: 0xTheC0der
Id: 336
League: ETH
Rank: 39/47
Findings: 1
Award: $22.02
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: roguereggiant
Also found by: 0xepley, Aamir, Al-Qa-qa, LinKenji, MSK, McToady, Myd, SAQ, Sathish9098, ZanyBonzy, aariiif, cudo, emerald7017, fouzantanveer, hassanshakeel13, hunter_w3b, ihtishamsudo, kaveyjoe, peanuts
22.023 USDC - $22.02
This report thoroughly examines the security & risk aspects of the UniStaker Infrastructure. Its purpose is to improve the security & functionality of the project. The analysis points potential risk & attack surfaces, offering practical recommendations for addressing them.
These contracts enable Uniswap Governance to manage fees on V3 pools, while maintaining a approach to fee assets. The generated revenue is shared with stakers in the form of a custom token. Stakers accumulate rewards when their tokens are actively staked, & this earning ceases when they withdraw. Additionally, stakers have the flexibility to designate someone else to receive their rewards. Upon governance approval, ownership permanently transitions to this system, allowing for the incorporation of additional contracts for future rewards.
The analysis process spanned 16 hours, I starting with a deep dive into the contract architecture followed by examination of the code for problems & concluding with of risks & recommendations.
There are 4 Interfaces in the scope as well but i will focus on main contracts whick are listed below:
<table><thead><tr><th>Contract</th><th>SLOC</th><th>Purpose</th><th>Libraries used</th></tr></thead><tbody><tr><td><em>Contracts (3)</em></td><td></td><td></td><td></td></tr><tr><td><a href="https://github.com/code-423n4/2024-02-uniswap-foundation/blob/main/src/UniStaker.sol">src/UniStaker.sol</a></td><td>423</td><td>This contract manages the distribution of rewards to stakers.</td><td><a href="https://openzeppelin.com/contracts/"><code>@openzeppelin/*</code></a></td></tr><tr><td><a href="https://github.com/code-423n4/2024-02-uniswap-foundation/blob/main/src/V3FactoryOwner.sol">src/V3FactoryOwner.sol</a></td><td>87</td><td>A contract that can serve as the owner of the Uniswap v3 factory and manages configuration and collection of protocol pool fees.</td><td><a href="https://openzeppelin.com/contracts/"><code>@openzeppelin/*</code></a></td></tr><tr><td><a href="https://github.com/code-423n4/2024-02-uniswap-foundation/blob/main/src/DelegationSurrogate.sol">src/DelegationSurrogate.sol</a></td><td>8</td><td>A dead-simple contract whose only purpose is to hold governance tokens on behalf of stakers while delegating voting power to a specific delegatee.</td><td>None</td></tr></tbody></table>High-Level Access Functions:
UniStaker.sol
& V3FactoryOwner.sol
, that these functions can be used as advantage by hacker if access control checks are bypassed or improperly implemented, allowing unauthorized users to alter critical settings or steal funds. Without suitable validation this could become a failure.No Limits When Setting Fees:
V3FactoryOwner.sol
, there is absence of validation on fee settings that could lead to setting excessively high or zero fees, potentially disrupting the system. A lack of checks in the system could lead to operational risks of the system.Loss of Precision:
UniStaker.sol
involving division could result in rounded down outcomes, leading to incorrect reward calculations or Division by large numbers might cause loss of precision.Missing Zero Address Check in Constructor:
UniStaker.sol
& DelegationSurrogate.sol
constructors do not have require/validation against the zero address for parameters. This could lead to contracts being initialized with invalid state, rendering them dysfunctional or open to dos attacks.Approve type(uint256).max May Not Work with Some Tokens:
DelegationSurrogate.sol
it employs an approval pattern that grants maximum allowance. This approach might not be compatible with all ERC-20 tokens, a token that doesn't uses standard implementations, would be resulting in failed transactions or unexpected contract behaviors.Division by Zero Not Prevented:
Division by a Scale Factor:
There is several potential attack surfaces, including them but not limited to:
Too much dependence on the owner for critical functions introduces centralization making the system vulnerable to single points of failure or malicious actions by the owner. The contracts design & token standards may not be fully compatible across different EVM-compatible chains limiting integration. The use of approve with type(uint256).max could lead to unexpected failures with non-standard tokens. Some patterns & operations in the contracts may lead to higher gas costs affecting the overall efficiency of the system.
The UniStaker Infrastructure exhibits a well approach to staking & governance. However, the identified Risks & architectural concerns highlight the necessity for continuous security practices & improvements. Addressing these issues through the recommended mitigation strategies will not only enhance the project's security posture but also its operational efficiency & user trust.
Future work should focus on access control mechanisms, optimizing gas usage, & ensuring cross chain compatibility to the protocol's resilience & adaptability in the DeFi landscape. Transitioning towards a more decentralized governance structure could mitigate risks associated with centralization & enhance community trust & protocol resilience.
By addressing these identified problems & giving to the recommended mitigation strategies, the UniStaker Infrastructure can significantly improve its system & security, compatibility, & decentralization ensuring the project remains robust against problems & threats while providing the needs of its users.
This section includes some code snippets related to identified risks a closer look at issues & where improvements can be made.
function setAdmin(address _newAdmin) external { _revertIfNotAdmin(); // Risk Point _setAdmin(_newAdmin); }
Issue: Lack of sufficient access control beyond the _revertIfNotAdmin check could lead to unauthorized changes.
function unclaimedReward(address _beneficiary) public view returns (uint256) { return unclaimedRewardCheckpoint[_beneficiary] + ( earningPower[_beneficiary] * (rewardPerTokenAccumulated() - beneficiaryRewardPerTokenCheckpoint[_beneficiary]) ) / SCALE_FACTOR; // Potential Precision Loss }
Issue: Division without prior validation could result in precision loss or unexpected behavior.
function calculateReward(uint256 amount) public view returns (uint256) { require(SCALE_FACTOR != 0, "SCALE_FACTOR cannot be zero"); // Recommended fix return (amount * rewardRate) / SCALE_FACTOR; }
Issue: Without ensuring the SCALE_FACTOR or any divisor is non-zero, the division operation is at risk of causing a revert, disrupting the contract's functionality.
UniStaker.sol Constructor:
constructor(IERC20 _rewardToken, IERC20Delegates _stakeToken, address _admin) { require(_admin != address(0), "Admin address cannot be zero"); // Recommended fix REWARD_TOKEN = _rewardToken; STAKE_TOKEN = _stakeToken; _setAdmin(_admin); }
Issue: Original constructor lacks a check for _admin being the zero address, which is critical for ensuring the contract is initialized with valid parameters.
DelegationSurrogate.sol Approval Pattern:
_token.approve(msg.sender, type(uint256).max);
Issue: This pattern assumes all ERC-20 tokens will accept & correctly handle an approval of type(uint256).max, which may not hold true for tokens with non-standard behaviors.
16 hours
#0 - c4-judge
2024-03-14T18:16:30Z
MarioPoneder marked the issue as grade-b