Dreamster ICO and Vesting
Smart Contract Audit Report
Executive Summary
This report presents the outcomes of our collaborative engagement with the Dreamster team, focusing on the comprehensive evaluation of the Dreamster_Presale contract.
Our team conducted an initial security assessment from April 3rd to April 5th, 2024. On April 23rd, our team amended this report to reflect the project team's newly deployed contract on Sepolia that resolves all Findings. On May 10th, 2024, our team amended this report to reflect the contract's updated mainnet address. On June 24th, 2024, our team amended this report to reflect the contract's updated mainnet address.
The Dreamster ICO enables the purchasing of tokens via BNB or various ERC-20 tokens set by the team. A percentage of their purchase amount is received immediately, while the remaining tokens are vested throughout a period of time. We previously audited the Dreamster team's token contract here.
Audit Scope
Name |
Source Code |
Visualized |
Dreamster_Presale |
Name |
Address/Source Code |
Visualized |
Dreamster_Presale |
Audit Findings
All findings have been resolved, though some centralized aspects are present.
Finding #1 |
Dreamster_Presale |
HighResolved |
Finding #1 - Dreamster_Presale
|
||
Description: The buyToken() function allows the caller to specify any arbitrary duration for the
Risk/Impact: Any user can specify a short
Recommendation: The Resolution: The team has implemented the above recommendation. |
||
Finding #2 |
Dreamster_Presale |
HighResolved |
Finding #2 - Dreamster_Presale
|
||
Description: In the claimLinearVestAmt() function, there's a risk that
Risk/Impact: If
Recommendation: An if-statement should be added to the claimLinearVestAmt() function that checks if Resolution: The team has implemented the above recommendation. |
||
Finding #3 |
Dreamster_Presale |
HighResolved |
Finding #3 - Dreamster_Presale
|
||
Description: In the if-statement in the linearVest() function,
Risk/Impact: These additional tokens purchased by the user can never be claimed.
Recommendation: Resolution: The team has implemented the above recommendation. |
||
Finding #4 |
Dreamster_Presale |
HighResolved |
Finding #4 - Dreamster_Presale
|
||
Description: The
Risk/Impact: The
Recommendation: The team should adjust the logic in the claimLinearVestAmt() function by properly following a linear vesting schedule to ensure
Resolution: The team has modified the logic to now properly reflect |
||
Finding #5 |
Dreamster_Presale |
HighResolved |
Finding #5 - Dreamster_Presale
|
||
Description: In the claimLinearVestAmt() function, the calculation extends the user's subsequent claim time proportionally to the delay in initiating their last claim. Consequently, the timing for the user's next claim is pushed further into the future, effectively penalizing users who delay their claims. This approach diverges from the intended linear vesting schedule.
Risk/Impact: The overall vesting period is extended based on the time that a user waits in between claims, with the next claim time being set to reflect these delays. Recommendation: We suggest that the team revisit and adjust the logic within the claimLinearVestAmt() function to guarantee a true linear vesting schedule, irrespective of the timing of user claims. Resolution: The team has implemented the above recommendation. |
||
Finding #6 |
Dreamster_Presale |
MediumResolved |
Finding #6 - Dreamster_Presale
|
||
Description: The buyToken() function permits the caller to set the
Risk/Impact: Any user can specify 'refer' for the
Recommendation: The Resolution: The team has implemented the above recommendation. |
||
Finding #7 |
Dreamster_Presale |
MediumResolved |
Finding #7 - Dreamster_Presale
|
||
Description: The verifySign() function does not include the contract address when hashing values for the transaction to verify the signature. Risk/Impact: This could allow users to repurpose a signature meant for a different contract or chain, in the event a similar contract exists. Recommendation: The verifySign() function should include this contract's address into the hash, ensuring signatures are specific to this contract alone. Resolution: The team has implemented the above recommendation. |
||
Finding #8 |
Dreamster_Presale |
LowAcknowledged |
Finding #8 - Dreamster_Presale
|
||
Description: An inconsistency exists in the buyToken() function as, initially, 25% of the purchase amount is allocated to the recipient of the buyOrder, while the remaining 75% of tokens are vested towards the caller of the transaction. Risk/Impact: Should the recipient and the caller not be the same address, this setup results in tokens being distributed to two separate addresses from a single purchase. This may lead to potential misalignment with the team's intended token distribution. Recommendation: The buyToken() function should be modified to ensure tokens are both transferred and vested either to the caller or the recipient of the buyOrder, ensuring consistent token allocation on purchases. Resolution: The team has indicated that this functionality is intended. |
||
Finding #9 |
Dreamster_Presale |
InformationalResolved |
Finding #9 - Dreamster_Presale
|
||
Description: Although the contract inherits ReentrancyGuard, the nonReentrant modifier is not used in the contract. Recommendation: The team could remove the ReentrancyGuard contract to reduce contract size and deployment costs. Resolution: The team has removed the ReentrancyGuard contract. |
||
Finding #10 |
Dreamster_Presale |
InformationalResolved |
Finding #10 - Dreamster_Presale
|
||
Description: The Recommendation: The above state variable could be declared constant for additional gas savings on each reference.
Resolution: The team has added a function that allows them to update the |
System Overview
BUYING TOKENSAny user can initiate a purchase by specifying the details of their buy order and details of a signature. Each signature nonce is marked as 'used' to prevent it from being used more than once. The returned signer address for the applicable transaction details must be the Signer address set by the team.
The total number of tokens allocated to the buyer is calculated based on the amount of BNB or tokens provided as payment and the current market price of the chosen payment type, obtained through a Chainlink AggregatorV3 contract. This calculation then incorporates the contract's token amount per USD value, set by the team. The specified amount of BNB or payment tokens are transferred from the caller to the owner. The caller must grant the contract a sufficient allowance in order for the transaction to successfully occur if the payment is not in BNB.
An initial percentage (set by the team) of the total number of purchased tokens is immediately transferred to the recipient address of the buy order. A new linear vesting schedule is created for the remaining tokens on behalf of the caller's address. An additional percentage of the total amount of purchased tokens is transferred from the contract to the provided referral address if the caller marks the transaction a referral.
LINEAR VESTINGUpon the creation of a vesting schedule via a purchase, the corresponding details of the vesting schedule are stored in the contract on behalf of the caller. Any user that has tokens vested on their behalf can initiate a claim once per 30-day period. The number of tokens transferred from the contract to the user is calculated linearly based on the total number of tokens allocated to their address in relation to their total vest duration. Once the user has claimed all of their tokens, the status of their vesting schedule is marked as inactive.
UPDATING PAYMENT DETAILSThe Admin role can update the payment details for a specified payment type at any time. Each payment type is assigned a name, the linkage to an AggregatorV3 price-fetch contract, the token address, the number of decimals, and its status of either active or inactive.
WITHDRAWING TOKENS/BNBThe Admin role can withdraw any tokens or BNB from the contract at any time. The team must ensure the contract has a sufficient token balance to support purchases and claims for all users.
SIGNER ADDRESS ROLEAny address granted the Signer role can set the contract's Signer address to any address at any time. The original Signer address is revoked from the Signer role and the new Signer address is granted the Signer role in the process.
ADDITIONAL ADMIN ROLE CONTROLSThe Admin role can update the token amount per USD rate to any value at any time. The Admin role can update the referral percentage to any value at any time. The Admin role can update the contract's owner to any address at any time. The caller is revoked from the Admin role and the new owner is granted the Admin role in the process.
Vulnerability Analysis
Vulnerability Category | Notes | Result |
---|---|---|
Arbitrary Jump/Storage Write | N/A | PASS |
Centralization of Control | The Admin role can update the token amount per USD rate to any value at any time. | PASS |
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 | N/A | PASS |
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 | PASS |
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.