hats-finance / Paladin-0x1610bfde27e57b068af7f38aec3d2a7b1d146989

Smart contract for the Vote-Flywheel part of Paladin Tokenomics
Other
0 stars 1 forks source link

There's no guarantee that the period updates continuously in LootCreator #51

Open hats-bug-reporter[bot] opened 7 months ago

hats-bug-reporter[bot] commented 7 months ago

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

Description: Description\ We have an important function called _updatePeriod in LootCreator. Within this function, we update the current period budget, handle pending budgets, and update some critical variables. It's essential to execute these updates correctly to ensure receiving PAL and extra token rewards.

Attack Scenario\

This can lead to several vulnerabilities.

Of course, there is an external function called updatePeriod, and if we trust that a trusted entity always ensures the proper update, there is no need to call this function when the distributor notifies the LootCreator. Attachments

  1. Proof of Concept (PoC) File

  2. Revised Code File (Optional)

    Modify _updatePeriod function.

    
    function _updatePeriod() internal {
    -     if(block.timestamp < nextBudgetUpdatePeriod) return;
Kogaroshi commented 7 months ago

My issue with the proposed fix is that the mapping periodBlockCheckpoint will be filled with incorrect block.number to fetch data in the case of allocations.

GTH1235 commented 7 months ago

Make _findBlockNumberForTimestamp function in HolyPalPower as public and use it.

function _findBlockNumberForTimestamp(uint256 timestamp) internal view returns(uint256) {
      uint256 deltaBlocks = block.number - ANCHOR_BLOCK;
      uint256 deltaTs = block.timestamp - ANCHOR_TIMESTAMP;

      uint256 secPerBlock = (deltaTs * SCALE_UNIT) / deltaBlocks;

      return block.number - (((block.timestamp - timestamp) * SCALE_UNIT) / secPerBlock);
  }

Or make the same function in LootCreator.

function _updatePeriod() internal {
    while (nextBudgetUpdatePeriod <= block.timestamp) {
-         periodBlockCheckpoint[nextBudgetUpdatePeriod] = block.number;
+         periodBlockCheckpoint[nextBudgetUpdatePeriod] = _findBlockNumberForTimestamp(nextBudgetUpdatePeriod);
    }
}

@Kogaroshi , what do you think?

Kogaroshi commented 7 months ago

Since we also use _findBlockNumberForTimestamp to find the user lock for a given timestamp, we can use the same logic to find the block.number at which we want to get the totalLocked, since in both case we'd have the same block.number so a better consistency. I'll work on a fix with those changes.

Kogaroshi commented 7 months ago

Changes made in https://github.com/PaladinFinance/Vote-Flywheel/pull/2/commits/3b0fe63eeb38718fb96d06329012cde349de8c38 All methods are not fully tested now, will add new tests later on.