Detectbox Audit Reports
Zenith Security Audit Report
Findings

Findings

Detailed Summary of Findings

Sl. NoNameSeverity
M-OINo Function to toggle the pause and unpauseMedium
L-OIUse 2-step transfer of AdministratorLow
L-02Use the latest version of SmartPyLow
L-03Lack of User's Input validation for direction in increasePosition entry_pointLow
L-04Validity of information retrieved from other contractsLow
1-01Documenting compiler versionInformational
I-02No Unit TestingInformational
1-03Documentation is missing in certain entry_pointsInformational

Pie Chart

Static Analysis

No major issues were found. Some false positive errors were reported by the tool. All the other issues have been categorized above according to their level of severity.

Manual Review

High Severity Issues

No High Severity issues were found.

Medium Severity Issues

M-01. No Function to toggle the pause and unpause

Description:

In the VMM.py contracts init function, the paused variable is initially set to False. However, it is worth noting that there is no explicit function within the contract to set the paused variable to True and pause the contracts functionality. While the contract contains several checks to ensure that the paused variable is not True, it lacks a specific function to toggle the paused state and enforce the pausing of the contract's operations,

Code Snippets:

vmm.py

    class Vmm_Contract (Helpers.Helpers):
        def __init__(self, admin, operators, usd_contract_address, oracle_address):
            self.init(
                administrator=admin,
                operators-operators,
                vmm=sp.record (token_amount=0, usd_amount=0, invariant=0),
                positions=sp.map(
                    tkey=sp.TAddress,
                    tvalue=sp.TRecord (
                        position=sp. TNat,
                        entry_price=sp.TNat,
                        funding_amount=sp.TInt, position_value=sp. TNat,
                        collateral_amount=sp. TNat,
                        usd_amount=sp. TNat,
                    ),
                ), fees_collected
                usd_contract_address=usd_contract_address,
                oracle_address=oracle_address,
                funding_period-sp.nat (3600),
                short_funding_rate=sp.record (value=sp.nat (0), direction="NA"),
                long_funding_rate=sp.record (value=sp.nat (0), direction="NA"),
                total long-sp.nat(0),
                previous_funding_time=sp.now,
                upcoming funding_time=(sp.now).add_seconds (3600),
                total_short-sp.nat(0),
                paused=False, //@audit No entry point to toggle pause.
                fees_collected=sp.nat(0),
                current_index_price=sp.nat(0), current_mark_price=sp.nat (0),
                transaction_fees=sp.nat(2),
                decimal=10**6,
            )
 

helpers.py

    def _notPaused(setf):
        sp. verify (self. data. paused == False, Errors. Paused)

Recommendations :

Add entry_point to toggle pause and unpause,

Low Severity Issues

L-01. use 2-step transfer of Administrator

Description:

The current implementation of the updateAdmin entry-point in the VMM.py contract allows for directly setting a new address tor the administrator role without any additional verification or confirmation steps. This approach poses a potential risk as it allows for the possibility of mistakenly assigning the administrator role to an incorrect or non-functional address. In such cases, there is a risk of losing control over the contract and potentially locking funds Within it.

Code Snippets:

vmm.py: 80-86

    @sp.entry_point
        def updateAdmin (self, admin):
            self._onlyAdmin ()
            self._notPaused() //@audit Use 2-step transfer of ownership.
            sp.set_type(admin, sp. TAddress)
            self.update_index_price()
            self.data.administrator = admin

Recommendations :

To mitigate the potential risks associated With changing critical privileged addresses, it is recommended to implement a two-step procedure. This approach adds an extra layer of security by requiring confirmation from both the current privileged address and the newly proposed address.

Here's a recommended approach:

  • 1• Step 1: Proposal: The current privileged address initiates the process by proposing a new address for the administrator role.
    1. Step 2. Confirmation: The newly proposed address acknowledges and accepts the proposal. This contirmation step can be implemented as a separate entry-point that accepts the proposed address.
    1. Step 3: Update the privileged address: After successful confirmation from the newly proposed address, the contract can update the administrator address with the proposed address. This step should only be executed if both steps 1 and 2 have been successfully completed.

L-02. use the latest version of SmartPy

Description*

The contracts were written using a legacy version of SmartPy. While this version does not receive any new features or updates, it is highly recommended to transition to the latest version of SmartPy. The latest version introduces new features and functionalities that enhance the development experience, including improved DSL syntax, additional libraries, enhanced testing frameworks, and better integration with Tezos-specific functionalities.

Recommendations*

It's recommended to use the latest version of SmartPy instead of relying on legacy versions.

L-03- Lack of User's Input validation for direction in increaseposition entry_point

Description: The increasePosition entry point is responsible for increasing a user's position in the trading platform- It takes a direction parameter, where 1 represents a long position and 2 represents a short position. Currently. the code includes if conditions to Check if the direction is 1 or 2. However, there is no explicit validation to ensure that the direction value is not greater than 2. Although the current implementation has if conditions for checking if the value is 1 or 2, it is considered a best practice to include a verification Step to ensure the value is within the expected range.

