WEBTHREE

®

Scope of Work

The scope of this audit is based on the material provided by the client. The goal of this audit is to ensure the following:

  • Find potential exploits for the contract
  • Find issues in the contract that will affect the integrity of the mint
  • Ensure the contract adheres to the business logics provided by the client
The logic of the contract will be compared to the business logic provided in the materials provided below:
  • GBMTokenERC20.sol: Upgradeable ERC20 token with pausable functionality
  • GBMStake.sol: Token staking contract
  • GBMHoard.sol: Merkle tree-based token distribution system
  • GBMSoulboundBadges.sol: Soulbound NFT badges
  • UUPS upgradeability pattern across all contracts
  • Owner-controlled minting and distribution parameters
The contract was provided on 2025-07-17 and audit was delivered on 2025-07-22. It was given in the following formats:

Disclaimer

This is a limited report based on our analysis of the Smart Contract audit and performed in accordance with best practices as of the date of this report, in relation to cybersecurity vulnerabilities and issues in the smart contract source code analyzed, the details of which are set out in this report, (hereinafter “Source Code”) and the Source Code compiling, deploying and performing the intended functions. In order to get a full view of our findings and the scope of our analysis, it is crucial for you to read the full report. While we have done our best in conducting our analysis and producing this report, it is important to note that you should not rely on this report and cannot claim against us on the basis of what it says or doesn’t say, or how we produced it, and it is important for you to conduct your own independent investigations before making any decisions.

By reading this report or any part of it, you agree to the terms of this disclaimer. If you do not agree to the terms, then you must immediately cease reading this report, and delete and destroy any and all copies of this report downloaded and/or printed by you. This report is provided for information purposes only and on a non-reliance basis and does not constitute investment advice. No one shall have any right to rely on the report or its contents and the individuals and/or team providing this report owe no duty of care towards you or any other person, nor does the individuals and/or team make any warranty or representation to any person on the accuracy or completeness of the report. The report is provided “as is” without any conditions, warranties, or other terms of any kind except as set out in this disclaimer and the individuals and/or team hereby exclude all representations, warranties, conditions and other terms (including without limitations, the warranties implied by law of satisfactory quality, fitness for purpose and the use of reasonable care and skill) which, but for this clause might have effect in relation to the report.

Except and only to the extend that it is prohibited by law, the individuals and/or team hereby exclude all liability and responsibility, and neither you nor any other person shall have any claim against the individuals and/or team for any amount of kind of loss or damage that may result to you or any other person including without limitation, any direct, indirect, special, punitive, consequential, or pure economic loss or damages, or any loss of income, profits, goodwill, data, contracts, use of money, or business interruption and whether in delict, tort (including without limitation negligence), contract, breach of statutory duty, misrepresentation (whether innocent or negligent) or otherwise under any claim of any nature whatsoever in any jurisdiction) in any way arising from or connected with this report and the use, inability to use or the results of use of this report and an reliance on this report.

Summary

Audited by:
ZooperDooper
While for the most part the code is well written and follows best practices, there have been some issues that have been identified that will require immediate attention. While some issues can be dismissed, as the context around the issue is important e.g. single point of failure through owner role. A critical issue has been identified, but has been dismissed to medium due to the fact that the contract is upgradeable.
FINDINGS
0 Critical Issues
0 Medium Issues
0 Low Issues
0 Nits
KEY
Critical Issues
Medium Issues
Low Issues
Nits / Informational

Issues

Medium Issue
(Addressed) Summary - Broken Unstaking Mechanism in GBMStake

Due to the use of transferFrom() instead of transfer(), users will not be able to unstake their tokens. This is because by design, transferFrom() is to be used by approved addresses and requires an allowance to be set. As the contract cannot set its own allowance, users will not be able to unstake their tokens. This is a critical issue as it will prevent users from withdrawing their funds. This is however mitigated by the fact that the contract is upgradeable.

IERC20($._ERC20ToStake).transferFrom(address(this), msg.sender, amount_);

Issues

Low Issue
(Addressed) Summary - Potential inflation attack (Acknowledged by GBM Team)

The mintFor() function in GBMTokenERC20 allows the owner to mint unlimited tokens without any supply cap. While GBM has explicitly stated they are taking security concerns around the owner account, it does represent a potential attack vector. Especially if the token will be used for vote weight; from a user perspective it could also be a concern, as the owners of the project could potentially mint tokens to themselves and use them for voting.

function mintFor(address to_, uint256 amount_) public override returns (bool) {
    _mint(to_, amount_);
   }

Issues

Nits
(Addressed) Summary - Lack of Input Validation in Distribution Functions

Functions addDistribution() and editDistribution() don't validate array length mismatches, percentage values exceeding 100%, or timestamp ordering.

require(newCliffsTimestamp_.length == newCliffsPercentage_.length, "Array length mismatch");
require(newCliffsPercentage_[i] <= 100000, "Percentage cannot exceed 100%");

Issues

Nits
(Addressed) Summary - Inconsistent Error Messages

Using both require() and custom error in the same check is inconsistent.

Issues

Nits
(Addressed) Summary - Centralization Risk (Acknowledged by GBM Team)

Single owner has excessive control over critical functions including pausing transfers, minting unlimited tokens, modifying merkle roots, and updating distribution schedules. It poses a risk from a code perspective and depends on the owner to not abuse their power. Measures have been taken by the team to ensure bad actors cannot access the owner account.

Issues

Nits
(Addressed) Summary - Multiple Typos in Contract Code

Several typos found throughout the codebase: 'Souldbond' should be 'Soulbound' in contract name and related variables; 'Percentkage' should be 'Percentage' in variable names, function names, and comments throughout GBMHoard.sol

// Fix contract name
contract GBMSoulboundBadges
// Fix variable names
mapping(uint256 => mapping(uint256 => uint256)) _rootToCliffToPercentageUnlocked;
// Fix function name
function getDistributionCliffPercentage(uint256 rootIndex_, uint256 cliffIndex_)

Issues

Nits
(Addressed) Summary - Gas Optimization Opportunities (acknowledged by GBM Team)

Use ++i instead of i++ in loops, cache storage reads in local variables, consider packing struct fields

// Use ++i instead of i++ in loops
for (uint256 i = 0; i < length; ++i) {
    // loop body
}