Q1 2025 Web3 Security ReportAccess control failures led to $1.63 billion in losses
Discover report insights
  • Hacken
  • Audits
  • doefin
  • [SCA] Doefin / Doefin-Contracts / Sept2024
Doefin logo

Doefin

Audit name:

[SCA] Doefin / Doefin-Contracts / Sept2024

Date:

Apr 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 Doefin team for the collaborative engagement that enabled the execution of this Smart Contract Security Assessment.

This documentation introduces the core components of the Doefin protocol, a decentralized options trading platform combining off-chain Bitcoin block header verification and secure options settlement. Key contracts include the DoefinV1OrderBook, which manages binary options' creation, matching, and settlement; DoefinV1Config, which enables flexible protocol configuration; and the DoefinV1BlockHeaderOracle, which verifies Bitcoin block headers to support accurate option outcomes. Supplementing these, the BlockHeaderUtils library provides tools for handling Bitcoin block headers, ensuring the platform operates with integrity and transparency.

Document

NameSmart Contract Code Review and Security Analysis Report for Doefin
Audited ByAtaberk Yavuzer, Viktor Raboshchuk
Approved ByGrzegorz Trawinski
Websitehttps://www.doefin.com/
Changelog29/10/2024 - Preliminary Report
02/12/2024 - Secondary Report
04/04/2025 - Final Report
PlatformArbitrum
LanguageSolidity
TagsOracle, OrderBook, ERC-1155, Centralized Exchange (CEX), Meta Transactions
Methodologyhttps://hackenio.cc/sc_methodology
  • Document

    Name
    Smart Contract Code Review and Security Analysis Report for Doefin
    Audited By
    Ataberk Yavuzer, Viktor Raboshchuk
    Approved By
    Grzegorz Trawinski
    Changelog
    29/10/2024 - Preliminary Report
    02/12/2024 - Secondary Report
    04/04/2025 - Final Report
    Platform
    Arbitrum
    Language
    Solidity
    Tags
    Oracle, OrderBook, ERC-1155, Centralized Exchange (CEX), Meta Transactions

Review Scope

Repositoryhttps://github.com/Doefin/v1-core/tree/master
Commit862d43
Retest commit94a1158

Audit Summary

19Total Findings
17Resolved
2Accepted
0Mitigated

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

Documentation quality

  • Whitepaper documentation is missed.

  • Functional requirements is provided.

  • Technical description is provided.

Code quality

  • The code mostly follows gas optimization examples.

  • The development environment is configured.

Test coverage

Code coverage of the project is 67% (branch coverage)

  • Deployment and basic user interactions are covered with tests.

  • Negative cases coverage is partially missed.

  • Interactions by several users are not tested thoroughly.

System Overview

Doefin is a decentralized options trading platform with off-chain bitcoin block header verification, order book management, and options settlement with the following contracts:

DoefinV1OrderBook - handles creating, matching, exercising, and settling binary options. It interacts with collateral tokens, manages premiums, and ensures that options are processed according to the rules defined by the protocol.

DoefinV1Config - serves as the configuration manager for the Doefin protocol. It allows the owner to set and update various protocol parameters, such as the list of approved tokens, the addresses of critical protocol components, and more.

DoefinV1BlockHeaderOracle - acts as a block header oracle for verifying Bitcoin block headers. It is responsible for ensuring the integrity of the block headers submitted to the Doefin protocol and uses them to determine the settlement of options.

BlockHeaderUtils - library provides utility functions to assist in the validation and processing of Bitcoin block headers within the DoefinV1BlockHeaderOracle contract. It ensures that block headers are correctly hashed and validated according to Bitcoin's consensus rules before being accepted by the oracle.

Privileged roles

  • The owner of the DoefinV1Config contract can add approved tokens, remove approved tokens, set the fee, set the order book address, set the fee address, set the block header oracle address, set the authorized relayer, set the trusted forwarder

  • The owner of the DoefinV1OrderBook contract can delete orders from the order book.

  • The authorized relayer in the DoefinV1OrderBook contract can create and match orders by utilizing the createAndMatchOrder function.

  • The trusted forwarder of the DoefinV1OrderBook contract has the privilege to relay meta-transactions on behalf of users.

Potential Risks

Dependency on Unaudited External Libraries: The project utilizes libraries or contracts without security audits, potentially introducing vulnerabilities. This compromises the security of the audited system, making it susceptible to attacks exploiting these external weaknesses. Since the solady library is not audited by a major smart contract security firm, it may pose a risk mentioned here.

Dynamic Array Iteration Gas Limit Risks: The project iterates over large dynamic arrays, which leads to excessive gas costs, risking denial of service due to out-of-gas errors, directly impacting contract usability and reliability.

Insufficient Multi-signature Controls for Critical Functions: The lack of multi-signature requirements for key operations centralizes decision-making power, increasing vulnerability to single points of failure or malicious insider actions, potentially leading to unauthorized transactions or configuration changes. The Doefin team announced that they will utilize a multi-signature wallet for the mainnet deployment.

Owner's Unrestricted State Modification: The absence of restrictions on state variable modifications by the owner leads to arbitrary changes, affecting contract integrity and user trust, especially during critical operations like minting phases.

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. If the administrative key data is stored in an unreliable manner or if there is an insider actor, it can pose a great risk to the management of the project. For this reason, distributing some permissions to other roles in a more distributed manner may be a good suggestion to prevent this.

Findings

Code
Title
Status
Severity
F-2024-6765Unauthorized Users Can Change Crucial Roles
fixed

Critical
F-2024-6831Validation Error in updateOrder Allows makerPremium to Exceed notional
fixed

High
F-2024-6816Frontrunning Attack Leading to Fund Theft
fixed

High
F-2025-8475Invalid Block Difficulty Calculation Affects Order Logic
fixed

High
F-2025-9446Order Updates Does Not Take the Payout Calculation Into Account
fixed

High
F-2024-6828ERC1155 Tokens Not Burned in deleteOrders() Function
fixed

Medium
F-2024-6822Removal of Approved Tokens May Lead to Business Requirement Violations
fixed

Medium
F-2024-6817Order Execution Infeasibility in Edge Case of Identical Strike Value
fixed

Medium
F-2025-9448Different Expiry Type Can Lead to Invalid Order Creation
fixed

Medium
F-2024-6841Unlimited Order Placing Can Lead To Order Griefing
accepted

Low
1-10 of 19 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/Doefin/v1-core/tree/master
Commit862d43eb006989bfe2ba74ef2923c272c18187b8
Retest commit94a1158e24c12a94bde3dc50e5dfe8a906d6d9c5
WhitepaperN/A
Requirementshttps://github.com/Doefin/v1-core/README.md
Technical Requirementshttps://docs.google.com/document/d/15Hg-VeCIqXWbK8lEe-2mjVdRuuDi0vpZh91576B8BKQ

Assets in Scope

DoefinV1BlockHeaderOracle.sol - DoefinV1BlockHeaderOracle.sol
DoefinV1Config.sol - DoefinV1Config.sol
DoefinV1OrderBook.sol - DoefinV1OrderBook.sol
abstracts
NoDelegateCall.sol - abstracts/NoDelegateCall.sol
libraries
BlockHeaderUtils.sol - libraries/BlockHeaderUtils.sol
Errors.sol - libraries/Errors.sol
interfaces
IAdminable.sol - interfaces/IAdminable.sol
IDoefinBlockHeaderOracle.sol - interfaces/IDoefinBlockHeaderOracle.sol
IDoefinConfig.sol - interfaces/IDoefinConfig.sol
IDoefinV1OrderBook.sol - interfaces/IDoefinV1OrderBook.sol

Appendix 3. Additional Valuables

Verification of System Invariants

During the audit of Doefin contracts, 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, 30 invariants were tested over 50000 runs. This thorough testing ensured that the system works correctly even with unexpected or unusual inputs.

Invariant

Test Result

Run Count

