DeFiHardhat
35,000 USDC
View results
Submission Details
Severity: low
Invalid

Interface definition error.

Summary

The FertilizerFacet.claimFertilized() calls the IFertilizer interface on its beanstalkUpdate() function in amount calculation.
However, the Fertilizer contract does not declare is IFertilizer in its definition.

Vulnerability Details

The claimFertilized() calls IFertilizer.beanstalkUpdate() in uint256 amount = C.fertilizer().beanstalkUpdate(msg.sender, ids, s.bpf);:

function claimFertilized(uint256[] calldata ids, LibTransfer.To mode)
external
payable
{
uint256 amount = C.fertilizer().beanstalkUpdate(msg.sender, ids, s.bpf); // @audit Invoked here
LibTransfer.sendToken(C.bean(), amount, msg.sender, mode);
}

Here is C.fertilizer() that invokes IFertilizer interface:

function fertilizer() internal pure returns (IFertilizer) {
return IFertilizer(FERTILIZER);
}

and here is C.fertilizer.beanstalkUpdate():

function beanstalkUpdate(
address account,
uint256[] memory ids,
uint128 bpf
) external returns (uint256);

However, Fertilizer contract does not declare is IFertilizer in its definition:

contract Fertilizer is Internalizer { // @audit Missing `is IFertilizer`

Though it has the beanstalkUpdate() implementation:

function beanstalkUpdate(
address account,
uint256[] memory ids,
uint128 bpf
) external onlyOwner returns (uint256) {
return __update(account, ids, uint256(bpf));
}

Even if the Fertilizer contract has a beanStalkUpdate() function that matches the signature in the IFertilizer interface, not using is IFertilizer means the contract is not formally considered an implementation of that interface, which affects enforceability & type compatibility.

Impact

The result will cause FertilizerFacet.claimFertilized() to fail forever as there is no implementation of the IFertilizer.beanstalkUpdate() resulting in failure to Rinse Rinsable Sprouts earned from Fertilizer.

Tools Used

Manual Review

Recommendations

The Fertilizer contract needs to declare that it implements the IFertilizer interface through is IFertilizer.

contract Fertilizer is IFertilizer, Internalizer {
// Implement the beanStalkUpdate function from the IFertilizer interface
function beanStalkUpdate() external override {
// Functionality to update the bean stalk
}
}

This setup ensures that any contract or external caller interacting with the Fertilizer contract through the IFertilizer interface can call the beanStalkUpdate() function, relying on the concrete implementation provided within the Fertilizer contract.

Case 2

The LiquidityWeightFacet contract also needs to declare is ILiquidityWeightFacet so that any other contract that tries to invoke the maxWeight() function through the interface can do so since the implementation exists.

contract LiquidityWeightFacet is ILiquidityWeightFacet {
...
}
Updates

Lead Judging Commences

giovannidisiena Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational/Invalid

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.