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

Audit name:

[SCA] Dione Protocol | OdysseyBridgeS | Sep2024

Date:

Oct 21, 2024

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

The Dione Protocol is a bridge solution between Ethereum and Odyssey blockchains. Oddysey chain is a highly performant Layer-1 protocol offering swift transaction finality, robust security, and seamless scalability. The bridge aims to transfer Dione tokens from Odyssey to Ethereum and USDC tokens from Ethereum to Odyssey primarily.

Document

NameSmart Contract Code Review and Security Analysis Report for Dione Protocol
Audited ByGrzegorz Trawinski, Viktor Raboshchuk
Approved ByPrzemyslaw Swiatowiec
Websitehttps://www.dioneprotocol.com/
Changelog30/09/2024 - Preliminary Report, 21/10/2024 - Final Report
PlatformEthereum, Odyssey
LanguageSolidity
TagsBridge
Methodologyhttps://hackenio.cc/sc_methodology
  • Document

    Name
    Smart Contract Code Review and Security Analysis Report for Dione Protocol
    Audited By
    Grzegorz Trawinski, Viktor Raboshchuk
    Approved By
    Przemyslaw Swiatowiec
    Changelog
    30/09/2024 - Preliminary Report, 21/10/2024 - Final Report
    Platform
    Ethereum, Odyssey
    Language
    Solidity
    Tags
    Bridge

Review Scope

Repositoryhttps://github.com/DioneProtocol/sfxdx__odyssey-bridge-sc
Commita89f414
Retest Commit8697ea1

Audit Summary

25Total Findings
24Resolved
1Accepted
0Mitigated

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

Documentation quality

  • Functional requirements are missed.

  • Technical description is partially provided.

Code quality

  • The code mostly follows style guides and best practices.

    • See observations for more details.

  • The development environment is configured.

Test coverage

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

  • Not all branches are covered with tests.

System Overview

The Dione Protocol is a bridge solution between Ethereum and Odyssey blockchains.

WDIONE - is a smart contract that wraps Dione token, allowing users to deposit and withdraw native Dione assets.

WDIONEBridged - is a smart contract for wrapped Dione token on the Ethereum side.

DioneBridge - is a main bridge contract. It is using the Wanchain Message Bridge (WMB) behind the scenes. It allows to deposit WDione tokens. It allows to redeem WDioneBridged tokens. Additionally it allows to bridge native tokens and any other ERC20 token. It supports both withdrawing tokens and minting wrapped tokens.

DioneBridgeERC20 - is a smart contract for bridge transfers of ERC20 token.

DioneBridgeERC20DeterministicFactory - is a smart contract that deploys ERC20 tokens for cross-chain bridges.

DioneBridgeERC20Factory - is a smart contract that allows the deployment of new ERC20 tokens by cloning a pre-existing token contract.

DioneBridgeERC677 - is a smart contract allowing tokens to be transferred with additional data, and if the recipient is a contract, it triggers a callback function on the recipient.

WmbAppUpgradeable - is an abstract base that enables applications to send and receive cross-chain messages via the Wanchain Message Bridge (WMB).

Privileged roles

  • The owner of the WDIONE can configure key parameters such as fees, blacklist management, and fee receiver updates.

  • The DEFAULT_ADMIN_ROLE of DioneBridge contract can set token limits, supported tokens, cross-chain parameters, and fees.

  • The GOVERNANCE_ROLE of DioneBridge contract can pause or unpause the contract operations.

  • The RESCUER_ROLE of DioneBridge contract allows the recovery of tokens that are accidentally sent to the contract.

  • The owner of the WDIONEBridged contract can set the transfer fee, the fee receiver, the fee threshold and manage the whitelist.

  • The bridge role WDIONEBridged contract.

  • The MINTER_ROLE of the DioneBridgeERC20 contract allows accounts to mint new tokens by calling the mint() function.

  • The owner of the DioneBridgeERC20DeterministicFactory contract can deploy deterministic token contracts using the deployDeterministic() function and transfer ownership.

  • In the WDIONEBridged contract, the onlyBridge modifier restricts access to mint() and burn(), functions, allowing only the DioneBridge contract to execute them.

Potential Risks

