Skip to content

Latest commit

 

History

History
47 lines (32 loc) · 2 KB

055.md

File metadata and controls

47 lines (32 loc) · 2 KB

Obedient Lava Monkey

Medium

Incorrect handling of lastUpdateTimestamp can lead to skipped state updates.

Summary:

If reserve.lastUpdateTimestamp matches block.timestamp, state updates are skipped for reserve data, as the system assumes no meaningful time has elapsed, causing loss of accrued interest or inconsistent reserve state.


Root Cause:

The check if (reserveCache.reserveLastUpdateTimestamp == uint40(block.timestamp)) { return; } prevents updates to indexes and treasury accruals when the timestamp matches, even when meaningful actions (e.g., liquidity changes) occur in the same block.


Internal Pre-conditions:

  1. reserve.lastUpdateTimestamp is set to the current block's timestamp.
  2. A function triggering updateState is called again within the same block (e.g., consecutive liquidity updates or flash loan repayments).

External Pre-conditions:

  1. A user or contract interaction (e.g., deposit, borrow, or repay) triggers reserve updates multiple times within a single block.

Attack Path:

  1. A user calls a function that triggers updateState, setting lastUpdateTimestamp to block.timestamp.
  2. Another function (e.g., a repay or flash loan) is called within the same block.
  3. The state update logic is skipped due to the timestamp match, resulting in missed updates to indexes and treasury accruals.

Impact:

  • The protocol treasury loses accrued fees or interest for actions performed in the same block.
  • Users and the protocol face inconsistent reserve states, as changes are not reflected correctly.

Mitigation:

Replace the strict timestamp equality check with a condition that allows updates for meaningful reserve changes:

if (reserveCache.reserveLastUpdateTimestamp == uint40(block.timestamp) && liquidityAdded == 0 && liquidityTaken == 0) {
    return;
}