Platform: Code4rena
Start Date: 08/09/2023
Pot Size: $70,000 USDC
Total HM: 8
Participants: 84
Period: 6 days
Judge: gzeon
Total Solo HM: 2
Id: 285
League: ETH
Rank: 70/84
Findings: 1
Award: $12.79
š Selected for report: 0
š Solo Findings: 0
š Selected for report: castle_chain
Also found by: 0xAadi, 0xHelium, 0xLook, 0xblackskull, 0xfuje, 0xmystery, 0xnev, 0xpiken, 7ashraf, BARW, Bauchibred, Bughunter101, Ch_301, JP_Courses, Kaysoft, Krace, MohammedRizwan, SanketKogekar, Sathish9098, alexzoid, ast3ros, btk, catellatech, degensec, fatherOfBlocks, grearlake, imtybik, jkoppel, jolah1, klau5, lsaudit, m_Rassska, merlin, mrudenko, nobody2018, rokinot, rvierdiiev, sandy
12.7917 USDC - $12.79
Number | Issue | Instances | |
---|---|---|---|
[Lā01] | Prevent newTrancheToken() from being Dos-ed | 1 | |
[Lā02] | Misleading comment in Context.sol as it should be ERC2771 context | 1 | |
[Lā03] | In Tranche.sol , Misleading modifier name restricted() should be notRestricted() | 1 | |
[Lā04] | While setting delay , the contract does not check delay should be less than maxDelay | 1 | |
[Lā05] | The Root.delay will initially be set to 48 hours per docs | 1 | |
[Lā06] | updatePrice() can set the price to 0 | 1 |
newTrancheToken()
from being Dos-edIn Factory.sol
has TrancheTokenFactory
which has newTrancheToken()
which can be Dos-ed or front-run attacker as the salt used does not contain msg.sender
. It is also recommended to add incremented nonce to avoid the incoming front running issue.
There is 1 instance of this issue:
File: src/util/Factory.sol function newTrancheToken( uint64 poolId, bytes16 trancheId, string memory name, string memory symbol, uint8 decimals, address[] calldata trancheTokenWards, address[] calldata restrictionManagerWards ) public auth returns (address) { address restrictionManager = _newRestrictionManager(restrictionManagerWards); // Salt is hash(poolId + trancheId) // same tranche token address on every evm chain >> bytes32 salt = keccak256(abi.encodePacked(poolId, trancheId)); >> TrancheToken token = new TrancheToken{salt: salt}(decimals); // some code }
File: src/util/Factory.sol + /// @notice Mapping to store deployer nonces for CREATE2 + mapping(address deployer => uint256 nonce) public deployerNonces; function newTrancheToken( uint64 poolId, bytes16 trancheId, string memory name, string memory symbol, uint8 decimals, address[] calldata trancheTokenWards, address[] calldata restrictionManagerWards ) public auth returns (address) { address restrictionManager = _newRestrictionManager(restrictionManagerWards); // Salt is hash(poolId + trancheId) // same tranche token address on every evm chain - bytes32 salt = keccak256(abi.encodePacked(poolId, trancheId)); + bytes32 salt = keccak256(abi.encodePacked(poolId, trancheId, msg.sender, deployerNonces[msg.sender]++)); TrancheToken token = new TrancheToken{salt: salt}(decimals); // some code }
Context.sol
as it should be ERC2771
contextIn Context.sol
, There is misleading Natspec as title of contract.
/// @title ERC1271 Context
This is not correct for the context base contract as ERC-1271
is for Standard Signature Validation method whereas ERC2771
talks about secure Protocol for Native Meta Transactions and this also confirms the other Natspecin context.sol
- /// @title ERC1271 Context + /// @title ERC2771 Context
Tranche.sol
, Misleading modifier name restricted()
should be notRestricted()
The modifier checks whether the transfer, mint, transferFrom are restricted per ERC1404. However restricted()
modifier should be notRestricted()
which makes more sense as the modifier first condition would be to check the success code
and in rare case it would revert with error code.
Also refer this ERC1404 implementation to see notRestricted
has been used.
There is 1 instance of this issue:
- modifier restricted(address from, address to, uint256 value) { + modifier NotRestricted(address from, address to, uint256 value) {
delay
, the contract does not check delay
should be less than maxDelay
While setting delay
in Root.sol
constructor. It does not check the delay
must be less than maxDelay
. With current implementation delay
can be set to any value which means it can be delayed indefinately.
/// @dev To prevent filing a delay that would block any updates indefinitely uint256 private MAX_DELAY = 4 weeks;
There is 1 instance of this issue:
constructor(address _escrow, uint256 _delay) { + require(_delay <= MAX_DELAY, "out of range delay"); escrow = _escrow; delay = _delay; wards[msg.sender] = 1; emit Rely(msg.sender); }
Per contest readme.md states,
The Root.delay will initially be set to 48 hours.
However this is not implemented in contract.
There is 1 instance of this issue:
uint256 public delay;
The Root.delay() should be set to to 48 hours per contest readme.md
updatePrice()
can set the price to 0updatePrice can be used to update the price, however if it is set to zero. Everything multiplied with price will be zero too.
function updatePrice(uint128 price) public auth { latestPrice = price; lastPriceUpdate = block.timestamp; emit UpdatePrice(price); }
Add price is not equal to 0 validation check.
function updatePrice(uint128 price) public auth { + require(price != 0, "invalid price"); latestPrice = price; lastPriceUpdate = block.timestamp; emit UpdatePrice(price); }
#0 - c4-pre-sort
2023-09-17T01:49:33Z
raymondfam marked the issue as sufficient quality report
#1 - c4-judge
2023-09-26T17:34:23Z
gzeon-c4 marked the issue as grade-b