Risk of Stuck Transactions from Incorrect messageGasLimit: The admin role of contract DioneBridge capable to specify a custom messageGasLimit for the deposit and redeem functions. However, if the gasLimit is set incorrectly, it poses a risk that transactions may become indefinitely stuck in pending status or be reverted.

System Reliance on External Contracts: The functioning of the system significantly relies on Wanchain Message Bridge 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.

Flexibility and Risk in Contract Upgrades: The project's contracts are upgradable, allowing the administrator to update the contract logic at any time. While this provides flexibility in addressing issues and evolving the project, it also introduces risks if upgrade processes are not properly managed or secured, potentially allowing for unauthorized changes that could compromise the project's integrity and security.

Absence of Upgrade Window Constraints: The contract suite allows for immediate upgrades without a mandatory review or waiting period, increasing the risk of rapid deployment of malicious or flawed code, potentially compromising the system's integrity and user assets.

Findings

Code
Title
Status
Severity
F-2024-6287The wmbReceive's Mint Does Not Update _balances Array
fixed

Critical
F-2024-6290The rescueTokens Function Can Break Bridge Accounting
fixed

High
F-2024-6291Inconsistent and Ambiguous Application of Fees
fixed

High
F-2024-6337The transferFrom Does Not Check Allowance For Applied Fee
fixed

Medium
F-2024-6338Fee-On-Transfer Is Applied On Top Of The Transferred Amount
fixed

Low
F-2024-6322Incorrect Fee Validation in setFee() Function Allows Excessive Fees and Prevents Reduction
fixed

Low
F-2024-6308The wmbReceive Function Can Revert Due To Gas Overconsumption
fixed

Low
F-2024-6307Excessive Amount of Native Tokens Are Collected By The Protocol
fixed

Low
F-2024-6292The dispatchMessage Can Revert Due To Too Large Fee Provided
fixed

Low
F-2024-6289USDC Blacklisting Feature Can Prevent Token Transfer
fixed

Low
1-10 of 25 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/DioneProtocol/sfxdx__odyssey-bridge-sc
Commita89f4141f732c1ac7d178154bff65649a9f30841
Retest Commit8697ea1c9c2f3c6873ba267d6cb759b1ad395c45
Whitepaperhttps://dione-protocol.gitbook.io/dione-whitepaper
RequirementsBridge and Wrapped D-2.pdf
Technical Requirements-

Assets in Scope

WDIONE.sol - WDIONE.sol
WDIONEBridged.sol - WDIONEBridged.sol
bridge
DioneBridgeERC20.sol - bridge › DioneBridgeERC20.sol
DioneBridgeERC20DeterministicFactory.sol - bridge › DioneBridgeERC20DeterministicFactory.sol
DioneBridgeERC20Factory.sol - bridge › DioneBridgeERC20Factory.sol
DioneBridge.sol - bridge › DioneBridge.sol
DioneBridgeERC677.sol - bridge › DioneBridgeERC677.sol
interfaces
IDioneBridge.sol - bridge › interfaces › IDioneBridge.sol
IDioneBridgeERC20.sol - bridge › interfaces › IDioneBridgeERC20.sol
IWETH9.sol - bridge › interfaces › IWETH9.sol
wanchain
app
WmbAppUpgradeable.sol - wanchain › app › WmbAppUpgradeable.sol
interfaces
IEIP5164.sol - wanchain › interfaces › IEIP5164.sol
IWanchainMPC.sol - wanchain › interfaces › IWanchainMPC.sol
IWmbConfig.sol - wanchain › interfaces › IWmbConfig.sol
IWmbGateway.sol - wanchain › interfaces › IWmbGateway.sol
IWmbReceiver.sol - wanchain › interfaces › IWmbReceiver.sol

Appendix 3. Additional Valuables

Verification of System Invariants

During the audit of Dione Protocol, Hacken followed its methodology by performing fuzz-testing on the project's main functions. Echidna , a tool used for fuzz-testing, was employed to check how the protocol behaves under various inputs. 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

