TRUST Summit | Nov 3, 2025 | NYCWhere decision-makers define the next chapter of secure blockchain adoption.
Learn more

Audit name:

[SCA] Lumia | Governance | Jan2025

Date:

Feb 4, 2025

Table of Content

Introduction
Audit Summary
System Overview
Potential Risks
Findings
Appendix 1. Definitions
Appendix 2. Scope
Appendix 3. Additional Valuables
Disclaimer

Want a comprehensive audit report like this?

Introduction

We express our gratitude to the Lumia team for the collaborative engagement that enabled the execution of this Smart Contract Security Assessment.

Lumia is a robust liquidity infrastructure protocol interconnecting Layer 1’s and Layer 2’s with liquidity from CEXs and DEXs.

Document

NameSmart Contract Code Review and Security Analysis Report for Lumia
Audited ByViktor Raboshchuk, Viktor Lavrenenko
Approved ByAtaberk Yavuzer
Websitehttps://lumia.org/
Changelog22/01/2025 - Preliminary Report
29/01/2025 - Final Report
PlatformLumia, BSC, Ethereum
LanguageSolidity
TagsStaking; Governance; Migration
Methodologyhttps://hackenio.cc/sc_methodology
  • Document

    Name
    Smart Contract Code Review and Security Analysis Report for Lumia
    Audited By
    Viktor Raboshchuk, Viktor Lavrenenko
    Approved By
    Ataberk Yavuzer
    Changelog
    22/01/2025 - Preliminary Report
    29/01/2025 - Final Report
    Platform
    Lumia, BSC, Ethereum
    Language
    Solidity
    Tags
    Staking; Governance; Migration

Audit Summary

12Total Findings
9Resolved
3Accepted
0Mitigated

The system users should acknowledge all the risks summed up in the risks section of the report

Documentation quality

  • Functional requirements are not complete:

    • Project overview is not detailed.

    • All roles in the system are missing.

    • Use cases are not complete.

    • For each contract all features are not described.

  • Technical description is not complete:

    • Run instructions are provided.

    • Technical specification is partially provided.

    • The NatSpec documentation is partially provided.

Code quality

  • The development environment is configured.

  • Best practices are not followed.

Test coverage

Code coverage of the project is 35.3% (branch coverage).

  • Deployment and basic user interactions are covered with tests.

  • Negative cases coverage is partially provided.

  • Interactions by several users are not tested thoroughly.

System Overview

