Olas - hash's results

Olas is a unified network for off-chain services like automation, oracles, co-owned AI. It offers a stack for building services and a protocol for incentivizing their creation and their operation in a co-owned and decentralized way.

General Information

Platform: Code4rena

Start Date: 21/12/2023

Pot Size: $90,500 USDC

Total HM: 10

Participants: 39

Period: 18 days

Judge: LSDan

Total Solo HM: 5

Id: 315

League: ETH

Olas

Findings Distribution

Researcher Performance

Rank: 2/39

Findings: 6

Award: $20,540.04

QA:
grade-b

🌟 Selected for report: 3

πŸš€ Solo Findings: 2

Findings Information

🌟 Selected for report: hash

Labels

bug
3 (High Risk)
primary issue
selected for report
sponsor disputed
sufficient quality report
H-03

Awards

11846.5006 USDC - $11,846.50

External Links

Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L277-L293

Vulnerability details

Impact

Deposits will be unwithdrawable from the lockbox

Proof of Concept

If the entire liquidity of a position has been removed, the withdraw function calls the updateFeesAndRewards function on the Orca pool before attempting to close the position.

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L277-L293

    function withdraw(uint64 amount) external {
        address positionAddress = positionAccounts[firstAvailablePositionAccountIndex];
      
        ......

        uint64 positionLiquidity = mapPositionAccountLiquidity[positionAddress];
        
        ......

        uint64 remainder = positionLiquidity - amount;

        ......

        if (remainder == 0) {
            // Update fees for the position
            AccountMeta[4] metasUpdateFees = [
                AccountMeta({pubkey: pool, is_writable: true, is_signer: false}),
                AccountMeta({pubkey: positionAddress, is_writable: true, is_signer: false}),
                AccountMeta({pubkey: tx.accounts.tickArrayLower.key, is_writable: false, is_signer: false}),
                AccountMeta({pubkey: tx.accounts.tickArrayUpper.key, is_writable: false, is_signer: false})
            ];
            whirlpool.updateFeesAndRewards{accounts: metasUpdateFees, seeds: [[pdaProgramSeed, pdaBump]]}();

This is faulty as the updateFeesAndRewards function will always revert if the position's liquidity is 0.

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/interfaces/whirlpool.sol#L198

Whirlpool source code:

update_fees_and_rewards -> calculate_fee_and_reward_growths -> _calculate_modify_liquidity

https://github.com/orca-so/whirlpools/blob/3206c9cdfbf27c73c30cbcf5b6df2929cbf87618/programs/whirlpool/src/manager/liquidity_manager.rs#L97-L99

fn _calculate_modify_liquidity(
    whirlpool: &Whirlpool,
    position: &Position,
    tick_lower: &Tick,
    tick_upper: &Tick,
    tick_lower_index: i32,
    tick_upper_index: i32,
    liquidity_delta: i128,
    timestamp: u64,
) -> Result<ModifyLiquidityUpdate> {
    // Disallow only updating position fee and reward growth when position has zero liquidity
    if liquidity_delta == 0 && position.liquidity == 0 {
        return Err(ErrorCode::LiquidityZero.into());
    }

Since the withdrawal positions are chosen sequentially, only a maximum of (first position's liquidity - 1) amount of liquidity can be withdrawn.

POC Test

https://gist.github.com/10xhash/a687ef66de8210444a41360b86ed4bca

Tools Used

Manual review

Avoid the update_fees_and_rewards call completely since fees and rewards would be updated in the decreaseLiquidity call.

Assessed type

call/delegatecall

#0 - c4-pre-sort

2024-01-10T15:38:18Z

alex-ppg marked the issue as sufficient quality report

#1 - c4-sponsor

2024-01-15T17:42:40Z

mariapiamo (sponsor) disputed

#2 - c4-judge

2024-01-20T14:35:44Z

dmvt marked the issue as unsatisfactory: Invalid

#3 - 10xhash

2024-01-23T07:19:26Z

Why is this issue not valid?

The call to updateFeesAndRewards of whirlpool will revert when the liquidity of that position is 0. This implementation calls updateFeesAndRewards after withdrawing (ie. calling decreaseLiquidity) on whirlpool and hence will revert. In the newly released version of lockbox written in Rust, they have updated the call order to only call decreaseLiquidity after the call to updateFeesAndRewards. If it helps to view the issue's validity on the newer codebase, please apply the following diff and run the tests. In the test, the second liquidity withdrawal will fail.

diff --git a/lockbox2/programs/liquidity_lockbox/src/lib.rs b/lockbox2/programs/liquidity_lockbox/src/lib.rs
index c94a678..13c86a4 100644
--- a/lockbox2/programs/liquidity_lockbox/src/lib.rs
+++ b/lockbox2/programs/liquidity_lockbox/src/lib.rs
@@ -376,6 +376,29 @@ pub mod liquidity_lockbox {
     // Get program signer seeds
     let signer_seeds = &[&ctx.accounts.lockbox.seeds()[..]];
 
+        // CPI to decrease liquidity
+        let cpi_program_modify_liquidity = ctx.accounts.whirlpool_program.to_account_info();
+        let cpi_accounts_modify_liquidity = ModifyLiquidity {
+          whirlpool: ctx.accounts.whirlpool.to_account_info(),
+          position: ctx.accounts.position.to_account_info(),
+          position_authority: ctx.accounts.lockbox.to_account_info(),
+          position_token_account: ctx.accounts.pda_position_account.to_account_info(),
+          tick_array_lower: ctx.accounts.tick_array_lower.to_account_info(),
+          tick_array_upper: ctx.accounts.tick_array_upper.to_account_info(),
+          token_owner_account_a: ctx.accounts.token_owner_account_a.to_account_info(),
+          token_owner_account_b: ctx.accounts.token_owner_account_b.to_account_info(),
+          token_vault_a: ctx.accounts.token_vault_a.to_account_info(),
+          token_vault_b: ctx.accounts.token_vault_b.to_account_info(),
+          token_program: ctx.accounts.token_program.to_account_info()
+        };
+    
+        let cpi_ctx_modify_liquidity = CpiContext::new_with_signer(
+          cpi_program_modify_liquidity,
+          cpi_accounts_modify_liquidity,
+          signer_seeds
+        );
+        whirlpool::cpi::decrease_liquidity(cpi_ctx_modify_liquidity, amount as u128, token_min_a, token_min_b)?;
+
     // Update fees for the position
     let cpi_program_update_fees = ctx.accounts.whirlpool_program.to_account_info();
     let cpi_accounts_update_fees = UpdateFeesAndRewards {
@@ -413,29 +436,6 @@ pub mod liquidity_lockbox {
     );
     whirlpool::cpi::collect_fees(cpi_ctx_collect_fees)?;
 
-    // CPI to decrease liquidity
-    let cpi_program_modify_liquidity = ctx.accounts.whirlpool_program.to_account_info();
-    let cpi_accounts_modify_liquidity = ModifyLiquidity {
-      whirlpool: ctx.accounts.whirlpool.to_account_info(),
-      position: ctx.accounts.position.to_account_info(),
-      position_authority: ctx.accounts.lockbox.to_account_info(),
-      position_token_account: ctx.accounts.pda_position_account.to_account_info(),
-      tick_array_lower: ctx.accounts.tick_array_lower.to_account_info(),
-      tick_array_upper: ctx.accounts.tick_array_upper.to_account_info(),
-      token_owner_account_a: ctx.accounts.token_owner_account_a.to_account_info(),
-      token_owner_account_b: ctx.accounts.token_owner_account_b.to_account_info(),
-      token_vault_a: ctx.accounts.token_vault_a.to_account_info(),
-      token_vault_b: ctx.accounts.token_vault_b.to_account_info(),
-      token_program: ctx.accounts.token_program.to_account_info()
-    };
-
-    let cpi_ctx_modify_liquidity = CpiContext::new_with_signer(
-      cpi_program_modify_liquidity,
-      cpi_accounts_modify_liquidity,
-      signer_seeds
-    );
-    whirlpool::cpi::decrease_liquidity(cpi_ctx_modify_liquidity, amount as u128, token_min_a, token_min_b)?;
-
     // Update the position liquidity
     ctx.accounts.lockbox.total_liquidity = ctx.accounts.lockbox
       .total_liquidity

#4 - dmvt

2024-01-23T19:59:21Z

This:

This is faulty as the updateFeesAndRewards function will always revert if the position's liquidity is 0.

is incorrect. liquidity_delta must also be 0.

#5 - 10xhash

2024-01-23T20:30:08Z

But a call to updateFeesAndRewards would be having liquidity_delta 0 since no liquidity is being removed/added

#6 - dmvt

2024-01-23T20:54:45Z

I've ask the sponsor to comment with their reasoning as well, but this issue as reported is insufficient quality for a high risk. The language is incorrect and the impact is not clearly stated.

#7 - kupermind

2024-01-23T21:12:14Z

We have changed the order of operations in our rust program indeed, and it works there. Verified the order of instructions provided here and it fails if the remainder is zero.

#8 - dmvt

2024-01-23T21:16:14Z

Ok. I really hate when this happens, but seems like you have a valid unique high with less than ideal quality. I'm going to reinstate the credit because regardless of quality issues, you've saved the sponsor from a major issue in production. In the future, please spend a bit more time describing your issues and their impact, particularly when high risk. The more detail you can give and the more specific / accurate your statements, the more value you provide.

#9 - c4-judge

2024-01-23T21:16:26Z

dmvt removed the grade

#10 - c4-judge

2024-01-23T21:16:30Z

dmvt marked the issue as selected for report

#11 - c4-judge

2024-01-23T21:16:35Z

dmvt marked the issue as primary issue

Findings Information

🌟 Selected for report: hash

Also found by: 0xTheC0der, HChang26, c0pp3rscr3w3r

Labels

bug
3 (High Risk)
primary issue
selected for report
sponsor confirmed
sufficient quality report
H-04

Awards

2159.0247 USDC - $2,159.02

External Links

Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Tokenomics.sol#L1037-L1038 https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/governance/contracts/OLAS.sol#L75-L84

Vulnerability details

Impact

Bond depositors and agent/component owner's may never receive the payout Olas Incorrect inflation control

Proof of Concept

effectiveBond is used to account how much of Olas is available for bonding. This includes Olas that are to be minted in the current epoch ie. effectiveBond will include the Olas partitioned for bonding in epoch 5 at the beginning of epoch 5 itself. In case of epoch's crossing YEAR intervals, a portion of the Olas would actually only be mintable in the next year due to the yearwise inflation control enforced at the mint (after 9 years due to fixed supply till 10 years). Due to silent reverts, this can lead to lost Olas payouts

The inflation for bonds are accounted using the effectiveBond variable. https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Tokenomics.sol#L609-L617

    function reserveAmountForBondProgram(uint256 amount) external returns (bool success) {
       
       .....

        // Effective bond must be bigger than the requested amount
        uint256 eBond = effectiveBond;
        if (eBond >= amount) {

            eBond -= amount;
            effectiveBond = uint96(eBond);
            success = true;
            emit EffectiveBondUpdated(eBond);
        }
    }

This variable is updated with the estimated bond Olas at the beginning of an epoch itself.

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Tokenomics.sol#L1037-L1038

    function checkpoint() external returns (bool) {
        
        .....

        // Update effectiveBond with the current or updated maxBond value
        curMaxBond += effectiveBond;
        effectiveBond = uint96(curMaxBond);

In case of epochs crossing YEAR intervals after 9 years, the new Olas amount will not be fully mintable in the same year due to the inflation control check enforced in the Olas contract.

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/governance/contracts/OLAS.sol#L75-L84

    function mint(address account, uint256 amount) external {

        ....
        
        // Check the inflation schedule and mint
        if (inflationControl(amount)) {
            _mint(account, amount);
        }

Whenever a deposit is made on a bond, the required Olas is minted by the treasury and transferred to the Depository contract, from where the depositor claims the payout after the vesting time. Olas.sol doesn't revert for inflation check failure but fails silently. This can cause a deposit to succeed but corresponding redeem to fail since payout Olas has not been actually minted. It can also happen that agent/component owner's who have not claimed the topup Olas amount will loose their reward due to silent return when minting their reward.

Example

  • Year 10, 1 month left for Year 11
  • All Olas associated with previous epochs have been minted
  • New epoch of 2 months is started, 1 month in Year 10 and 1 month in Year 11
  • Total Olas for the epoch, t = year 10 1 month inflation + year 11 1 month inflation year 10 1 month inflaiton (y10m1) = (1_000_000_000e18 * 2 / 100 / 12) year 11 1 month inflation (y11m1) = (1_020_000_000e18 * 2 / 100 / 12) t = y10m1 + y11m1
  • Olas bond percentage = 50%
  • Hence effectiveBond = t/2
  • But actual mintable remaining in year 0, m = y10m1 < effectiveBond
  • A bond is created with supply == effectiveBond
  • User's deposit for the entire bond supply but only y10m1 Olas can be minted. Depending on the nature of deposits, the actual amount minted can vary from 0 to y10m1. In case of unminted amounts(as rewards of agent/component owner's etc.) at Year 10, this amount can be minted for bond deposits following which if agent/component owners claim within the year, no Olas will be received by them.
  • Users loose their Olas payout

POC Test

https://gist.github.com/10xhash/2157c1f2cdc9513b3f0a7f359a65015e

Tools Used

Manual review

In case of multi-year epochs, separate bond amounts of next year

Assessed type

Timing

#0 - c4-pre-sort

2024-01-10T15:38:49Z

alex-ppg marked the issue as sufficient quality report

#1 - c4-sponsor

2024-01-16T15:19:16Z

kupermind (sponsor) confirmed

#2 - c4-judge

2024-01-20T14:14:12Z

dmvt marked the issue as selected for report

#3 - c4-judge

2024-01-23T12:43:48Z

dmvt marked the issue as primary issue

#4 - 10xhash

2024-01-24T08:13:12Z

Could you please consider the following points regarding duped #322,#461 and #390

The root cause in this issue is the breaking of protocol's assumption that tokenomics is supposed to enforce year wise inflation. This broken assumption is made highly impactful by the silent revert vulnerability. Issues #322,#461 and #390 do not address/mention this root cause and just highlights the impact part if the assumption is broken.

In this issue, there are two vulnerabilities:

  1. Effective bond amount being updated with next year's inflation in the current year itself ie. amount to be minted in year x is included in year (x-1) itself in effectiveBond. This breaks the assumption that year wise inflation is enforced by tokenomics.
  2. The silent revert in case of inflationControl failure at the time of minting Olas. This makes the broken assumption highly impactful.

Issue 2 in isolation, which is what is highlighted by reports #322,#461 and #390, would not have any impact since the tokenomics is supposed to take care of enforcing inflation control.

Fixing just issue 2, with a faulty tokenomics ie. issue 1 still persisting, would still leave some issues in the protocol:

  1. If year crossing bonds are created, rewards of previous completed epoch might not be claimable by agent/component owner's until the year changes.
  2. Deviation from expected yearwise inflation for years 1-10 since mint contract has a pre minted supply for first 10 years and it wouldn't revert.

Findings Information

🌟 Selected for report: erebus

Also found by: BugzyVonBuggernaut, hash

Labels

bug
3 (High Risk)
satisfactory
sufficient quality report
duplicate-341

Awards

2460.4271 USDC - $2,460.43

External Links

Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L223

Vulnerability details

Impact

An attacker can cause deposits to be locked in the lockbox

Proof of Concept

In withdraw, if the position has 0 liquidity the execution is reverted

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L223

    function withdraw(uint64 amount) external {
        address positionAddress = positionAccounts[firstAvailablePositionAccountIndex];
        
        .....

        uint64 positionLiquidity = mapPositionAccountLiquidity[positionAddress];
        // Check that the token account exists
        if (positionLiquidity == 0) {
            revert("No liquidity on a provided token account");
        }

Since the withdrawal positions are chosen sequentially, a position with liquidity 0 present in the ith index of positionAccounts array, will make all positions from i -> end locked and unwithdrawable.

Due to lack of checks in the deposit function, an attacker can make a depsoit with 0 liquidity resulting in the above scenario. This will lead to all funds associated with further deposits to be locked in the lockbox.

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L84

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L140

POC Test

https://gist.github.com/10xhash/168166ba89447fa6fbc61981866c1b28

Tools Used

Manual review

Require liquidity of depositing positions to be non-zero

Assessed type

Invalid Validation

#0 - c4-pre-sort

2024-01-10T15:32:02Z

alex-ppg marked the issue as duplicate of #341

#1 - c4-pre-sort

2024-01-10T15:32:10Z

alex-ppg marked the issue as sufficient quality report

#2 - c4-judge

2024-01-19T20:04:59Z

dmvt marked the issue as satisfactory

Findings Information

🌟 Selected for report: EV_om

Also found by: erebus, hash, lsaudit

Labels

bug
2 (Med Risk)
satisfactory
sufficient quality report
duplicate-452

Awards

498.2365 USDC - $498.24

External Links

Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L376-L377

Vulnerability details

Impact

User's / protocol unable to withdraw intended amounts from the lockbox

Proof of Concept

When withdrawing it is required to pass all the associated accounts correctly. Hence the getLiquidityAmountsAndPositions function is implemented to obtain the required data for a given withdrawal amount. But the function is wrongly implemented and gives incorrect withdrawal amount for the last position

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L338-L379

    function getLiquidityAmountsAndPositions(uint64 amount)
        external view returns (uint64[] positionAmounts, address[] positionAddresses, address[] positionPdaAtas)
    {
        
        ......

        uint64 liquiditySum = 0;

        for (uint32 i = firstAvailablePositionAccountIndex; i < numPositionAccounts; ++i) {

            .....

            liquiditySum += positionLiquidity;

            .....

            if (liquiditySum >= amount) {
                amountLeft = liquiditySum - amount;
                break;
            }
        }

        for (uint32 i = 0; i < numPositions; ++i) {
            
            ....

            positionAmounts[i] = mapPositionAccountLiquidity[positionAddresses[i]];
            
            ....
        }

        // @audit incorrect
        if (numPositions > 0 && amountLeft > 0) {
            positionAmounts[numPositions - 1] = amountLeft;
        }
    }

Instead of subtracting amountLeft from the final position, the positionAmount is set as amountLeft. This can cause the overall sum to be greater or less than the actual amount

Example

1 Position with liquidity 150 User wants to withdraw 100

Function walkthrough: After first loop block, liquiditySum == 150 hence amountLeft = 50 In the second loop block, positionAmounts[0] would be set to 50 This would make the totalWithdrawal amount to 50 while the actual intended withdrawal was 100

Tools Used

Manual review

Subtract from the final position instead of setting

        if (numPositions > 0 && amountLeft > 0) {
            positionAmounts[numPositions - 1] -= amountLeft;
        }

Assessed type

Math

#0 - c4-pre-sort

2024-01-10T14:54:30Z

alex-ppg marked the issue as duplicate of #452

#1 - c4-pre-sort

2024-01-10T14:54:34Z

alex-ppg marked the issue as sufficient quality report

#2 - c4-judge

2024-01-19T22:03:28Z

dmvt marked the issue as satisfactory

Findings Information

🌟 Selected for report: hash

Labels

bug
2 (Med Risk)
selected for report
sponsor confirmed
sufficient quality report
M-04

Awards

3553.9502 USDC - $3,553.95

External Links

Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L194-L214

Vulnerability details

Impact

Possible DOS when withdrawing liquidity from Lockbox

Proof of Concept

When withdrawing it is required to pass all the associated accounts in the transaction. But among these (position,pdaPositionAccount and positionMint) are dependent on the current modifiable-state of the account ie. if another withdrawal occurs, the required accounts to be passed to the function call might change resulting in a revert.

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L194-L214

    @mutableAccount(pool)
    @account(tokenProgramId)
    @mutableAccount(position)
    @mutableAccount(userBridgedTokenAccount)
    @mutableAccount(pdaBridgedTokenAccount)
    @mutableAccount(userWallet)
    @mutableAccount(bridgedTokenMint)
    @mutableAccount(pdaPositionAccount)
    @mutableAccount(userTokenAccountA)
    @mutableAccount(userTokenAccountB)
    @mutableAccount(tokenVaultA)
    @mutableAccount(tokenVaultB)
    @mutableAccount(tickArrayLower)
    @mutableAccount(tickArrayUpper)
    @mutableAccount(positionMint)
    @signer(sig)
    function withdraw(uint64 amount) external {
        address positionAddress = positionAccounts[firstAvailablePositionAccountIndex];
        if (positionAddress != tx.accounts.position.key) {
            revert("Wrong liquidity token account");
        }

The DOS for a withdrawal can be caused by another user withdrawing before the user's transaction. Due to the possibility to steal fees, attackers would be motivated to frequently call the withdraw method making such a scenario likely.

Tools Used

Manual review

To mitigate this it would require a redesign on how the lockbox accepts liquidity. Instead of adding new positions, the lockbox can keep its liquidity in a single position continuously increasing its liquidity for deposits.

Assessed type

Context

#0 - c4-pre-sort

2024-01-10T15:38:34Z

alex-ppg marked the issue as sufficient quality report

#1 - c4-sponsor

2024-01-15T17:24:36Z

mariapiamo (sponsor) confirmed

#2 - c4-judge

2024-01-20T14:31:07Z

dmvt marked the issue as selected for report

Awards

21.8971 USDC - $21.90

Labels

bug
disagree with severity
downgraded by judge
grade-b
primary issue
QA (Quality Assurance)
satisfactory
sponsor confirmed
sufficient quality report
Q-06

External Links

Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Tokenomics.sol#L902-L904

Vulnerability details

Impact

Epoch cannot be incremented causing partial bricking of protocol. This will cause donations of current epoch to be locked

Proof of Concept

1 year is considered as a valid new epochLen

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Tokenomics.sol#L497-L540

    function changeTokenomicsParameters(
        uint256 _devsPerCapital,
        uint256 _codePerDev,
        uint256 _epsilonRate,
        uint256 _epochLen,
        uint256 _veOLASThreshold
    ) external
    {
        
        ......

        if (uint32(_epochLen) >= MIN_EPOCH_LENGTH && uint32(_epochLen) <= ONE_YEAR) {
            nextEpochLen = uint32(_epochLen);
        } else {
            _epochLen = epochLen;
        }

But the checkpoint function reverts incase the time difference b/w the two epochs is greater than 1 year.

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Tokenomics.sol#L902-L904

    function checkpoint() external returns (bool) {
        
        ......

        uint256 diffNumSeconds = block.timestamp - prevEpochTime;
        uint256 curEpochLen = epochLen;
        
        if (diffNumSeconds < curEpochLen || diffNumSeconds > ONE_YEAR) {
            return false;
        }

Hence in case the epochLen is set close to 1 year, it will likely cause checkpoint() to revert since block timestamp can differ from the narrow possible range.

Tools Used

Manual review

Validate nextEpochLen to be a sizable amount of time lower than 1 year.

Assessed type

Invalid Validation

#0 - c4-pre-sort

2024-01-10T15:09:30Z

alex-ppg marked the issue as primary issue

#1 - c4-pre-sort

2024-01-10T15:09:35Z

alex-ppg marked the issue as sufficient quality report

#2 - c4-sponsor

2024-01-16T15:17:36Z

kupermind marked the issue as disagree with severity

#3 - c4-sponsor

2024-01-16T15:18:23Z

kupermind (sponsor) confirmed

#4 - c4-judge

2024-01-18T19:55:29Z

dmvt marked the issue as unsatisfactory: Out of scope

#5 - c4-judge

2024-01-20T14:57:32Z

dmvt marked the issue as satisfactory

#6 - c4-judge

2024-01-20T14:57:42Z

dmvt changed the severity to QA (Quality Assurance)

#7 - c4-judge

2024-01-20T14:57:46Z

dmvt marked the issue as grade-b

#8 - BenRai1

2024-01-23T05:46:38Z

Hi @dmvt, I was wondering why this issue was downgraded to QA. It shows how it is possible to DOS the whole protocol if the epoch lenght is set to 1 year and therefore, in my opinion should at least be a medium, maybe even a high. Would be great if you could help me understand the reasening behind this.

#9 - dmvt

2024-01-23T19:51:36Z

From the sponsor:

<img width="517" alt="Screenshot 2024-01-23 at 7 50 49β€―PM" src="https://github.com/code-423n4/2023-12-autonolas-findings/assets/1116695/66c4cff5-7375-4b81-af4d-c169649cf222">

I agree with their assessment

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Β© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter