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 | |
---|---|
Name | Smart Contract Code Review and Security Analysis Report for Doefin |
Audited By | Ataberk Yavuzer, Viktor Raboshchuk |
Approved By | Grzegorz Trawinski |
Website | https://www.doefin.com/→ |
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 |
Methodology | https://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
- Website
- https://www.doefin.com/→
- 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
- Methodology
- https://hackenio.cc/sc_methodology→
Review Scope | |
---|---|
Repository | https://github.com/Doefin/v1-core/tree/master→ |
Commit | 862d43 |
Retest commit | 94a1158 |
Review Scope
- Commit
- 862d43
- Retest commit
- 94a1158
Audit Summary
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-6765 | Unauthorized Users Can Change Crucial Roles | fixed | Critical | |
F-2024-6831 | Validation Error in updateOrder Allows makerPremium to Exceed notional | fixed | High | |
F-2024-6816 | Frontrunning Attack Leading to Fund Theft | fixed | High | |
F-2025-8475 | Invalid Block Difficulty Calculation Affects Order Logic | fixed | High | |
F-2025-9446 | Order Updates Does Not Take the Payout Calculation Into Account | fixed | High | |
F-2024-6828 | ERC1155 Tokens Not Burned in deleteOrders() Function | fixed | Medium | |
F-2024-6822 | Removal of Approved Tokens May Lead to Business Requirement Violations | fixed | Medium | |
F-2024-6817 | Order Execution Infeasibility in Edge Case of Identical Strike Value | fixed | Medium | |
F-2025-9448 | Different Expiry Type Can Lead to Invalid Order Creation | fixed | Medium | |
F-2024-6841 | Unlimited Order Placing Can Lead To Order Griefing | accepted | Low |
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 | |
---|---|
Repository | https://github.com/Doefin/v1-core/tree/master→ |
Commit | 862d43eb006989bfe2ba74ef2923c272c18187b8 |
Retest commit | 94a1158e24c12a94bde3dc50e5dfe8a906d6d9c5 |
Whitepaper | N/A |
Requirements | https://github.com/Doefin/v1-core/README.md→ |
Technical Requirements | https://docs.google.com/document/d/15Hg-VeCIqXWbK8lEe-2mjVdRuuDi0vpZh91576B8BKQ→ |
Scope Details
- Commit
- 862d43eb006989bfe2ba74ef2923c272c18187b8
- Retest commit
- 94a1158e24c12a94bde3dc50e5dfe8a906d6d9c5
- Whitepaper
- N/A
- Requirements
- https://github.com/Doefin/v1-core/README.md→
- Technical Requirements
- https://docs.google.com/document/d/15Hg-VeCIqXWbK8lEe-2mjVdRuuDi0vpZh91576B8BKQ→
Assets in Scope
DoefinV1BlockHeaderOracle.sol
DoefinV1Config.sol
DoefinV1OrderBook.sol
abstracts/NoDelegateCall.sol
libraries/BlockHeaderUtils.sol
libraries/Errors.sol
interfaces/IAdminable.sol
interfaces/IDoefinBlockHeaderOracle.sol
interfaces/IDoefinConfig.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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Failed | 50k+ |
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. | Passed | 50k+ |
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. | Failed | 50k+ |
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; | Failed | 50k+ |
testFuzz_reverseUint32 : Should correctly reverse a uint32 value | Passed | 50k+ |
testFuzz_reverseBytes32 : Should correctly reverse a bytes32 value | Passed | 50k+ |
testFuzz_calculateBlockHash : Given a valid block header with non-zero fields, calculating the block hash should produce a valid non-zero hash; | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Failed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Failed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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. | Passed | 50k+ |
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 withOrderBook_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 valueTest Result
- Passed
Run Count
- 50k+
Invariant
testFuzz_reverseBytes32
: Should correctly reverse a bytes32 valueTest 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 withConfig_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.