Summary
It is possible to participate in voting with insufficient stake.
Vulnerability Details
To participate in consensus, an account must be registered:
modifier onlyRegistered(LLMOracleKind kind) {
if (!registry.isRegistered(msg.sender, kind)) {
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:
function isRegistered(address user, LLMOracleKind kind) public view returns (bool) {
@> return registrations[user][kind] != 0;
}
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:
function register(LLMOracleKind kind) public {
uint256 amount = getStakeAmount(kind);
if (isRegistered(msg.sender, kind)) {
revert AlreadyRegistered(msg.sender);
}
if (token.allowance(msg.sender, address(this)) < amount) {
revert InsufficientFunds();
}
token.transferFrom(msg.sender, address(this), amount);
registrations[msg.sender][kind] = amount;
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:
function setStakeAmounts(uint256 _generatorStakeAmount, uint256 _validatorStakeAmount) public onlyOwner {
generatorStakeAmount = _generatorStakeAmount;
validatorStakeAmount = _validatorStakeAmount;
}
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);
}