Lumia  is a governance protocol with staking functionality and migration functionality with the following contracts:

  • orionprotocol___lumia/contracts/legacy/governance/VeORNPausable.sol - (VeOrnPausable contract is a staking contract that allows users to lock their ORN tokens for specified durations to earn both standard and points-based rewards. The latter can be received in the dropLock mode of the contract. Inheriting from TWBalance, veORNStorage, and StakingPoints, it manages user deposits, calculates rewards, and facilitates withdrawals upon lock expiration. Moreover, the contract has a pausing functionality which allows the owner to pause the critical contract's functionality and migrate users' data to the Lumia chain).

  • orionprotocol___lumia/contracts/governance/VeLumia/VeLumiaMigrated.sol - (VeLumiaMigrated contract is a staking contract that allows users to lock their Lumia for specified durations to earn both standard and points-based rewards. It contains additional functionality to allow the contract's admin to migrate the stakes and unclaimed rewards from the VeOrnPausable.sol deployed on Ethereum and BSC.

  • orionprotocol___lumia/contracts/governance/VeLumia/Migrator.sol - (VeOrnMigrator contract is a contract containing the migration functionality needed to migrate the data from the VeORNPausable to VeLumiaMigrated).

  • orionprotocol___lumia/contracts/legacy/governance/veORNStorage.sol - (veORNStorage contract is a storage contract storing the necessary data for the VeORNPausable.sol).

  • orionprotocol___lumia/contracts/legacy/governance/base/Staking.sol - (The Staking contract is an abstract Solidity smart contract enabling users to stake ORN and earn rewards. It tracks each user’s stake, accumulated rewards, and withdrawals. The contract manages a global rewardRate, calculates individual rewards based on stake size and time elapsed, and allows users to claim or unstake their funds).

  • orionprotocol___lumia/contracts/governance/libraries/PausableLib.sol - (The pausing functionality used by VeORNPausable and VeLumiaMigrated contracts).

Privileged roles

  • The owner of the VeOrnPausable contract which is stored by the smartOwner can:

    • pause/unpause the contract.

    • change the address of the smartVote contract via the setSmartVote() function.

    • change the admin of the contract via the setAdmin() function.

    • update the airdrop state via the updateAirdropState() function.

  • The admin of the VeOrnPausable contract can:

    • set rewards and pointRewards via setRewards() and setPointsRewards() functions.

    • call the migration moveORNToVeLumia() function.

  • The owner of the VeLumiaMigrated contract can:

    • change the address of the smartVote contract via the setSmartVote() function.

    • change the admin of the contract via the setAdmin() function.

    • update the airdrop state via the updateAirdropState() function.

    • pause/unpause the contract.

  • The admin of the VeLumiaMigrated contract can:

    • set rewards and pointRewards via setRewards() and setPointsRewards() functions.

    • initiate the migration process via migrateMany() function.

Potential Risks

Relying on off-chain admin calculations: The off-chain migrating user data from VeOrnPausable to VeLumiaMigrated introduces significant risks. Inaccurate or manipulated off-chain data may lead to incorrect user balances, loss of unclaimed rewards, distorted governance power, and potential financial loss for users, undermining trust and raising legal concerns.

Reliance on Governance External Contracts: The functioning of the system significantly relies on the governance of external contracts. Any flaws or vulnerabilities in these contracts adversely affect the audited project, potentially leading to security breaches or loss of funds.

Single Points of Failure and Control: The project is fully or partially centralized, introducing single points of failure and control. This centralization can lead to vulnerabilities in decision-making and operational processes, making the system more susceptible to targeted attacks or manipulation.

Administrative Key Control Risks: The digital contract architecture relies on administrative keys for critical operations. Centralized control over these keys presents a significant security risk, as compromise or misuse can lead to unauthorized actions or loss of funds.

Reward Pool Depletion: If the reward pool balance runs out, users won't be able to withdraw their earned rewards or stakes, as there won't be enough funds to cover the claims. To prevent this, protocol administrators should regularly monitor the reward pool and top it up as needed to ensure it always has enough balance for payouts.

Admin's Unrestricted State Modification: The absence of restrictions on state variable modifications via functions setPointsRewards() and setRewards() by the admin can lead to sudden changes in rewards. This affects contract integrity and user trust, especially during critical operations like reward distribution. Moreover, the incorrect reward value and abnormal duration period for the rewards distribution can potentially result in no rewards being allocated to participants.

Reliance on Owner's Actions: Users who stake their tokens using the dropLock option will encounter withdrawal restrictions and will only be able to retrieve their staked tokens once the isAirdropPassed parameter is activated. Since this activation is performed exclusively by the contract owner through the updateAirdropState() function, it creates a risk of delayed unlocked stakes.

The VeLumiaMigrated::_migrate() function considers the option when the locktime of users' stakes on Ethereum or BSC is different from the same value of users' previous stakes on the Lumia chain resulting in the function choosing the minimum from both values. As a consequence, the user's bigger locktime value can be suddenly changed and replaced with a smaller one after the migration is over.

During the migration process, the ratio between 1 ORN and 1 Lumia token is maintained at 1:1, reflecting the rebranding of ORN to Lumia. While this ensures consistency in the migration, it's important to assess the rebranding process thoroughly to identify and address any potential issues that may have arisen.

This audit report focuses exclusively on the security assessment of the contracts within the specified review scope. Interactions with out-of-scope contracts are presumed to be correct and are not examined in this audit. We want to highlight that Interactions with contracts outside the specified scope, such as the implementation of the IOrionVoting interface, legacy/governance/base/StakingPoints.sol, and other out-of-scope contracts have not been verified or assessed as part of this report. While we have diligently identified and mitigated potential security risks within the defined scope, it is important to note that our assessment is confined to the isolated contracts within this scope. The overall security of the entire system, including external contracts and integrations beyond our audit scope, cannot be guaranteed. Users and stakeholders are urged to exercise caution when assessing the security of the broader ecosystem and interactions with external contracts. For a comprehensive evaluation of the entire system, additional audits and assessments outside the scope of this report are necessary. This report serves as a snapshot of the security status of the audited contracts within the specified scope at the time of the audit. We strongly recommend ongoing security evaluations and continuous monitoring to maintain and enhance the overall system's security.

The previously deployed versions of VeORN and VeLumiaMigrated lack storage gaps in their parent contracts, including StakingPoints, TWBalance, Staking, Pausable and VeOrnMigrator. This omission introduces a significant risk of storage collisions if these parent contracts are modified in the future. Specifically, updates to the storage layouts—such as adding new state variables or restructuring existing ones—could overwrite or corrupt critical data in the child contracts, potentially leading to unpredictable behavior, security vulnerabilities, or complete contract failure.

Front-running During The Initialization Of The Implementation Contract: If the deployment and the initialization of the implementation contract, which is VeLumiaMigrated, will not be handled within one transaction, it can cause the front-running of the VeLumiaMigrated::initialize() function by the attacker which will lead to unexpected system behavior. In addition to that, the VeORNPausable contract does not adhere to the best practices and does not implement the Initialization pattern, which creates a risk of the improper usage of the system.

Findings

Code
Title
Status
Severity
F-2025-8366Improper DropLock State Management Leads to Incorrect Reward Calculations and Usability Issues
fixed

Medium
F-2025-8365Unpaused claimReward Allows Reward Duplication During Migration Process
fixed

Medium
F-2025-8359Unclaimed Rewards Not Properly Decremented After claimReward() Execution
fixed

Medium
F-2025-8358Mismatch Between Documentation and Contract Logic
fixed

Medium
F-2025-8356Version Incompatibility in Solidity Compilation
fixed

Low
F-2025-8354Incorrect Handling of Future Pause Timestamp Can Cause Unintended Pausing
fixed

Low
F-2025-8426CEI Pattern Violation in VeOrnPausable and VeLumiaMigrated Contracts
fixed

Observation
F-2025-8376Redundant Modifiers in pause() and unpause() Functions Decrease Code Quality
fixed

Observation
F-2025-8374Duplicated Token Name and Symbol Can Lead to Confusion
accepted

Observation
F-2025-8361Absence of Custom Errors Leading to Increased Gas Costs
fixed

Observation
1-10 of 12 findings

Identify vulnerabilities in your smart contracts.

Appendix 1. Definitions

Severities

When auditing smart contracts, Hacken is using a risk-based approach that considers Likelihood, Impact, Exploitability and Complexity metrics to evaluate findings and score severities.

Reference on how risk scoring is done is available through the repository in our Github organization:

Severity

Description

Critical
Critical vulnerabilities are usually straightforward to exploit and can lead to the loss of user funds or contract state manipulation.

High
High vulnerabilities are usually harder to exploit, requiring specific conditions, or have a more limited scope, but can still lead to the loss of user funds or contract state manipulation.

Medium
Medium vulnerabilities are usually limited to state manipulations and, in most cases, cannot lead to asset loss. Contradictions and requirements violations. Major deviations from best practices are also in this category.

Low
Major deviations from best practices or major Gas inefficiency. These issues will not have a significant impact on code execution.
  • Severity

    Critical

    Description

    Critical vulnerabilities are usually straightforward to exploit and can lead to the loss of user funds or contract state manipulation.

    Severity

    High

    Description

    High vulnerabilities are usually harder to exploit, requiring specific conditions, or have a more limited scope, but can still lead to the loss of user funds or contract state manipulation.

    Severity

    Medium

    Description

    Medium vulnerabilities are usually limited to state manipulations and, in most cases, cannot lead to asset loss. Contradictions and requirements violations. Major deviations from best practices are also in this category.

    Severity

    Low

    Description

    Major deviations from best practices or major Gas inefficiency. These issues will not have a significant impact on code execution.

Potential Risks

The "Potential Risks" section identifies issues that are not direct security vulnerabilities but could still affect the project’s performance, reliability, or user trust. These risks arise from design choices, architectural decisions, or operational practices that, while not immediately exploitable, may lead to problems under certain conditions. Additionally, potential risks can impact the quality of the audit itself, as they may involve external factors or components beyond the scope of the audit, leading to incomplete assessments or oversight of key areas. This section aims to provide a broader perspective on factors that could affect the project's long-term security, functionality, and the comprehensiveness of the audit findings.

Appendix 2. Scope

The scope of the project includes the following smart contracts from the provided repository:

Scope Details

Repositoryhttps://github.com/orionprotocol/lumia/tree/audit/veOrn-veLumia-migration
Commitc8129b00df29916efe2a8a4606acbe7d84603d2d
WhitepaperN/A
RequirementsRequirements
Technical RequirementsRequirements

Assets in Scope

orionprotocol___lumia
contracts
governance
libraries
PausableLib.sol - orionprotocol___lumia › contracts › governance › libraries › PausableLib.sol
VeLumia
Migrator.sol - orionprotocol___lumia › contracts › governance › VeLumia › Migrator.sol
VeLumiaMigrated.sol - orionprotocol___lumia › contracts › governance › VeLumia › VeLumiaMigrated.sol
legacy
governance
base
Staking.sol - orionprotocol___lumia › contracts › legacy › governance › base › Staking.sol
StakingPoints.sol - orionprotocol___lumia › contracts › legacy › governance › base › StakingPoints.sol
VeORNPausable.sol - orionprotocol___lumia › contracts › legacy › governance › VeORNPausable.sol
veORNStorage.sol - orionprotocol___lumia › contracts › legacy › governance › veORNStorage.sol

Appendix 3. Additional Valuables

Verification of System Invariants

During the audit of Lumia, Hacken followed its methodology by performing fuzz-testing on the project's main functions. Due to the complex and dynamic interactions within the protocol, unexpected edge cases might arise. Therefore, it was important to use fuzz-testing to ensure that several system invariants hold true in all situations.

Fuzz-testing allows the input of many random data points into the system, helping to identify issues that regular testing might miss. A specific Echidna fuzzing suite was prepared for this task, and throughout the assessment, 25 invariants were tested over 20000 runs. This thorough testing ensured that the system works correctly even with unexpected or unusual inputs.

Invariant

Test Result

Run Count

testFuzzCreateLock:: Ensures that users can create locks with varying amounts and durations. Validates that the locked amount and lock expiration time are accurately recorded in the contract's state. Confirms that the total stake within the contract correctly reflects the user's lock after advancing time by the lock duration.Passed20K+
testFuzzIncreaseLock: Verifies that users can incrementally increase their existing lock amounts and extend durations . Checks that the total locked amount updates appropriately and that the lock's expiration time remains consistent post-increase. Ensures the contract's total stake accurately represents the user's enhanced stake after time progression.Passed20K+
testFuzzWithdraw:: Tests the withdrawal mechanism by allowing users to withdraw their locked funds after the lock duration has fully elapsed. Confirms that upon withdrawal, the user's balance increases by the locked amount, and the contract's total stake decreases accordingly. Additionally, it verifies that users can successfully claim their accrued rewards before withdrawing, ensuring the integrity of the withdrawal process.Passed20K+
testFuzzRewardsFlow:: Evaluates the entire rewards lifecycle by setting variable rewards and durations, creating locks, and advancing time to accrue rewards. Checks that users receive partial rewards proportional to their lock amounts and durations after half the reward period. Ensures that after the full reward duration, all rewards are claimable and that no residual rewards remain, maintaining accurate reward distribution.Passed20K+
testFuzzTimeWeightedAverage:: Assesses the calculation of the time-weighted average of the total supply within the contract. Users create locks, and after a portion of the lock duration, some locks are increased. The test advances time and verifies that the TWA accurately reflects the changes in total supply over time, ensuring precise tracking of staking contributions relative to their durations.Passed20K+
testFuzzTopUpInfluence:: Investigates how additional top-ups by the admin influence reward distribution. After initial top-ups and user lock creations, the admin performs further top-ups. The test advances time to accrue rewards and verifies that the reward ratios between users remain consistent despite the increased contract balance, ensuring that top-ups do not skew proportional reward allocations.Passed20K+
testFuzzParallelLocks:: Ensures that multiple users can concurrently create locks with different amounts and durations. After advancing time, the test verifies that each user accrues rewards proportional to their respective locks. It also checks that all users can successfully claim their rewards independently, maintaining correct reward calculations and preventing cross-user interference.Passed20K+
testFuzzTopUpThenFailWithdraw:: Validates that users without an active lock cannot withdraw funds. After the admin performs a top-up, an arbitrary user (excluded from known roles) attempts to withdraw without establishing a lock. The test expects the withdrawal to revert with a specific error (InvalidOperandOOG), ensuring that the contract correctly enforces lock prerequisites for withdrawals and prevents unauthorized fund retrievals.Passed20K+
testFuzz_balanceOfT:: Ensures that after user creates a lock with a specified balance0 the amountTW  recorded in balanceOfTW for the user is at least equal to balance0 multiplied by the lock duration. This guarantees accurate tracking of time-weighted balances based on lock amounts and durations.Passed20K+
testFuzz_balanceOfAv:: Validates that after user creates a lock and subsequently increases it by an additional amount, the average balance calculated by balanceOfAvg reflects the increased lock correctly. It ensures that the average considers both the initial and additional lock amounts over the specified time deltas, maintaining consistency in average calculations.Passed20K+
testFuzz_toUint128:: This test verifies the toUint128 function's ability to accurately convert a non-negative int128 value to uint128. It ensures that when provided with a valid positive input, the conversion retains the original value without alteration. Additionally, the test confirms that the function correctly reverts when attempting to convert negative int128 values, thereby preventing unintended underflows and maintaining type safety within the contract.Passed20K+
testFuzz_toInt128::This test assesses the toInt128 function's functionality by converting a uint128 value to an int128. It ensures that the conversion succeeds when the input is within the permissible range (≤ MAX_U64x64), accurately reflecting the original uint128 value. The test also verifies that inputs exceeding MAX_U64x64 correctly trigger a revert, safeguarding against overflow and ensuring that only valid conversions are permitted, thus maintaining the integrity of signed integer operations.Passed20K+
testFuzz_from_uint::  evaluates the from_uint method, which scales a uint256 input by shifting it left by 64 bits to achieve fixed-point representation. The test ensures that for inputs within the allowable range (≤ 0x7FFFFFFFFFFFFFFF), the function returns the correctly scaled uint128 value. It also verifies that inputs exceeding this threshold cause the function to revert, thereby preventing overflow and ensuring precise fixed-point calculations essential for accurate mathematical operations within the contract.Passed20K+
testFuzz_div18:: This test scrutinizes the div18 function, which performs division of x by y scaled by 10¹⁸ to maintain fixed-point precision. It ensures that the function returns accurate results when y is non-zero and the operation does not result in an overflow. The test also confirms that attempts to divide by zero or perform operations that exceed the maximum allowed value correctly revert, thereby enforcing safe arithmetic practices and maintaining the reliability of financial computations within the contract.Passed20K+
testFuzz_div256:: The test function examines the div256 method, which divides x shifted left by 64 bits by y to achieve fixed-point division. The test ensures that when y is non-zero and the division does not lead to an overflow, the function returns the correct uint128 result. It also verifies that dividing by zero or causing an overflow appropriately triggers a revert, thereby safeguarding against invalid operations and ensuring that only mathematically sound divisions are executed within the contract.Passed20K+
testFuzz_mul256:: This test evaluates the mul256 function, responsible for multiplying x by y and shifting the result right by 64 bits to maintain fixed-point precision. It ensures that for valid inputs where the product does not exceed uint64x64 limits, the function returns the accurate uint128 result. The test also checks that scenarios leading to overflow correctly cause the function to revert, thus preventing erroneous calculations and ensuring the integrity of multiplication operations within the contract's mathematical framework.Passed20K+
testFuzz_div:: function tests the div method, which divides x shifted left by 64 bits by y to perform fixed-point division. The test verifies that the function returns precise results when y is non-zero and the division remains within uint64x64 bounds. It also ensures that dividing by zero or operations resulting in an overflow appropriately revert, thereby enforcing safe and accurate division practices essential for the contract's reliable mathematical computations.Passed20K+
testFuzz_mul:: This test assesses the mul function, which multiplies x by y and shifts the product right by 64 bits to maintain fixed-point precision. It ensures that for inputs where the multiplication does not exceed uint64x64 limits, the function returns the correct uint128 result. Additionally, the test verifies that multiplying by zero yields zero and that any multiplication leading to an overflow correctly reverts, thereby maintaining the accuracy and safety of multiplication operations within the contract.Passed20K+
testFuzz_exp_2:: function evaluates the exp_2 method, which calculates 2 raised to the power of x. The test ensures that for inputs below 0x400000000000000000, the function returns accurate exponential values without causing an overflow. It also verifies that inputs exceeding this threshold correctly trigger a revert, thereby maintaining the mathematical correctness and preventing the computation of excessively large values that could compromise the contract's stability.Passed20K+
testFuzz_sqrt:: This test examines the sqrt function, which computes the floor of the square root for a given uint128 input. It ensures that for non-zero inputs, the square of the result is less than or equal to x shifted left by 64 bits and that incrementing the result by one causes the square to exceed x shifted left by 64 bits. Additionally, the test confirms that the square root of zero correctly returns zero, thereby ensuring accurate and reliable square root calculations essential for precise mathematical operations within the contract.Passed20K+
testFuzz_sqrt0:: function tests the sqrt0 method, which calculates the square root for non-negative int128 inputs. The test ensures that negative inputs correctly trigger a revert, preventing invalid operations. For non-zero inputs, it verifies that the square of the result does not exceed x shifted left by 64 bits and that incrementing the result by one causes the square to surpass this threshold. The test also confirms that the square root of zero returns zero, thereby maintaining mathematical accuracy and type safety in square root computations.Passed20K+
testFuzz_createLock:: After creating a lock with valid fuzzed amounts and durations, the contract's total supply increases appropriately, the user's lock information (amount and expiration) is accurately recorded, and invalid inputs causing out-of-bound lock times correctly trigger reverts.Passed20K+
testFuzz_getReward:: Following a lock creation and time warp, the accrued reward reported by getReward() aligns with the expected accumulation, and upon claiming, the user's balance increases by approximately the pending reward while preserving reward calculation accuracy.Passed20K+
testFuzz_pauseAndUnpauseTimestamp:: Using a future timestamp to pause and then unpausing the contract ensures that the pause state activates only after the specified time, and subsequent unpausing correctly resets the pause state, with the contract's paused status reflecting these transitions accurately.Failed20K+
testFuzz_ClaimRewardAfterTime:: After warping time and topping up funds to cover rewards, claiming rewards results in the user's balance increasing by an amount closely matching the pending reward, preserving correct reward distribution and ensuring no discrepancies occur during the claim process.Passed20K+
testFuzz_WithdrawLock:: When attempting to withdraw funds, if the lock period has not expired, the transaction reverts as expected with the appropriate error message, and once the lock expires, withdrawal succeeds, resetting the user's token balance to zero and reducing the total supply accordingly.Passed20K+
  • Invariant

    testFuzzCreateLock:: Ensures that users can create locks with varying amounts and durations. Validates that the locked amount and lock expiration time are accurately recorded in the contract's state. Confirms that the total stake within the contract correctly reflects the user's lock after advancing time by the lock duration.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzzIncreaseLock: Verifies that users can incrementally increase their existing lock amounts and extend durations . Checks that the total locked amount updates appropriately and that the lock's expiration time remains consistent post-increase. Ensures the contract's total stake accurately represents the user's enhanced stake after time progression.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzzWithdraw:: Tests the withdrawal mechanism by allowing users to withdraw their locked funds after the lock duration has fully elapsed. Confirms that upon withdrawal, the user's balance increases by the locked amount, and the contract's total stake decreases accordingly. Additionally, it verifies that users can successfully claim their accrued rewards before withdrawing, ensuring the integrity of the withdrawal process.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzzRewardsFlow:: Evaluates the entire rewards lifecycle by setting variable rewards and durations, creating locks, and advancing time to accrue rewards. Checks that users receive partial rewards proportional to their lock amounts and durations after half the reward period. Ensures that after the full reward duration, all rewards are claimable and that no residual rewards remain, maintaining accurate reward distribution.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzzTimeWeightedAverage:: Assesses the calculation of the time-weighted average of the total supply within the contract. Users create locks, and after a portion of the lock duration, some locks are increased. The test advances time and verifies that the TWA accurately reflects the changes in total supply over time, ensuring precise tracking of staking contributions relative to their durations.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzzTopUpInfluence:: Investigates how additional top-ups by the admin influence reward distribution. After initial top-ups and user lock creations, the admin performs further top-ups. The test advances time to accrue rewards and verifies that the reward ratios between users remain consistent despite the increased contract balance, ensuring that top-ups do not skew proportional reward allocations.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzzParallelLocks:: Ensures that multiple users can concurrently create locks with different amounts and durations. After advancing time, the test verifies that each user accrues rewards proportional to their respective locks. It also checks that all users can successfully claim their rewards independently, maintaining correct reward calculations and preventing cross-user interference.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzzTopUpThenFailWithdraw:: Validates that users without an active lock cannot withdraw funds. After the admin performs a top-up, an arbitrary user (excluded from known roles) attempts to withdraw without establishing a lock. The test expects the withdrawal to revert with a specific error (InvalidOperandOOG), ensuring that the contract correctly enforces lock prerequisites for withdrawals and prevents unauthorized fund retrievals.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_balanceOfT:: Ensures that after user creates a lock with a specified balance0 the amountTW  recorded in balanceOfTW for the user is at least equal to balance0 multiplied by the lock duration. This guarantees accurate tracking of time-weighted balances based on lock amounts and durations.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_balanceOfAv:: Validates that after user creates a lock and subsequently increases it by an additional amount, the average balance calculated by balanceOfAvg reflects the increased lock correctly. It ensures that the average considers both the initial and additional lock amounts over the specified time deltas, maintaining consistency in average calculations.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_toUint128:: This test verifies the toUint128 function's ability to accurately convert a non-negative int128 value to uint128. It ensures that when provided with a valid positive input, the conversion retains the original value without alteration. Additionally, the test confirms that the function correctly reverts when attempting to convert negative int128 values, thereby preventing unintended underflows and maintaining type safety within the contract.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_toInt128::This test assesses the toInt128 function's functionality by converting a uint128 value to an int128. It ensures that the conversion succeeds when the input is within the permissible range (≤ MAX_U64x64), accurately reflecting the original uint128 value. The test also verifies that inputs exceeding MAX_U64x64 correctly trigger a revert, safeguarding against overflow and ensuring that only valid conversions are permitted, thus maintaining the integrity of signed integer operations.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_from_uint::  evaluates the from_uint method, which scales a uint256 input by shifting it left by 64 bits to achieve fixed-point representation. The test ensures that for inputs within the allowable range (≤ 0x7FFFFFFFFFFFFFFF), the function returns the correctly scaled uint128 value. It also verifies that inputs exceeding this threshold cause the function to revert, thereby preventing overflow and ensuring precise fixed-point calculations essential for accurate mathematical operations within the contract.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_div18:: This test scrutinizes the div18 function, which performs division of x by y scaled by 10¹⁸ to maintain fixed-point precision. It ensures that the function returns accurate results when y is non-zero and the operation does not result in an overflow. The test also confirms that attempts to divide by zero or perform operations that exceed the maximum allowed value correctly revert, thereby enforcing safe arithmetic practices and maintaining the reliability of financial computations within the contract.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_div256:: The test function examines the div256 method, which divides x shifted left by 64 bits by y to achieve fixed-point division. The test ensures that when y is non-zero and the division does not lead to an overflow, the function returns the correct uint128 result. It also verifies that dividing by zero or causing an overflow appropriately triggers a revert, thereby safeguarding against invalid operations and ensuring that only mathematically sound divisions are executed within the contract.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_mul256:: This test evaluates the mul256 function, responsible for multiplying x by y and shifting the result right by 64 bits to maintain fixed-point precision. It ensures that for valid inputs where the product does not exceed uint64x64 limits, the function returns the accurate uint128 result. The test also checks that scenarios leading to overflow correctly cause the function to revert, thus preventing erroneous calculations and ensuring the integrity of multiplication operations within the contract's mathematical framework.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_div:: function tests the div method, which divides x shifted left by 64 bits by y to perform fixed-point division. The test verifies that the function returns precise results when y is non-zero and the division remains within uint64x64 bounds. It also ensures that dividing by zero or operations resulting in an overflow appropriately revert, thereby enforcing safe and accurate division practices essential for the contract's reliable mathematical computations.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_mul:: This test assesses the mul function, which multiplies x by y and shifts the product right by 64 bits to maintain fixed-point precision. It ensures that for inputs where the multiplication does not exceed uint64x64 limits, the function returns the correct uint128 result. Additionally, the test verifies that multiplying by zero yields zero and that any multiplication leading to an overflow correctly reverts, thereby maintaining the accuracy and safety of multiplication operations within the contract.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_exp_2:: function evaluates the exp_2 method, which calculates 2 raised to the power of x. The test ensures that for inputs below 0x400000000000000000, the function returns accurate exponential values without causing an overflow. It also verifies that inputs exceeding this threshold correctly trigger a revert, thereby maintaining the mathematical correctness and preventing the computation of excessively large values that could compromise the contract's stability.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_sqrt:: This test examines the sqrt function, which computes the floor of the square root for a given uint128 input. It ensures that for non-zero inputs, the square of the result is less than or equal to x shifted left by 64 bits and that incrementing the result by one causes the square to exceed x shifted left by 64 bits. Additionally, the test confirms that the square root of zero correctly returns zero, thereby ensuring accurate and reliable square root calculations essential for precise mathematical operations within the contract.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_sqrt0:: function tests the sqrt0 method, which calculates the square root for non-negative int128 inputs. The test ensures that negative inputs correctly trigger a revert, preventing invalid operations. For non-zero inputs, it verifies that the square of the result does not exceed x shifted left by 64 bits and that incrementing the result by one causes the square to surpass this threshold. The test also confirms that the square root of zero returns zero, thereby maintaining mathematical accuracy and type safety in square root computations.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_createLock:: After creating a lock with valid fuzzed amounts and durations, the contract's total supply increases appropriately, the user's lock information (amount and expiration) is accurately recorded, and invalid inputs causing out-of-bound lock times correctly trigger reverts.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_getReward:: Following a lock creation and time warp, the accrued reward reported by getReward() aligns with the expected accumulation, and upon claiming, the user's balance increases by approximately the pending reward while preserving reward calculation accuracy.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_pauseAndUnpauseTimestamp:: Using a future timestamp to pause and then unpausing the contract ensures that the pause state activates only after the specified time, and subsequent unpausing correctly resets the pause state, with the contract's paused status reflecting these transitions accurately.

    Test Result

    Failed

    Run Count

    20K+

    Invariant

    testFuzz_ClaimRewardAfterTime:: After warping time and topping up funds to cover rewards, claiming rewards results in the user's balance increasing by an amount closely matching the pending reward, preserving correct reward distribution and ensuring no discrepancies occur during the claim process.

    Test Result

    Passed

    Run Count

    20K+

    Invariant

    testFuzz_WithdrawLock:: When attempting to withdraw funds, if the lock period has not expired, the transaction reverts as expected with the appropriate error message, and once the lock expires, withdrawal succeeds, resetting the user's token balance to zero and reducing the total supply accordingly.

    Test Result

    Passed

    Run Count

    20K+

Additional Recommendations

The smart contracts in the scope of this audit could benefit from the introduction of automatic emergency actions for critical activities, such as unauthorized operations like ownership changes or proxy upgrades, as well as unexpected fund manipulations, including large withdrawals or minting events. Adding such mechanisms would enable the protocol to react automatically to unusual activity, ensuring that the contract remains secure and functions as intended.

To improve functionality, these emergency actions could be designed to trigger under specific conditions, such as:

  • Detecting changes to ownership or critical permissions.

  • Monitoring large or unexpected transactions and minting events.

  • Pausing operations when irregularities are identified.

These enhancements would provide an added layer of security, making the contract more robust and better equipped to handle unexpected situations while maintaining smooth operations.

Disclaimer