Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: high
Invalid

Lack of slippage control can cause Oracles to pay excess fee

Summary

Accounts registering with the LLMOracleRegistry can pay excess fee due to lack of slippage control on the fee

Vulnerability Details

Accounts that are eligible to respond to LLM requests are registered with LLMOracleRegistry and pay a fee:

/// @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);
// 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;
emit Registered(msg.sender, kind);
}

The vulnerability arises from the fact that this fee can be changed by admin at anytime:

/// @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;
validatorStakeAmount = _validatorStakeAmount;
}

Consider a case where an Oracle wishes to register both as a generator and validator. In order to save on gas fee, the account approves tokens to the LLMOracleRegistry in one transaction with the total amount required to register as generator and validator. The account then sends a register transaction. At the same time, admin wishes to increase the stake fee. He therefore also sends a setStakeAmounts transaction, but with a higher gas fee than the Oracle. The block validator choses to prioritize the admin's transaction ahead of the register transaction. The end result is that the Oracle's registration will be processed at a higher fee than anticipated.

For a POC, consider the case when admin changes the fee after Oracle has already approved tokens:

it("register generator oracle can pay more fee", async function () {
const amount = GENERATOR_STAKE + VALIDATOR_STAKE;
await token.connect(oracle).approve(oracleRegistryAddress, amount);
const allowance = await token.allowance(oracle, oracleRegistryAddress);
expect(allowance).to.equal(amount);
const NEW_GENERATOR_STAKE = ethers.parseEther("0.2");
await oracleRegistry.connect(dria).setStakeAmounts(NEW_GENERATOR_STAKE,VALIDATOR_STAKE);
await expect(oracleRegistry.connect(oracle).register(OracleKind.Generator))
.to.emit(oracleRegistry, "Registered")
.withArgs(oracle.address, OracleKind.Generator);
expect(await oracleRegistry.isRegistered(oracle.address, OracleKind.Generator)).to.equal(true);
await expect(oracleRegistry.connect(oracle).register(OracleKind.Validator)).to.revertedWithCustomError(
oracleRegistry,
"InsufficientFunds"
);
// we have not yet registered as a validator
expect(await oracleRegistry.isRegistered(oracle.address, OracleKind.Validator)).to.equal(false);
});

Impact

Oracles can pay higher fee than anticipated.

Tools Used

Manual review

Recommendations

Consider introducing a maxFee input parameter for the register function.

Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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