Skip to content

Latest commit

 

History

History
78 lines (54 loc) · 3.59 KB

File metadata and controls

78 lines (54 loc) · 3.59 KB

Clean Hemp Barracuda

Medium

Incomplete Gas Tracking in Order Execution

Summary

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

Root Cause

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:

  1. Keeper calls execute Order, gas used for executing the order is 80,000.
  2. Then, applicable Gas is 80,000, fee is calculated based on that.
  3. 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.

Internal Pre-conditions

No response

External Pre-conditions

No response

Attack Path

Scenario:

  1. Keeper Action: Bob executes an order, consuming 80,000 gas for order logic and 20,000 gas for fee handling.
  2. Fee Calculation:
    • applicableGas = 80,000 (order logic only).
    • fee = (80,000 + buffer) * gasPrice.
  3. 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
}

Impact

  • 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.

PoC

No response

Mitigation

  1. Measure Total Gas: Calculate applicableGas after all logic, including fee handling.
  2. Adjust Gas Tracking:
    uint256 startGas = gasleft();
    // ... order execution and fee handling logic ...
    uint256 totalGasUsed = startGas - gasleft();
    _handleKeeperFee(..., totalGasUsed, ...);
  3. Note: This requires restructuring to ensure _handleKeeperFee is included in gas measurement.