Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: low
Valid

Consensus Mechanism Allows Participation Of Voters With Insufficent Stake

Summary

It is possible to participate in voting with insufficient stake.

Vulnerability Details

To participate in consensus, an account must be registered:

/// @notice Reverts if `msg.sender` is not a registered oracle.
modifier onlyRegistered(LLMOracleKind kind) {
if (!registry.isRegistered(msg.sender, kind)) { /// @audit must be registered
revert NotRegistered(msg.sender);
}
_;
}

https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/llm/LLMOracleCoordinator.sol#L80C5-L86C6

Digging into the implementation of isRegistered, we find:

/// @notice Check if an Oracle is registered.
function isRegistered(address user, LLMOracleKind kind) public view returns (bool) {
@> return registrations[user][kind] != 0; /// @audit must have non-zero stake
}

https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/llm/LLMOracleRegistry.sol#L145C5-L148C6

This means, regardless of how much stake is deposited (even if it were just 1 wei), they would be considered a valid participant in consensus.

This mechanism relies upon the assumption that users can only register with valid minimum stakes, since the minimum stake amounts are enforced upon registration:

/// @notice Register an Oracle.
/// @dev Reverts if the user is already registered or has insufficient funds.
/// @param kind The kind of Oracle to unregister.
function register(LLMOracleKind kind) public {
uint256 amount = getStakeAmount(kind); /// @audit determines the correct stake
// ensure the user is not already registered
if (isRegistered(msg.sender, kind)) {
revert AlreadyRegistered(msg.sender);
}
// ensure the user has enough allowance to stake
if (token.allowance(msg.sender, address(this)) < amount) {
revert InsufficientFunds();
}
token.transferFrom(msg.sender, address(this), amount);
// register the user
registrations[msg.sender][kind] = amount; /// @audit ensures a valid minimum stake
emit Registered(msg.sender, kind);
}

https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/llm/LLMOracleRegistry.sol#L91C5-L111C6

However, after registering for the protocol, the protocol owner may choose to increase the minimum stake for the role:

/// @notice Set the stake amount required to register as an Oracle.
/// @dev Only allowed by the owner.
function setStakeAmounts(uint256 _generatorStakeAmount, uint256 _validatorStakeAmount) public onlyOwner {
generatorStakeAmount = _generatorStakeAmount; /// @audit alter minimum stake
validatorStakeAmount = _validatorStakeAmount; /// @audit alter minimum stake
}

https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/llm/LLMOracleRegistry.sol#L133C5-L138C6

This means that if the stake amounts were to be increased, those with inefficient stakes still continue to be recognized as valid stakers, even though they have made an insufficient economic sacrifice.

Impact

Users with insufficient stake are permitted to participate in voting if they had registered prior to an increase in the minimum stake amount.

Tools Used

Manual Review

Recommendations

Enforce the minimum stake for the role:

/// @notice Check if an Oracle is registered.
function isRegistered(address user, LLMOracleKind kind) public view returns (bool) {
- return registrations[user][kind] != 0;
+ return registrations[user][kind] >= getStakeAmount(kind);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Consensus Mechanism Allows Participation Of Voters With Insufficent Stake

Support

FAQs

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