Code snippet :

    @sp.entry_point
        def increasePosition(self, direction, usd_amount, leverage_multiple):
            self._notPaused()
            sp.set_type(leverage_multiple, sp.TNat)
            sp.set_type(usd_amount, sp. TNat)
            self.update_index_price()
            sp.verify(usd_amount > 0, message="POSITION CAN'T BE ZERO")
            sp.verify(leverage_multiple > 0, message="LEVERAGE CAN'T BE ZERO")
            sp.verify(direction=<< 2, message="DIRECTION CAN'T BE MORE THAN TWO")
            self.transfer_usd (from_=sp.sender, to_=sp.self_address, amount_=usd_amount)
            usd_amount1 = sp. local(
                "usd_amount1",
                sp.as_nat (usd_amount (usd_amount self.data.transaction_fees) / 100),
            )
            with sp.if (direction == 1):...
                pos_value = sp.local()...
 
            with sp.if (direction == 2):...
                pos_value = sp. local()...
 

Recommendations:

It is advisable to include a verification statement to validate the direction value. This can be achieved by adding a verify statement to Check if the direction value is less than or equal to 2.

    sp.verify(direction <= 2, "DIRECTION CAN'T BE MORE THAN TWO")

L•04. Validity Of information retrieved from other contracts

Description:

The smart contract "Lg.!pgrspy" retrieves price information from the external Oracle but does not check the age of the data. To ensure the validity and reliability of the retrieved data, it iS recommended to check the age of the data and determine its staleness.

Code Snippets:

    def update_index_price(self):
        """
        The function updates the current index price by retrieving data from an
        oracle.
        """
        oracle_data = sp.view(
        "get lastCompletedData",
        sp.address("KT1C1sYNxacr8LPZimA512gAfWajdGah75nq"),
        sp.unit,
        t=sp.TRecord(
            round=sp.TNat,
            epoch=sp.TNat,
            data=sp.TNat,
            percentOracleResponse=sp.TNat,
            decimals=sp.TNat,
            lastUpdatedAt=sp.TTimestamp,
        ).layout(
            (
                "round",
                (
                    "epoch",
                    (
                        "data",
                        ("percentOracleResponse", ("decimals", "lastUpdatedAt")),
                    ),
                ),
            )
        ),
    ).open_some()
    self.data.current_index_price = oracle_data.data

Recommendations:

By implementing these recommendations, the contract will validate the age of the data and ensure that only up- to-date information is used, enhancing the reliability of the contract's functionality. This can be achieved by comparing the last update timestamp Of the oracle data with the current time. Here's a suggested implementation to address this issue:

    current_time = sp.now
        last_updated_time = oracle_data. lastUpdatedAt
        # Calculate the time difference in seconds
        time_difference = current_time last_updated_time
        # Define the staleness threshold (e.g., 5 minutes)
        staleness_threshold = sp.minutes(5)
        # Verify if the data is stale based on the staleness threshold
        sp.verify(
            time_difference <= staleness_threshold,
            message="Oracle data is stale",
        )
        self.data.current_index_price = oracle_data.data

Informational Issues

I-01. Documenting compiler version

Description:

The documentation for the smart contracts lacks information about the specific compiler and its version used during the compilation process. Documentation should list the compiler and its version used. This helps identify and follow compiler issues in the future.

Recommendations:

We recommend adding information about which SmartPy compiler version has been used to compile the code.

I-02. No unit Testing

Description:

The smart contracts lack comprehensive test coverage, as there are no existing test cases to validate their functionality. This poses a riSk as it becomes difficult to ensure the contracts behave as intended and handle various scenarios correctly. Additionally, there are no on-chain test cases available for the contracts in scope. We also noted that for all of the contracts in scope, there are no on-chain test cases available.

Recommendations:

We recommend defining and executing test cases in SmartPy appropriately covering all entry points, In addition to the testing in SmartPy, we also advise defining appropriate on-chain testing.

1-03. Documentation is missing in certain entry_points

Description:

The smart contracts lack proper documentation at certain entry points, specifically in the following functions:

Helpers.py:

  • _ onlyAdmin
  • _notPaused
  • transfer_usd

vmm.py:

  • updateFundingPerjod
  • updateAdmin

These functions lack a docstring, which is a string enclosed in triple quotes. that describes the purpose and behavior of the functions. Documentation plays a vital role in understanding and maintaining the contracts, and its absence hinders comprehension and collaboration efforts,

Recommendations:

To address this issue, we recommend the following improvements to the documentation. Include a docstring for each function that currently lacks one. The docstring should provide comprehensive information about the entry point, including:

  • A clear description of the function's purpose and functionality.
  • Details about the input parameters, including their meanings, types, and any restrictions or requirements.
  • Pre-conditions specifying who can call the entry point and any necessary conditions for its execution.
  • Post-conditions defining the expected outcomes or effects of executing the function,
  • Mention any operations that may be performed, such as transfers or contract origination, and their impact.