Enshroud
Smart Contract Audit Report

Executive Summary
This report presents the outcomes of our collaborative engagement with the Enshroud team, focusing on the comprehensive evaluation of the Enshroud Token, Crowdsale, TimelockManager, EnshroudProtocol, MVOStaking, and DAOPool contracts.
Our team conducted an initial security assessment from September 18th to October 16th, 2024 using provided contracts on Sepolia Testnet.
Enshroud is a new platform which includes a new token, a token sale, asset encryption through the use of NFTs, staking, and transaction validators.
Audit Scope
Name |
Source Code (Testnet) |
Visualized |
EnshroudToken |
||
CrowdSale |
||
TimelockManager |
||
EnshroudProtocol |
||
MVOStaking |
||
DAOPool |
Name/Source Code |
Visualized |
EnshroudToken
|
|
CrowdSale
|
|
TimelockManager
|
|
EnshroudProtocol
|
|
MVOStaking
|
|
DAOPool
|
Audit Findings
High findings were identified and the team must review them. In addition, centralized aspects are present.
Finding #1 |
DAOPool |
High Open |
Finding #1 - DAOPool
|
||
Description: When a claim for deposit trade is created, an open offer is created for the user offering the shares for a claim, but when the trade is executed, the share amount is decremented from the open offer of the user providing the tokens.
Risk/Impact: The token offeror's openOffer mapping may underflow, breaking trading functionality. Recommendation: The openOffer value of the claim offeror should be decremented instead of the openOffer of the token offeror. Resolution: The team has not yet resolved this issue. |
||
Finding #2 |
DAOPool |
High Open |
Finding #2 - DAOPool
|
||
Description: When claiming Enshroud tokens, the total staked amount is excluded from the total claimable tokens to prevent user's staked balances from being withdrawn as rewards; however, deposited (unstaked) Enshroud tokens are not excluded. Risk/Impact: Users' deposited but unstaked ENSHROUD balances will be distributed as rewards. Recommendation: The contract's total deposited ENSHROUD should be excluded from claimable rewards. Resolution: The team has not yet resolved this issue. |
||
Finding #3 |
DAOPool |
High Open |
Finding #3 - DAOPool
|
||
Description: The claimed mapping for ETH is used to ensure that a user has not claimed before making a claim offer as ETH is intended to be claimed on any type of claim, but the claimTokenYieldAsENFTs() function does not claim ETH.
Risk/Impact: An offeror can claim yield in every available token excluding ETH, then offer a claim. The token offeror will still be permitted to accept the trade, but the claim offeror will only lose a portion of their ETH rewards while still receiving the full value from their other claims. This can be exploited by a user with two addresses by executing offers to another address owned by them in order to execute multiple token claims using the same shares. Recommendation: The claimTokenYieldAsENFTs() function should automatically distribute ETH rewards and update a user's claimed mapping for ETH. Resolution: The team has not yet resolved this issue. |
||
Finding #4 |
DAOPool |
High Open |
Finding #4 - DAOPool
|
||
Description: A user can stake and lock another user's tokens on behalf of them at any time. Risk/Impact: A user's deposit balance can be locked by another user at any time, preventing them from withdrawing for at least one week. Recommendation: Users should only be permitted to stake their own deposit balance, or staking approval functionality should be added. Resolution: The team has not yet resolved this issue. |
||
Finding #5 |
DAOPool |
High Open |
Finding #5 - DAOPool
|
||
Description: When staking on behalf of another user, the specified user's staked tokens are delegated to the caller's delegate instead of the staker's. Risk/Impact: Voting power may be incorrect or break due to incorrect delegation of voting power. Recommendation: Users should only be permitted to stake their own deposit balance. Resolution: The team has not yet resolved this issue. |
||
Finding #6 |
DAOPool |
High Open |
Finding #6 - DAOPool
|
||
Description: Users cannot withdraw from their staked MVO balance if they have an active Timelock.
Risk/Impact: If a malicious user withdraws their Timelock balance to another user's MVO address, the recipient will not be permitted to withdraw from their MVO until the Timelock has completed, regardless of if they have an existing unlocked staking balance. Recommendation: Timelocked balances should not prevent users from withdrawing their non-timelocked balances. Resolution: The team has not yet resolved this issue. |
||
Finding #7 |
TimelockManager |
High Open |
Finding #7 - TimelockManager
|
||
Description: The IMVOStaking_Timelock stakeTimelock() function declaration used by the Timelock contract contains parameters in incorrect order.
Timelock stakeTimelock function:
Risk/Impact: The Timelock contract's withdrawTimelockToMVOStaking() function will fail if a user has an active Timelock. Recommendation: The team should update the mentioned interface and function call to use the correct function parameters. Resolution: The team has not yet resolved this issue. |
||
Finding #8 |
EnshroudProtocol |
Medium Open |
Finding #8 - EnshroudProtocol
|
||
Description: A user can provide any token for deposit, but fee-on-transfer tokens are not supported. Risk/Impact: User balances will be larger than their deposited amounts. As a result, user withdrawals may fail or result in a loss of other users' deposited funds. Recommendation: The team should add support for fee-on-transfer tokens, or add a token whitelist. Resolution: The team has not yet resolved this issue. |
||
Finding #9 |
CrowdSale |
Medium Open |
Finding #9 - CrowdSale
|
||
Description: The minWei variable used to prevent users from sending less than the minimum token price is set to the initial token price upon deployment, but is not increased to match the price increase from Tier increments. Risk/Impact: If a user provides less than the minimum price of a token after the Tier has increased, they will not receive any tokens and lose their provided ETH. Recommendation: The minWei variable should be increased on every Tier increment. Resolution: The team has not yet resolved this issue. |
||
Finding #10 |
EnshroudProtocol & MVOStaking |
Low Open |
Finding #10 - EnshroudProtocol & MVOStaking
|
||
Description: The RequestApproved() function requires three Admins to approve certain administrative updates before it can be executed. This is done by approving a certain address; however, there is no restriction on which administrative function the proposed address will be used for.
Risk/Impact: If two Admins call a function to update an address, such as setMVOStakingAddress(), a third Admin could call updateDaoPool(), providing the address intended to be used as the MVOStaking contract. This function would execute as the address had been given two approvals. Recommendation: The team should ensure that address approvals are function-specific. Resolution: The team has not yet resolved this issue. |
||
Finding #11 |
EnshroudProtocol |
Informational Open |
Finding #11 - EnshroudProtocol
|
||
Description: User points can be artificially inflated through multiple deposits of valueless tokens or using a malicious contract. As user points do not serve any purpose on-chain, this has no impact within the scope of this audit. Recommendation: The team should consider adding a token whitelist or updating the user points logic. |
System Overview
Enshroud Token and CrowdSaleENSHROUD is a new token used in core functionality throughout the platform. The Minter Role has the ability to mint any amount of tokens to any address at any time. Any user with the Minter Role has the ability to grant or revoke the Minter Role from any address at any time. This contract inherits ERC-20 Permit functionality to allow for gasless approvals, which is utilized in the throughout the project.
One option of purchasing tokens is through the CrowdSale contract. To start, 1,000,000 Enshroud Tokens are minted to the contract. Users can purchase tokens by supplying ETH to the contract once it has been initialized. The price of tokens is determined by the current Tier rate. Each Tier has a supply of 1 million tokens. Once a Tier's supply is purchased, 1 million tokens are minted for the next Tier and the rate is doubled. If a purchase amount is larger than the remaining tokens in a Tier, the remaining amount will be purchased at the next Tier's rate. Funds received by the contract are transferred to the team's Treasury address. Purchased Enshroud tokens are immediately transferred to the specified recipient upon purchase.
TimelockManagerThe TimelockManager contact is used to grant locked tokens to specified recipients. The Admin can create a new timelock for any recipient address if they do not already have an active one, specifying a source address, amount, start time, and end time. Enshroud tokens are transferred from the source address to this contract, and unlock linearly for withdrawal throughout the specified period. A user can alternatively withdraw their remaining timelock amount immediately to the associated DAO Pool address. The user can specify an address for the DAO Pool deposit beneficiary. Any unlocked funds are withdrawn to the DAO Pool as withdrawable, while the remaining amount is withdrawn to the DAO Pool as locked, maintaining the same linear unlock schedule. Additionally, users can withdraw their locked tokens to the MVO Staking contract. Upon withdrawing to the Staking contract, any pending unlocked tokens are transferred to the specified recipient. The remaining locked amount is transferred with continued unlocking in the Staking contract. The Admin can update the associated MVOStaking, DAOPool, or Admin addresses at any time.
Enshroud ProtocolThe EnshroudProtocol contract is used to support the core ENFT functionality of the platform. As the MVO and intended encryption functionality is outside the scope of this audit, we are unable to provide an assessment with regards to its effectiveness or security. Any user can make an ETH or ERC-20 token deposit on behalf of any address at any time. A deposit fee is deducted, and the remaining balance is added to the user's deposit. Any deposited ETH is wrapped upon deposit. The contract supports ERC-20Permit functionality, allowing users to make deposits using gasless approvals.
Given approval from MVOs (Market Value Operators), users have the option to mint "ENFTs", representing their deposited funds. When minting an ENFT, the user's deposit balance of the chosen asset is decreased, and this value is recorded in the ENFT’s metadata. As the caller is not included in the provided information, a signature can be used by any user to mint if they have the necessary token balance. The ENFTs can later be redeemed for their underlying asset value or exchanged for new ENFTs. Upon redemption, a withdrawal fee is deducted, and the remaining balance is transferred to the user. If the sum of the provided amounts is less than the Operations Info amount when redeeming, an ENFT is also minted to the user.
A portion of the deposit and withdrawal fees are allocated to the Treasury address, while the remainder is sent to the DAO Pool. Custom deposit and withdrawal fees can be set for each token, but if no custom fee is specified, the standard ETH fee percentage is applied. Users can also spend their ENFTs by burning them to mint new ENFTs with different metadata. For minting, redeeming, or spending ENFTs, users must provide "Operations Info," which includes details such as the token, amount, and other data related to the ENFT, along with MVO IDs and signatures.
The MVOs that initially provided transaction information and signatures to the user are awarded points in the associated MVOStaking contract whenever an ENFT is minted, redeemed, or spent. Once an ENFT is minted, it cannot be redeemed or spent until the contract's minimum number of confirmation blocks has passed. Portions of the Operations Info related to the ENFT operation, signatures, and IDs are verified within the MVOStaking contract. Additionally, an ENFT cannot be minted, redeemed, or spent if its ID has been added to the Auditor Greylist. There is no deadline for execution once provided transaction information and signatures from an MVO.
Three separate Admins can agree on a proposal in order to update the associated MVO Staking address, DAO Pool address, Treasury address, update an Auditor's status, or remove an ENFT's greylist status. An address with Admin status in this contract is also considered an Admin within the MVOStaking and DAOPool contracts.
MVOs and MVO StakingThe MVOStaking contract is designed to manage staking, reward distribution, and governance for MVO participants within the Enshroud Protocol. MVOs are responsible for validating transactions within the EnshroudProtocol contract, earning rewards for their participation. The contract stores incentives in the form of Enshroud tokens to be distributed over a five-year period, with a decreasing reward schedule from 5 million tokens in year one to 1 million tokens in year five. Claiming is disabled after five years have passed.
When points are awarded to a list of MVOs resulting from ENFT operations in the EnshroudProtocol contract, the lead MVO's associated Staking address is awarded three points, while each of the "committee MVO" staking addresses are awarded 1 point. An MVO's staking address rewards are accrued over time based on the reward rate at the time of claiming and the number of points the address has in relation to the total number of points. If the MVO is part of a pool, a percentage of the rewards are minted to its associated pool. An Admin can manually reduce an MVO's points at any time.
An MVO's staking address can stake tokens at any time. Staking can occur directly by approving this contract before depositing, depositing using permit for gasless approval, or through a timelock through the TimelockManager contract. In either instance, the amount staked is instantly added to the MVO's stake amount. An MVO must hold the minimum staking requirement and be set as active in order to participate in transaction validation and pools.
An existing MVO staking address can create a new MVO Pool with a new mining pool ID and pool fee up to 50%. An MVO Pool can be deleted by its owner at any time. Active MVOs can join an existing pool if they have no pending rewards and have at least the minimum stake amount.
Any Admin can add, update, or remove an MVO at any time. The minimum stake amount and associated Enshroud Protocol address can be updated with approval from three unique admins.
DAOPoolThe DAOPool contract serves as the central staking and governance mechanism for the Enshroud protocol, handling staking, reward distribution, balance trading, and voting functionality. Users can stake Enshroud tokens into the contract to gain governance shares, which grant voting rights within the DAO and the ability to claim protocol yield.
Users can deposit Enshroud tokens directly to the contract using either approval or permit, or by a DAOPool withdrawal from the TimelockManager contract. When locked tokens are withdrawn from a Timelock into this contract, they maintain their existing vesting schedule. Deposited tokens can then be withdrawn or staked for shares which hold voting power. Voting power can be delegated to a different address. A user cannot update their delegate or undelegate more than once per week.
Staked tokens also entitle users to a share of the total amount of any token or ETH held by the contract at the time of claiming, excluding the total staked amount when claiming Enshroud tokens. Users can claim their rewards directly to their address, or have their rewards deposited into the EnshroudProtocol contract on their behalf. In addition, users can offer a portion of their shares for their next claim in exchange for an equal amount of deposited tokens. If another user accepts an offer, each party's deposit balance is adjusted permanently, and each of their shares are temporarily adjusted for their next claim only. Users must wait at least one week between specified token claims, maximizing their yield by claiming as often as possible. In order to unstake, users must initiate the unstake amount, then wait at least one week before completing the unstake. The equivalent voting power is lost once an unstake is initiated.
An Admin can update the associated TimelockManager and EnshroudProtocol addresses at any time.
Vulnerability Analysis
Vulnerability Category | Notes | Result |
---|---|---|
Arbitrary Jump/Storage Write | N/A | PASS |
Centralization of Control |
|
WARNING |
Compiler Issues | N/A | PASS |
Delegate Call to Untrusted Contract | N/A | PASS |
Dependence on Predictable Variables | N/A | PASS |
Ether/Token Theft | N/A | PASS |
Flash Loans | N/A | PASS |
Front Running | N/A | PASS |
Improper Events | N/A | PASS |
Improper Authorization Scheme | N/A | PASS |
Integer Over/Underflow | N/A | PASS |
Logical Issues | FAIL | |
Oracle Issues | N/A | PASS |
Outdated Compiler Version | N/A | PASS |
Race Conditions | N/A | PASS |
Reentrancy | N/A | PASS |
Signature Issues | N/A | PASS |
Sybil Attack | N/A | PASS |
Unbounded Loops | N/A | PASS |
Unused Code | N/A | PASS |
Overall Contract Safety | FAIL |
About SourceHat
SourceHat has quickly grown to have one of the most experienced and well-equipped smart contract auditing teams in the industry. Our team has conducted 1800+ solidity smart contract audits covering all major project types and protocols, securing a total of over $50 billion U.S. dollars in on-chain value!
Our firm is well-reputed in the community and is trusted as a top smart contract auditing company for the review of solidity code, no matter how complex. Our team of experienced solidity smart contract auditors performs audits for tokens, NFTs, crowdsales, marketplaces, gambling games, financial protocols, and more!
Contact us today to get a free quote for a smart contract audit of your project!
What is a SourceHat Audit?
Typically, a smart contract audit is a comprehensive review process designed to discover logical errors, security vulnerabilities, and optimization opportunities within code. A SourceHat Audit takes this a step further by verifying economic logic to ensure the stability of smart contracts and highlighting privileged functionality to create a report that is easy to understand for developers and community members alike.
How Do I Interpret the Findings?
Each of our Findings will be labeled with a Severity level. We always recommend the team resolve High, Medium, and Low severity findings prior to deploying the code to the mainnet. Here is a breakdown on what each Severity level means for the project:
- High severity indicates that the issue puts a large number of users' funds at risk and has a high probability of exploitation, or the smart contract contains serious logical issues which can prevent the code from operating as intended.
- Medium severity issues are those which place at least some users' funds at risk and has a medium to high probability of exploitation.
- Low severity issues have a relatively minor risk association; these issues have a low probability of occurring or may have a minimal impact.
- Informational issues pose no immediate risk, but inform the project team of opportunities for gas optimizations and following smart contract security best practices.