Clean Hemp Barracuda
Medium
The executeOrder
function in the Manager
contract miscalculates keeper fees by excluding the gas consumed during the fee handling process itself. This results in undercompensation for keepers, as the fee calculation does not account for the entire gas usage of the transaction.
https://github.com/sherlock-audit/2025-01-perennial-v2-4-update/blob/main/perennial-v2/packages/periphery/contracts/TriggerOrders/Manager.sol#L145
the applicableGas is startGas (before the order execution) minus gasleft() after the order execution but before the keeper fee handling. So the gas used for the order execution is captured, but the gas used for the keeper fee handling itself is not included. However, the keeper fee handling is part of the transaction, so the fee should cover the entire gas used, including the _handleKeeperFee logic.
But in the current code, applicable Gas does not include the gas used by _handleKeeperFee. This could lead to underpayment because the keeper's gas cost includes the fee handling, but the fee calculation doesn't account for it.
For example:
- Keeper calls execute Order, gas used for executing the order is 80,000.
- Then, applicable Gas is 80,000, fee is calculated based on that.
- But the *handleKeeperFee function itself consumes gas (e.g., 20,000), so total gas used is 100,000. However, the keeper is only compensated for 80,000, leading to a loss
This is a flaw because the keeper's total gas usage includes the fee handling, but the fee calculation doesn't include it.
This would result in the keeper being undercompensated for the full gas cost of the transaction, including the fee handling logic.
The fix would be to measure the gas used after all operations, including the _handleKeeperFee. However, in the current code, applicableGas is calculated before calling *handleKeeperFee, so the gas used by *handle KeeperFee is not included.
No response
No response
Scenario:
- Keeper Action: Bob executes an order, consuming 80,000 gas for order logic and 20,000 gas for fee handling.
- Fee Calculation:
applicableGas = 80,000
(order logic only).fee = (80,000 + buffer) * gasPrice
.
- Outcome:
- Keeper is paid for 80,000 gas but spent 100,000 gas (total transaction).
- Loss: 20,000 gas per transaction. Keepers stop executing orders over time.
Code Reference:
function executeOrder(...) external {
uint256 startGas = gasleft();
// ... order execution logic ...
uint256 applicableGas = startGas - gasleft(); // Measures gas used by order logic only
_handleKeeperFee(...); // Additional gas used here is not tracked
}
- Underpaid Keepers: Keepers incur gas costs for both executing the order and processing the fee, but are only reimbursed for the former. This leads to financial losses for keepers.
- Protocol Dysfunction: Persistent underpayment discourages keepers from executing orders, causing order backlog and degraded user experience.
No response
- Measure Total Gas: Calculate
applicableGas
after all logic, including fee handling. - Adjust Gas Tracking:
uint256 startGas = gasleft(); // ... order execution and fee handling logic ... uint256 totalGasUsed = startGas - gasleft(); _handleKeeperFee(..., totalGasUsed, ...);
- Note: This requires restructuring to ensure
_handleKeeperFee
is included in gas measurement.