test__CancelOrder: An order can only be canceled if it is pending; upon cancellation, the maker's balance increases by the maker's premium; upon cancellation, the order book's balance decreases by the maker's premium; the order's status is updated to canceled upon cancellation.Passed50k+
test__fuzzMatchOrder: Upon matching, the taker is correctly set in the order metadata; the taker's premium is correctly calculated as notional minus maker premium; the order book's collateral balance increases by the taker's premium amount; both maker and taker receive an token with a balance of one.Passed50k+
testFuzz_settleOrder: The order's status is updated to settled after successful settlement; unauthorized attempts to call settleOrder should revert; the order remains matched if settled before expiry.Passed50k+
testFuzz_deleteOrders: Only the contract owner can call deleteOrders; orders past their expiry or deadline are deleted; the maker's order token balance becomes zero upon deletion; the order's status is updated appropriately after deletion.Failed50k+
test__settleOrderByBlockNumberAfterSubmittingNextBlock: An order is settled after the required number of blocks are submitted to the BlockHeaderOracle; upon settlement, the order's status updates to settled; the winner is correctly determined based on final strike and initial strike and the maker's position; upon exercising the order, the winner's balance increases by the payout amount; after exercise, both the maker's and taker's order token balances are zero.Passed50k+
testFuzz_updateOrder_InvalidNotional: The maker's premium must always be less than the notional amount; updating an order to have a maker premium greater than or equal to the notional should revert with OrderBook_InvalidNotional; after a successful update, the maker's premium and notional are updated correctly; the maker's premium remains less than the notional after the update; the order's parameters are correctly updated only if the new premium is less than the new notional.Failed50k+
test__fuzzExerciseOrder: Upon exercising a settled order, the correct winner is determined based on the final strike relative to the initial strike and the maker's position; the winner's balance increases by the payout amount upon exercise; the winner receives the payout amount; the maker's and taker's order token balances are zero after exercise; the exercise of the order correctly transfers the payout to the winner; the order cannot be exercised before it is settled;Failed50k+
testFuzz_reverseUint32: Should correctly reverse a uint32 valuePassed50k+
testFuzz_reverseBytes32: Should correctly reverse a bytes32 valuePassed50k+
testFuzz_calculateBlockHash: Given a valid block header with non-zero fields, calculating the block hash should produce a valid non-zero hash;Passed50k+
testFuzz_calculateDifficultyTarget: The calculated difficulty target matches the expected value based on the nBits field; difficulty target calculation correctly interprets the compact representation in nBits.Passed50k+
testFuzz_isValidBlockHeaderHash: A block header hash is valid if it is less than the calculated difficulty target; the validity of a block hash correctly reflects whether it meets the target difficulty.Passed50k+
testFuzz_SetFee: The fee can be set to any value less than or equal to 10,000 by the contract owner; after setting the fee, getFee() should return the new fee; setting a valid fee updates the configuration correctly.Passed50k+
testFuzz_SetFee_InvalidFee: Setting the fee to a value greater than 10,000 should revert with Config_InvalidFee; invalid fee values above 100% cannot be set; the contract enforces fee limits to prevent invalid configurations.Passed50k+
testFuzz_SetFee_NotOwner: Only the contract owner can set the fee; attempts by non-owner accounts to set the fee should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the fee.Passed50k+
testFuzz_SetFeeAddress: The fee address can be set to any non-zero address by the contract owner; after setting, getFeeAddress() should return the new fee address; setting a valid fee address updates the configuration correctly.Passed50k+
testFuzz_SetFeeAddress_NotOwner: Only the contract owner can set the fee address; attempts by non-owner accounts to set the fee address should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the fee address.Passed50k+
testFuzz_SetAuthorizedRelayer: The authorized relayer can be set to any non-zero address by the contract owner; after setting, getAuthorizedRelayer() should return the new authorized relayer address; setting a valid authorized relayer updates the configuration correctly.Passed50k+
testFuzz_SetAuthorizedRelayer_NotOwner: Only the contract owner can set the authorized relayer; attempts by non-owner accounts to set the authorized relayer should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the authorized relayer.Failed50k+
testFuzz_SetOrderBook: The order book address can be set to any non-zero address by the contract owner; after setting, getOrderBook() should return the new order book address; setting a valid order book address updates the configuration correctly.Passed50k+
testFuzz_SetOrderBook_NotOwner: Only the contract owner can set the order book address; attempts by non-owner accounts to set the order book address should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the order book address.Passed50k+
testFuzz_SetBlockHeaderOracle: The block header oracle address can be set to any non-zero address by the contract owner; after setting, getBlockHeaderOracle() should return the new block header oracle address; setting a valid block header oracle address updates the configuration correctly.Passed50k+
testFuzz_SetBlockHeaderOracle_NotOwner: Only the contract owner can set the block header oracle address; attempts by non-owner accounts to set the block header oracle address should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the block header oracle address.Passed50k+
testFuzz_SetTrustedForwarder: The trusted forwarder address can be set to any non-zero address by the contract owner; after setting, getTrustedForwarder() should return the new trusted forwarder address; setting a valid trusted forwarder updates the configuration correctly.Passed50k+
testFuzz_SetTrustedForwarder_NotOwner: Only the contract owner can set the trusted forwarder address; attempts by non-owner accounts to set the trusted forwarder should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the trusted forwarder address.Failed50k+
testFuzz_AddTokenToApprovedList: The contract owner can add any non-zero token address with a non-zero minimum collateral amount to the approved token list; adding a token updates the internal approved token list correctly; the function does not revert when called with valid inputs by the owner.Passed50k+
testFuzz_AddTokenToApprovedList_NotOwner: Only the contract owner can add tokens to the approved list; attempts by non-owner accounts to add a token should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the approved token list.Passed50k+
testFuzz_RemoveTokenFromApprovedList: The contract owner can remove any token address from the approved token list; removing a token updates the internal approved token list correctly; the function does not revert when called with a valid token address by the owner.Passed50k+
testFuzz_RemoveTokenFromApprovedList_NotOwner: Only the contract owner can remove tokens from the approved list; attempts by non-owner accounts to remove a token should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the approved token list.Passed50k+
  • Invariant

    test__CancelOrder: An order can only be canceled if it is pending; upon cancellation, the maker's balance increases by the maker's premium; upon cancellation, the order book's balance decreases by the maker's premium; the order's status is updated to canceled upon cancellation.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    test__fuzzMatchOrder: Upon matching, the taker is correctly set in the order metadata; the taker's premium is correctly calculated as notional minus maker premium; the order book's collateral balance increases by the taker's premium amount; both maker and taker receive an token with a balance of one.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_settleOrder: The order's status is updated to settled after successful settlement; unauthorized attempts to call settleOrder should revert; the order remains matched if settled before expiry.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_deleteOrders: Only the contract owner can call deleteOrders; orders past their expiry or deadline are deleted; the maker's order token balance becomes zero upon deletion; the order's status is updated appropriately after deletion.

    Test Result

    Failed

    Run Count

    50k+

    Invariant

    test__settleOrderByBlockNumberAfterSubmittingNextBlock: An order is settled after the required number of blocks are submitted to the BlockHeaderOracle; upon settlement, the order's status updates to settled; the winner is correctly determined based on final strike and initial strike and the maker's position; upon exercising the order, the winner's balance increases by the payout amount; after exercise, both the maker's and taker's order token balances are zero.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_updateOrder_InvalidNotional: The maker's premium must always be less than the notional amount; updating an order to have a maker premium greater than or equal to the notional should revert with OrderBook_InvalidNotional; after a successful update, the maker's premium and notional are updated correctly; the maker's premium remains less than the notional after the update; the order's parameters are correctly updated only if the new premium is less than the new notional.

    Test Result

    Failed

    Run Count

    50k+

    Invariant

    test__fuzzExerciseOrder: Upon exercising a settled order, the correct winner is determined based on the final strike relative to the initial strike and the maker's position; the winner's balance increases by the payout amount upon exercise; the winner receives the payout amount; the maker's and taker's order token balances are zero after exercise; the exercise of the order correctly transfers the payout to the winner; the order cannot be exercised before it is settled;

    Test Result

    Failed

    Run Count

    50k+

    Invariant

    testFuzz_reverseUint32: Should correctly reverse a uint32 value

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_reverseBytes32: Should correctly reverse a bytes32 value

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_calculateBlockHash: Given a valid block header with non-zero fields, calculating the block hash should produce a valid non-zero hash;

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_calculateDifficultyTarget: The calculated difficulty target matches the expected value based on the nBits field; difficulty target calculation correctly interprets the compact representation in nBits.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_isValidBlockHeaderHash: A block header hash is valid if it is less than the calculated difficulty target; the validity of a block hash correctly reflects whether it meets the target difficulty.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_SetFee: The fee can be set to any value less than or equal to 10,000 by the contract owner; after setting the fee, getFee() should return the new fee; setting a valid fee updates the configuration correctly.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_SetFee_InvalidFee: Setting the fee to a value greater than 10,000 should revert with Config_InvalidFee; invalid fee values above 100% cannot be set; the contract enforces fee limits to prevent invalid configurations.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_SetFee_NotOwner: Only the contract owner can set the fee; attempts by non-owner accounts to set the fee should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the fee.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_SetFeeAddress: The fee address can be set to any non-zero address by the contract owner; after setting, getFeeAddress() should return the new fee address; setting a valid fee address updates the configuration correctly.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_SetFeeAddress_NotOwner: Only the contract owner can set the fee address; attempts by non-owner accounts to set the fee address should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the fee address.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_SetAuthorizedRelayer: The authorized relayer can be set to any non-zero address by the contract owner; after setting, getAuthorizedRelayer() should return the new authorized relayer address; setting a valid authorized relayer updates the configuration correctly.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_SetAuthorizedRelayer_NotOwner: Only the contract owner can set the authorized relayer; attempts by non-owner accounts to set the authorized relayer should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the authorized relayer.

    Test Result

    Failed

    Run Count

    50k+

    Invariant

    testFuzz_SetOrderBook: The order book address can be set to any non-zero address by the contract owner; after setting, getOrderBook() should return the new order book address; setting a valid order book address updates the configuration correctly.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_SetOrderBook_NotOwner: Only the contract owner can set the order book address; attempts by non-owner accounts to set the order book address should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the order book address.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_SetBlockHeaderOracle: The block header oracle address can be set to any non-zero address by the contract owner; after setting, getBlockHeaderOracle() should return the new block header oracle address; setting a valid block header oracle address updates the configuration correctly.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_SetBlockHeaderOracle_NotOwner: Only the contract owner can set the block header oracle address; attempts by non-owner accounts to set the block header oracle address should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the block header oracle address.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_SetTrustedForwarder: The trusted forwarder address can be set to any non-zero address by the contract owner; after setting, getTrustedForwarder() should return the new trusted forwarder address; setting a valid trusted forwarder updates the configuration correctly.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_SetTrustedForwarder_NotOwner: Only the contract owner can set the trusted forwarder address; attempts by non-owner accounts to set the trusted forwarder should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the trusted forwarder address.

    Test Result

    Failed

    Run Count

    50k+

    Invariant

    testFuzz_AddTokenToApprovedList: The contract owner can add any non-zero token address with a non-zero minimum collateral amount to the approved token list; adding a token updates the internal approved token list correctly; the function does not revert when called with valid inputs by the owner.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_AddTokenToApprovedList_NotOwner: Only the contract owner can add tokens to the approved list; attempts by non-owner accounts to add a token should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the approved token list.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_RemoveTokenFromApprovedList: The contract owner can remove any token address from the approved token list; removing a token updates the internal approved token list correctly; the function does not revert when called with a valid token address by the owner.

    Test Result

    Passed

    Run Count

    50k+

    Invariant

    testFuzz_RemoveTokenFromApprovedList_NotOwner: Only the contract owner can remove tokens from the approved list; attempts by non-owner accounts to remove a token should revert with "Ownable: caller is not the owner"; access control ensures only authorized users can modify the approved token list.

    Test Result

    Passed

    Run Count

    50k+

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