hats-finance / Fenix--0x9d7765a7ebd5b6322a30797a44a5428531970d3d

0 stars 1 forks source link

Inconsistent Checkpoint Updates in `VirtualRewarderCheckpoints.writeCheckpoint()` #56

Open hats-bug-reporter[bot] opened 1 month ago

hats-bug-reporter[bot] commented 1 month ago

Github username: -- Twitter username: -- Submission hash (on-chain): 0x414a5ff840357199b971057ea08e9ec4b2a8a0de477fbc8fb7d9d67cf3d8625e Severity: medium

Description: Description\ The VirtualRewarderCheckpoints.writeCheckpoint() function in the SingelTokenVirtualRewarderUpgradeable contract may not correctly handle multiple updates within the same block. This can lead to inconsistencies in the recorded checkpoints, potentially causing incorrect state representation for token balances and total supply. The function uses an in-memory read of the last checkpoint and updates it if the timestamp matches the current block's timestamp. This approach can lead to issues when multiple updates occur within the same block, as only the last update will be recorded, potentially overwriting previous updates within the same block.

Attack Scenario\

Initial State:

User A has a balance of 100 tokens. The total supply is 1000 tokens.

Multiple Updates in the Same Block:

User A deposits 50 tokens(using deposit function). User A withdraws 30 tokens(using withdraw function).

Expected Behavior:

Two separate checkpoints should be recorded, one for the deposit and one for the withdrawal.

Actual Behavior:

Only one checkpoint is recorded, reflecting the final state after both operations, potentially missing intermediate state changes.

Attachments

  1. Proof of Concept (PoC) File
    • writeCheckpoint Function:
function writeCheckpoint(
    mapping(uint256 index => Checkpoint checkpoint) storage self_,
    uint256 lastIndex_,
    uint256 timestamp_,
    uint256 amount_
) internal returns (uint256 newIndex) {
    Checkpoint memory last = self_[lastIndex_];//@audit-using memory

    newIndex = last.timestamp == timestamp_ ? lastIndex_ : lastIndex_ + 1;

    self_[newIndex] = Checkpoint({timestamp: timestamp_, amount: amount_});
}
  1. Revised Code File (Optional)
0xmahdirostami commented 1 month ago

I think this issue is similar to #43 as it explains the same consequences of writing checkpoint multiple times inside a block / Lack of POC + further explanations