Platform: Code4rena
Start Date: 16/12/2021
Pot Size: $100,000 USDC
Total HM: 21
Participants: 25
Period: 7 days
Judge: alcueca
Total Solo HM: 12
Id: 66
League: ETH
Rank: 15/25
Findings: 2
Award: $1,353.07
π Selected for report: 4
π Solo Findings: 0
Ruhum
The contract's setAddresses()
function used to initialize it can be called by anybody. It makes it susceptible to being front-run. Somebody else initializes the contract without the original deployer being able to change it since it can only be initialized once. There should be access controls so only the owner is able to initialize it.
none
add access controls
#0 - kingyetifinance
2022-01-05T17:35:49Z
@LilYeti: duplicate with #105
Ruhum
Assigning a new address to be in control of a contract should always be done in a two-step process. Otherwise, you might potentially lose access by assigning it to an address for which you don't have the key. By using a two-step process you make sure that everything works as expected.
Using the current owner you assign a new pending owner. Using the pending owner you then claim ownership. The current owner is then overwritten by the pending one and the pending owner address is cleared.
none
Check out the Compound Timelock contract as an example: https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol#L45-L58
#0 - kingyetifinance
2022-01-05T17:26:04Z
@LilYeti: Duplicate #115 . Severity there is 1.
#1 - alcueca
2022-01-15T06:06:31Z
Duplicate of #251
π Selected for report: Ruhum
531.2947 USDC - $531.29
Ruhum
All the other passed variables are checked. Only _whitelistAddress
is ignored. This allows passing a zero function which would break the functionality.
none
add checkContract(_whitelistAddress)
#0 - kingyetifinance
2022-01-05T17:30:10Z
@LilYeti: This is quite niche risk during deployment but is an issue nonetheless.
#1 - 0xtruco
2022-01-11T11:41:56Z
resolved
Ruhum
Structs should always be packed to save gas
none
Pack structs, e.g.:
// unpacked, higher gas (6 storage slots): struct CollateralParams { uint256 ratio; address oracle; uint256 decimals; bool active; address priceCurve; uint256 index; bool isWrapped; } // packed (needs 5 storage slots) struct CollateralParams { uint256 ratio; uint256 decimals; uint256 index; address oracle; bool active; address priceCurve; bool isWrapped; }
#0 - kingyetifinance
2022-01-06T09:11:04Z
@LilYeti : Duplicate with #4 #5 and #6
#1 - alcueca
2022-01-14T21:26:05Z
Taking as main
π Selected for report: Ruhum
97.5905 USDC - $97.59
Ruhum
View functions consume less gas. WJLP.getPendingRewards()
is technically also a view function but not specified as one. Because the IMasterChefJoeV2
interface used by the contract is wrong. It says poolInfo()
is not a view function, which it is.
getPendingRewards: https://github.com/code-423n4/2021-12-yetifinance/blob/main/packages/contracts/contracts/AssetWrappers/WJLP/WJLP.sol#L190
Faulty interface function: https://github.com/code-423n4/2021-12-yetifinance/blob/main/packages/contracts/contracts/AssetWrappers/WJLP/WJLP.sol#L29
actually poolinfo is just an array so its getter is a view function: https://github.com/traderjoe-xyz/joe-core/blob/main/contracts/MasterChefJoeV2.sol#L85
none
Declare both functions as view
to save gas
#0 - 0xtruco
2022-01-14T09:24:56Z
Resolved
π Selected for report: Ruhum
531.2947 USDC - $531.29
Ruhum
The Ownable contract used in the codebase doesn't allow transferring the ownership to a different address.
Most contracts that make use of Ownable always guard only a single function which after being called renounces the ownership. In that case, it should be fine since those are functions used to configure the contracts which make them usable, to begin with.
But, there are two contracts that don't renounce their ownership. Since those contracts want to keep ownership, it might come in handy in the future to be able to transfer the ownership to another address. As it is, the owner key is a single point of failure since there's no way to assign access to a different address.
Contracts that don't renounce ownership:
Ownable contract used throughout the codebase: https://github.com/code-423n4/2021-12-yetifinance/blob/main/packages/contracts/contracts/Dependencies/Ownable.sol
none
Either add the transfer functionality to the base contract or to the two contracts which don't want to renounce their ownership.
Also, consider using a two-step process to be safe. Here's an example from Compound's Timelock contract
#0 - kingyetifinance
2022-01-05T17:27:44Z
@LilYeti: Agree but should be severity level 1.
#1 - alcueca
2022-01-15T16:41:26Z
Assets are not at risk, and the protocol isn't at risk of leaking value or lose features. Low severity.