Dria

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

withdrawing platform fees takes Validators/Generators Fees, as well as money paid for incompleted tasks

Description

When doing tasks there are 3 types of fees that the caller should pay.

  • Platform Fees

  • Generator Fees

  • Validator Fees

llm/LLMOracleManager.sol#L110-L120

function getFee(LLMOracleTaskParameters calldata parameters)
public
view
returns (uint256 totalFee, uint256 generatorFee, uint256 validatorFee)
{
uint256 diff = (2 << uint256(parameters.difficulty));
generatorFee = diff * generationFee;
validatorFee = diff * validationFee;
totalFee =
platformFee + (parameters.numGenerations * (generatorFee + (parameters.numValidations * validatorFee)));
}

When taking platform Fees we are taking all money in the contract.

llm/LLMOracleCoordinator.sol#L375-L377

function withdrawPlatformFees() public onlyOwner {
feeToken.transfer(owner(), feeToken.balanceOf(address(this)));
}

When Completing The Task using finalizeValidation(), or when completing tasks that require no validation. We are not sending Fees directly to the Oraacle Registry, we are increasing there allowance so that they can transfer their tokens themselves.

llm/LLMOracleCoordinator.sol#L348 | llm/LLMOracleCoordinator.sol#L369

function finalizeValidation(uint256 taskId) private {
...
for (uint256 g_i = 0; g_i < task.parameters.numGenerations; g_i++) {
...
for (uint256 v_i = 0; v_i < task.parameters.numValidations; ++v_i) {
uint256 score = scores[v_i];
if ((score >= _mean - _stddev) && (score <= _mean + _stddev)) {
...
>> _increaseAllowance(validations[taskId][v_i].validator, task.validatorFee);
}
}
...
}
...
(uint256 stddev, uint256 mean) = Statistics.stddev(generationScores);
for (uint256 g_i = 0; g_i < task.parameters.numGenerations; g_i++) {
// ignore lower outliers
if (generationScores[g_i] >= mean - generationDeviationFactor * stddev) {
>> _increaseAllowance(responses[taskId][g_i].responder, task.generatorFee);
}
}
}

finalizeValidation() will only get fired when completeing the task. But for the caller pays the fees when calling Coordinator::request(), so the fees paid for tasks that didn't yet completed, will also get transfered to the Owner as PlatformFees.

So in brief.

  • When withdrawing Platform Fees All money in the contract will get transferred to the owner.

  • Validators/Generators that didn't withdraw there money (have allowance), will lose their money

  • fees paid for tasks that didn't complete yet but are either in PendingGeneration or PendingValidation, will also get transferred to the owners.

This is incorrect Fees accumulating logic, which will result in an unfair process for validators and Generators when distributing Fees.

Another thing is that there is no way to know exactly what our Validadators or Generators need. Admins will have to query over all there Registered addresses, which is open to anyone. And there are no Events, nor an array that groups them. making the process literally impossible for them to pay the money they own to Validators and Generators.

Recommendations

Accumulate PlatformFees on a global variable, in addition to Fees for outliers, and when withdrawing take this value only, instead of Taking all contract balance.

Updates

Lead Judging Commences

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

`withdrawPlatformFees` withdraws the entire balance

Support

FAQs

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