WDIONE::setFeeBps Only the owner can set feeBps, and the new value must not exceed PCT_DIV.Failed50k
WDIONE::setFeeReceiver The feeReceiver must be a valid non-zero address, and only the owner can update it.Failed50k
WDIONE::setBlacklist Only the owner can add or remove an account from the blacklist, and the blacklist state must reflect the changes correctly.Passed50k
WDIONE::deposit The caller’s balanceOf must increase by msg.value, and the total supply must increase by the same amount.Passed50k
WDIONE::withdraw The withdrawal must not exceed the caller’s balance, and the withdrawn amount must be transferred to the caller.Passed50k
WDIONE::approve The allowance for the spender must be set to the provided amount, and the Approval event must be emitted.Passed50k
WDIONE::transferFrom The src address must have sufficient balance, the allowance must be correctly handled, and the transfer fee must be deducted if applicable.Passed50k
WDIONEBridged::checkAndSendFees The function sends collected fees to the target chain when the collectedFees exceed feeThreshold, ensuring sufficient ETH is available for the operation.50k
WDIONEBridged::receive The receive() function allows the contract to accept ETH payments to fund cross-chain fee transfers.Passed50k
WDIONEBridged::mint() The function, callable only by the bridge, mints tokens to the specified address, increasing the total supply accordingly.Passed50k
WDIONEBridged::burn The function, callable only by the bridge, burns tokens from the caller's balance if sufficient, decreasing the total supply.Passed50k
WDIONEBridged::setFee The function, callable only by the owner, sets the transfer fee in basis points, ensuring it does not exceed PCT_DIV.Failed50k
WDIONEBridged::setFeeReceiver The function, callable only by the owner, updates the fee receiver's address accurately.Failed50k
WDIONEBridged::setFeeThreshold The function, callable only by the owner, sets the feeThreshold which determines when fees are sent to the target chain.Passed50k
WDIONEBridged::setWhitelist The function, callable only by the owner, correctly adds or removes a single account from the whitelist.Passed50k
DioneBridge::setWethAddress Only the admin can set WETH_ADDRESS, and it must be a non-zero address.Failed50k
DioneBridge::setSupportedBridge Only the admin can set supported bridges, and each chain ID must map to a valid non-zero bridge address.Failed50k
DioneBridge::setMaxSupply Only the admin can set the max supply for a specific token, it must be a non-zero address, and the new max supply must be stored correctly.Failed50k
DioneBridge::setMessageGasLimit Only the admin can set the gas limit for messages, ensuring it is stored correctly.Passed50k
DioneBridge::setTokenForReceive Only the admin can configure which tokens are supported for receiving from another chain, and the token operation must be valid.Failed50k
DioneBridge::setTokenToSend Only the admin can configure which non-zero address tokens are supported for sending to another chain, and the operation must be valid.Failed50k
DioneBridge::setWhitelist Only the admin can add or remove an address from the whitelist, and the whitelist state must be updated accordingly.Passed50k
DioneBridge::deposit The token must be supported, the correct fees must be deducted, and the remaining amount must be deposited into the contract.Passed50k
DioneBridge::redeem The token must be supported, the correct fees must be deducted, and the remaining amount must be burned, with the cross-chain withdrawal initiated.Passed50k
DioneBridge::rescueTokens Only the rescuer role can rescue tokens, and the rescued amount must be transferred to the specified address.Passed50k
DioneBridge::withdrawFees Only the admin can withdraw accumulated fees, ensuring the correct amount is transferred to the recipient, and the fees are updated.Passed50k
WmbAppUpgradeable::wmbReceive The wmbReceive function can only be called by the wmbGateway contract. The from address and fromChainId must be trusted according to the trustedRemotes mapping. Minting or withdrawing tokens operations must be successfully processed to ensure correct state transitions and token handling.Passed50k
WmbAppUpgradeable::setTrustedRemotes Only accounts with the DEFAULTADMINROLE can call setTrustedRemotes. The lengths of fromChainIds, froms, and trusted arrays must be equal. Updates the trustedRemotes mapping to reflect the provided trusted statuses for each remote address.Passed50k
  • Invariant

    WDIONE::setFeeBps Only the owner can set feeBps, and the new value must not exceed PCT_DIV.

    Test Result

    Failed

    Run Count

    50k

    Invariant

    WDIONE::setFeeReceiver The feeReceiver must be a valid non-zero address, and only the owner can update it.

    Test Result

    Failed

    Run Count

    50k

    Invariant

    WDIONE::setBlacklist Only the owner can add or remove an account from the blacklist, and the blacklist state must reflect the changes correctly.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    WDIONE::deposit The caller’s balanceOf must increase by msg.value, and the total supply must increase by the same amount.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    WDIONE::withdraw The withdrawal must not exceed the caller’s balance, and the withdrawn amount must be transferred to the caller.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    WDIONE::approve The allowance for the spender must be set to the provided amount, and the Approval event must be emitted.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    WDIONE::transferFrom The src address must have sufficient balance, the allowance must be correctly handled, and the transfer fee must be deducted if applicable.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    WDIONEBridged::checkAndSendFees The function sends collected fees to the target chain when the collectedFees exceed feeThreshold, ensuring sufficient ETH is available for the operation.

    Test Result

    Run Count

    50k

    Invariant

    WDIONEBridged::receive The receive() function allows the contract to accept ETH payments to fund cross-chain fee transfers.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    WDIONEBridged::mint() The function, callable only by the bridge, mints tokens to the specified address, increasing the total supply accordingly.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    WDIONEBridged::burn The function, callable only by the bridge, burns tokens from the caller's balance if sufficient, decreasing the total supply.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    WDIONEBridged::setFee The function, callable only by the owner, sets the transfer fee in basis points, ensuring it does not exceed PCT_DIV.

    Test Result

    Failed

    Run Count

    50k

    Invariant

    WDIONEBridged::setFeeReceiver The function, callable only by the owner, updates the fee receiver's address accurately.

    Test Result

    Failed

    Run Count

    50k

    Invariant

    WDIONEBridged::setFeeThreshold The function, callable only by the owner, sets the feeThreshold which determines when fees are sent to the target chain.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    WDIONEBridged::setWhitelist The function, callable only by the owner, correctly adds or removes a single account from the whitelist.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    DioneBridge::setWethAddress Only the admin can set WETH_ADDRESS, and it must be a non-zero address.

    Test Result

    Failed

    Run Count

    50k

    Invariant

    DioneBridge::setSupportedBridge Only the admin can set supported bridges, and each chain ID must map to a valid non-zero bridge address.

    Test Result

    Failed

    Run Count

    50k

    Invariant

    DioneBridge::setMaxSupply Only the admin can set the max supply for a specific token, it must be a non-zero address, and the new max supply must be stored correctly.

    Test Result

    Failed

    Run Count

    50k

    Invariant

    DioneBridge::setMessageGasLimit Only the admin can set the gas limit for messages, ensuring it is stored correctly.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    DioneBridge::setTokenForReceive Only the admin can configure which tokens are supported for receiving from another chain, and the token operation must be valid.

    Test Result

    Failed

    Run Count

    50k

    Invariant

    DioneBridge::setTokenToSend Only the admin can configure which non-zero address tokens are supported for sending to another chain, and the operation must be valid.

    Test Result

    Failed

    Run Count

    50k

    Invariant

    DioneBridge::setWhitelist Only the admin can add or remove an address from the whitelist, and the whitelist state must be updated accordingly.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    DioneBridge::deposit The token must be supported, the correct fees must be deducted, and the remaining amount must be deposited into the contract.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    DioneBridge::redeem The token must be supported, the correct fees must be deducted, and the remaining amount must be burned, with the cross-chain withdrawal initiated.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    DioneBridge::rescueTokens Only the rescuer role can rescue tokens, and the rescued amount must be transferred to the specified address.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    DioneBridge::withdrawFees Only the admin can withdraw accumulated fees, ensuring the correct amount is transferred to the recipient, and the fees are updated.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    WmbAppUpgradeable::wmbReceive The wmbReceive function can only be called by the wmbGateway contract. The from address and fromChainId must be trusted according to the trustedRemotes mapping. Minting or withdrawing tokens operations must be successfully processed to ensure correct state transitions and token handling.

    Test Result

    Passed

    Run Count

    50k

    Invariant

    WmbAppUpgradeable::setTrustedRemotes Only accounts with the DEFAULTADMINROLE can call setTrustedRemotes. The lengths of fromChainIds, froms, and trusted arrays must be equal. Updates the trustedRemotes mapping to reflect the provided trusted statuses for each remote address.

    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