Smart Contract Audit

milestoneBased
April 27, 2023

Summary

Vidma team has conducted a smart contract audit for the given codebase.

The contracts are in good condition. Based on the fixes provided by the Ammbr team and on the quality and security of the codebase provided, Vidma team can give a score of 95 to the audited smart contracts.

During the auditing process, the Vidma team has found a couple of informational issues, 7 issues with a low level of severity, 1 issue with a medium level of severity, and 3 issues with a critical level of severity.

Severity of the issue
Total found
Resolved
Unresolved
Critical
3 issues
3 issues
0 issues
High
3 issues
3 issues
0 issues
Medium
3 issues
3 issues
0 issues
Low
3 issues
3 issues
0 issues
Informational
3 issues
3 issues
0 issues
Low
3 issues
3 issues
0 issues

The contracts are in good condition. Based on the fixes provided by the Ammbr team and on the quality and security of the codebase provided, Vidma team can give a score of 95 to the audited smart contracts.

Based on the given findings, risk level, performance, and code style, Vidma team can grant the following overall score:

Please mind that this audit does not certify the definite reliability and security level of the contract. This document describes all vulnerabilities, typos, performance issues, and security issues found by Vidma auditing team. If the code is under development, we recommend run one more audit once the code is finalized.

Summary

Vidma is pleased to present this audit report outlining our assessment of code, smart contracts, and other important audit insights and suggestions for management, developers, and users.

The audited scope of work includes the MilestoneBased contract, which is a factory for creating Roadmap contracts. The main goal of the Roadmap contract is to preserve the investor's investment and distribute it among the startup. In case the startup fails to comply with the agreement or begins to deceive investors, the investors can retrieve their investments through a DAO (Voting contract). Each roadmap has its own Voting contract, which cannot be changed. Anyone can create a proposal that has at least 2 options. Each parameter describes the contracts that need to be called and encodes the function signature with the parameters that will be used for the call. Voting decides which proposal option should be executed based on the votes of the voters. Voters are granted voting rights through the RoadmapStaking contract. They need to stake the selected ERC20 token to get the voting power, which is equivalent to the amount of tokens staked (1:1 ratio). The voting logic is implemented in the VotingPowerCalculator contract, which allows changing it without affecting the voting contract, as all contracts implement the TransparentUpgradeableProxy pattern from the OpenZeppelin library.

During the audit process, the Vidma team found several issues. A detailed summary and the current state are displayed in the table below.

Severity of the issue Issue severity
Critical
High
Medium
Low
Informational
Total
Severity of the issue Issue severity Total found Resolved Invalid Unresolved
Critical 0 issues 0 issues 0 issues 0 issues
High 0 issues 0 issues 0 issues 0 issues
Medium 0 issues 0 issues 0 issues 0 issues
Low 2 issues 1 issue 1 issue 0 issues
Informational 3 issues 3 issues 0 issues 0 issues
Total 5 issues 4 issues 1 issue 0 issues

After evaluating the findings in this report and the final state after fixes, the Vidma auditors can state that the contracts are fully operational and secure. Under the given circumstances, we set the following risk level:

High Confidence

To set the codebase quality mark, our auditors are evaluating the initial commit given for the scope of the audit and the last commit with the fixes. This approach helps us adequately and sequentially evaluate the quality of the code. Code style, optimization of the contracts, the number of issues, and risk level of the issues are all taken into consideration. The Vidma team has developed a transparent evaluation codebase quality system presented below.

Severity of the issue
Issue severity
Total found
Resolved
Critical
1
10
High
0.8
7
Medium
0.5
5
Low
0.2
0.5
Informational
0
0.1
Please note that the points are deducted out of 100 for each and every issue on the list of findings (according to the current status of the issue). Issues marked as “not valid” are not subject to point deduction.
Codebase quality:
99.80

Evaluating the initial commit and the last commit with the fixes, Vidma audit team set the following codebase quality mark.

Score
Based on the overall result of the audit and the state of the final reviewed commit, the Vidma audit team grants the following score:

100

In addition to manual check and static analysis, the auditing team has conducted a number of integrated autotests to ensure the given codebase has an adequate performance and security level. The test results and coverage can be found in the accompanying section of this audit report.

Please be aware that this audit does not certify the definitive reliability and security level of the contract. This document describes all vulnerabilities, typos, performance issues, and security issues found by the Vidma audit team.
If the code is still under development, we highly recommend running one more audit once the code is finalized.

Scope of work

milestoneBased is the first company to leverage a blockchain DAO and escrow smart contract capabilities, in an automated governance and milestone achievement management platform.

Within the scope of this audit, two independent auditors thoroughly investigated the given codebase and analyzed the overall security and performance of the smart contracts.

The audit was conducted from March 15, 2023 to April 14, 2023. The outcome is disclosed in this document.

The final review of the fixes was finished on April 27, 2023.

The scope of work for the given audit consists of the following contracts:

  • EntityAccessControler;
  • MilestoneBased;
  • Refund;
  • Roadmap;
  • RoadmapStaking;
  • TransparentProxyAdmin;
  • Voting;
  • VotingPowerCalculator;
  • SingSignEntityStrategy.

The source code was taken from the following source:

https://bitbucket.org/applicature/milestonebased.contracts

Initial commit submitted for the audit:

4f559c59405f8727b2a6cdc291ad411c259e5bcd

Last commit reviewed by the auditing team:

58763f6bb93b2e78078a8605b1bb8b36ec63d3a4

As a reference to the contracts logic, business concept, and the expected behavior of the codebase, the milestoneBased team has provided the following documentation:

https://applicature.atlassian.net/wiki/spaces/MBCDEV/pages/1702592515/Concept+of+roadmap+architecture

Workflow of the auditing process

Vidma audit team uses the most sophisticated and contemporary methods and well-developed techniques to ensure contracts are free of vulnerabilities and security risks. The overall workflow consists of the following phases:

Phase 1: The research phase

Research

After the Audit kick-off, our security team conducts research on the contract’s logic and expected behavior of the audited contract.

Documentation reading

Vidma auditors do a deep dive into your tech documentation with the aim of discovering all the behavior patterns of your codebase and analyzing the potential audit and testing scenarios.

The outcome

At this point, the Vidma auditors are ready to kick off the process. We set the auditing strategies and methods and are prepared to conduct the first audit part.

Phase 2: Manual part of the audit

Manual check

During the manual phase of the audit, the Vidma team manually looks through the code in order to find any security issues, typos, or discrepancies with the logic of the contract. The initial commit as stated in the agreement is taken into consideration.

Static analysis check

Static analysis tools are used to find any other vulnerabilities in smart contracts that were missed after a manual check.

The outcome

An interim report with the list of issues.

Phase 3: Testing part of the audit

Integration tests

Within the testing part, Vidma auditors run integration tests using the Truffle or Hardhat testing framework. The test coverage and the test results are inserted in the accompanying section of this audit report.

The outcome

Second interim report with the list of new issues found during the testing part of the audit process.

Structure and organization of the findings

For simplicity in reviewing the findings in this report, Vidma auditors classify  the findings in accordance with the severity level of the issues. (from most critical to least critical).

All issues are marked as “Resolved” or “Unresolved”, depending on if they have been fixed by project team or not. The issues with “Not Relevant” status are left on the list of findings but are not eligible for the score points deduction.

The latest commit with the fixes reviewed by the auditors is indicated in the “Scope of Work” section of the report.

The Vidma team always provides a detailed description of the issues and recommendations on how to fix them.

Classification of found issues is graded according to 6 levels of severity described below:

Critical
The issue affects the contract in such a way that funds may be lost or allocated incorrectly, or the issue could result in a significant loss.
Example: Underflow/overflow, precisions, locked funds.
High
The issue significantly affects the ability of the contract to compile or operate. These are potential security or operational issues.
Example: Compilation errors, pausing/unpausing of some functionality, a random value, recursion, the logic that can use all gas from block (too many iterations in the loop), no limitations for locking period, cooldown, arithmetic errors which can cause underflow, etc.
Medium
The issue slightly impacts the contract’s ability to operate by slightly hindering its intended behavior.
Example: Absence of emergency withdrawal of funds, using assert for parameter sanitization.
Low
The issue doesn’t contain operational or security risks, but are more related to optimization of the codebase.
Example: Unused variables, inappropriate function visibility (public instead of external), useless importing of SCs, misuse or disuse of constant and immutable, absent indexing of parameters in events, absent events to track important state changes, absence of getters for important variables, usage of string as a key instead of a hash, etc.
Informational
Are classified as every point that increases onboarding time and code reading, as well as the issues which have no impact on the contract’s ability to operate.
Example: Code style, NatSpec, typos, license, refactoring, naming convention (or unclear naming), layout order, functions order, lack of any type of documentation.

Manual Report

Optimization by ternary operator

Low ML – 01 |  Invalid

There are few functions that can be optimized to return the result of the ternary operator that will decrease using of if-else branching:

Roadmap.sol

  function checkIsMilestoneWithdrawable(uint256 _id) public view returns (bool) {
    Milestone storage milestone = milestones[_id];

    if (milestone.withdrawalStrategy == FundsReleaseType.MilestoneStartDate) {
      return milestone.startDate <= block.timestamp;
    } else if (milestone.withdrawalStrategy == FundsReleaseType.MilestoneEndDate) {
      return milestone.endDate <= block.timestamp;
    }

    return false;
  }

could be optimized to:

  function checkIsMilestoneWithdrawable(uint256 _id) public view returns (bool) {
    Milestone storage milestone = milestones[_id];
    return
      milestone.withdrawalStrategy == FundsReleaseType.MilestoneStartDate
        ? milestone.startDate <= block.timestamp
        : milestone.withdrawalStrategy == FundsReleaseType.MilestoneEndDate
        ? milestone.endDate <= block.timestamp
        : false;
  }

Voting.sol

 function _getSelectedOption(
    Proposal storage proposal,
    address voter
  ) internal view returns (bool exists, uint256 optionId) {
    uint256 stored = proposal.selectedOptions[voter];
    if (stored > 0) {
      return (true, stored - 1);
    } else {
      return (false, 0);
    }
  }

could be optimized to:

  function _getSelectedOption(
    Proposal storage proposal,
    address voter
  ) internal view returns (bool exists, uint256 optionId) {
    uint256 stored = proposal.selectedOptions[voter];

    return stored > 0 ? (true, stored - 1) : (false, 0);
  }

Recommendation:

Consider using ternary operators. It can decrease contract size (Roadmap: -0.004KiB, Voting: -0.006KiB).

Simplification of boolean value getters

Low ML – 02 |  Resolved

There are a few functions that could be simplified to get boolean values directly without if-else branching:

EntityAccessControler.sol

function _isEntity(address _entity) internal view returns (bool) {
    if (IEntityFactory(_getEntityFactoryContract()).entityRegister(_entity) == IEntityFactory.EntityType.None) {
      return false;
    }
    return true;
  }

could be optimized to:

function _isEntity(address _entity) internal view returns (bool) {
    return IEntityFactory(_getEntityFactoryContract()).entityRegister(_entity)  != IEntityFactory.EntityType.None;
  }

Refund.sol

 function _isRefunded() internal view returns (bool) {
    if (investmetnsRemainder > 0) {
      return true;
    } else {
      return false;
    }
  }

could be optimized to:

function _isRefunded() internal view returns (bool) {
    return investmetnsRemainder > 0;
  }

Recommendation:

Consider removing if-else branching to get similar values. It also decreases contract size (Refund: -0.039KiB, EntityAccessControler: -0.013KiB for every dependent contract: Refund, Roadmap, RoadmapStaking, Voting).

Missed NatSpec docs

Informational  MI – 01 |  Resolved

There are instances that need to be covered by Natspec:

  • EntityAccessControler.sol (L11): Smart Contract description;
  • Voting.sol (L345): getActiveVotedProposalsByVoter() function description;
  • TransparentProxyAdmin.sol (L6): Smart Contract description.

Recommendation:

Add NatSpec to contracts and their functions using Solidity documentation for NatSpec.

Typos in the codebase

Informational  MI – 02 |  Resolved

There are some typos in the contract's code and NatSpec that should be fixed:

  • EntityAccessControler.sol (L12): EntityAccessControler -> EntityAccessController and the filename;
  • EntityAccessControler.sol (L19): EnitityFactory -> EntityFactory;
  • EntityAccessControler.sol (L30): Enitity -> Entity;
  • EntityAccessControler.sol (L39): __EntityAccessControler_init -> __EntityAccessController_init;
  • EntityAccessControler.sol (L75-76): EntityFactroy -> EntityFactory;
  • IMilestoneBased.sol (L40): evoiding -> avoiding;
  • IMilestoneBased.sol (L109): cotnracts -> contracts;
  • MilestoneBased.sol (L161): cotnracts -> contracts;
  • IRefund.sol (L21): seetings -> settings;
  • IRefund.sol (L24): _fudningToken -> _fundingToken;
  • IRefund.sol (L27): _mBaddres -> _mBAddress;
  • IRefund.sol (L33): Trnafer -> Transfer;
  • IRefund.sol (L38,41): Tranfer -> Transfer;
  • IRefund.sol (L41): contrcat -> contract;
  • Refund.sol (L74,80): _mBaddres -> _mBAddress;
  • Refund.sol (L116,121): investmens -> investments;
  • Refund.sol (L132): enitity -> entity;
  • Roadmap.sol (L123): owenr -> owner;
  • Roadmap.sol (L123): prrove -> approve;
  • IRoadmapStaking.sol (L26): cotnract -> contract;
  • IRoadmapStaking.sol (L34): emtity -> entity;
  • RoadmapStaking.sol (L126): NotEnoughBalnce -> NotEnoughBalance;
  • IVotingPowerSupplier.sol (L11,12): votign -> voting;
  • IVoting.sol (L26): alredy -> already;
  • IVoting.sol (L99,100,101,102): cancelled -> canceled;
  • IVoting.sol (L103): ProposalVoteCancelled -> ProposalVoteCanceled;
  • IVoting.sol (L157): exeecution -> execution;
  • IVoting.sol (L204): choosed -> chosen;
  • IVoting.sol (L490): ProposalVoteCancelled -> ProposalVoteCanceled.

Recommendation:

Consider fixing typos. Also don't forget to change dependencies in other contracts for imports/function calls.

Event arguments code style

Informational  MI – 03 |  Resolved

Event arguments do not require underscores in their names like function arguments. It is often used to avoid naming collisions in functions.

Recommendation:

Consider removing underscore for event arguments:

  • IRoadmap.sol (L120,126): _ipfsHash -> ipfsHash.

Test Results

To verify the security of  contracts and the performance, a number of integration tests were carried out using the Hardhat testing framework.

In this section, we provide both tests written by milestoneBased and tests written by Vidma auditors.

milestoneBased Coverage – 93.55%

Vidma Coverage – 98.69%

Industry Standard – 95%

It is important to note that Vidma auditors do not modify, edit or add tests to the existing tests provided in the milestoneBased repository. We write totally separate tests with code coverage of a minimum of 95% to meet the industry standards.

Tests written by Xend and Wicrypt

Test Coverage

File
contracts\
MilestoneBased.sol 
contracts\entities\utils\
EntityAccessControler.sol
contracts\roadmaps\
Refund.sol
Roadmap.sol
RoadmapStaking.sol
TransparentProxyAdmin.sol
Voting.sol
VotingPowerCalculator.sol
All Files
File % Stmts % Branch % Funcs % Lines
contracts\ 100.00 91.18 100.00 98.11
MilestoneBased.sol  100.00 91.18 100.00 98.11
contracts\entities\utils\ 100.00 90.00 100.00 100.00
EntityAccessControler.sol 100.00 90.00 100.00 100.00
contracts\roadmaps\ 92.50 87.50 90.48 93.53
Refund.sol 95.83 95.83 93.33 97.67
Roadmap.sol 96.67 94.55 95.24 98.23
RoadmapStaking.sol 95.24 84.62 90.91 96.67
TransparentProxyAdmin.sol 50.00 45.45 50.00 50.00
Voting.sol 94.87 88.68 93.33 94.21
VotingPowerCalculator.sol 75.00 50.00 66.67 83.33
All Files 93.55 87.91 91.92 94.27

Test Results

Contract: Create2Factory

  • computeAddress
    • should return the address of the future contract correctly(167ms)
  • deploy
    • should deploy contract via create2 opcode correctly(142ms)
    • should catch event
  • setContractOwner
    • should transfer ownership correctly(204ms)
    • should revert if created contract doesn't inherited Ownable contract(194ms)
    • should revert if the contract isn't owner of passed contract(201ms)

Contract: SMilestoneBasedToken

  • constructor
    • should grant roles to deployer correctly
  • DEFAULT_ADMIN_ROLE
    • should grant DEFAULT_ADMIN_ROLE correctly(81ms)
  • mint
    • should revert if caller does not have permission to mint(71ms)
    • should mint tokens correctly(65ms)
  • transfer
    • should revert if transfer from and to invalid address(171ms)
    • should transfer tokens correctly(126ms)
  • updating Registry
    • should revert if sender isn't owner(63ms)
    • should update strategy of sMILE in registry correctly(106ms)
    • should update whiteList in registry correctly(175ms)
  • setRegistry
    • should revert if new address is zero address(49ms)
    • should update registry correctly(61ms)
    • should catch event

Contract: MilestoneBasedVesting

  • Constructor
    • Must fail if passed zero address of token(79ms)
    • Must set up correctly(97ms)
  • addTokensForVesting
    • Must fail if sender isn't owner(53ms)
    • Must fail if passed amount equal to zero(53ms)
    • Must fail if sender hasn't approved tokens for vesting contract(79ms)
    • Must add tokens for vesting to vesting contract(151ms)
  • createVesting
    • Must fail if sender isn't owner(54ms)
    • Must fail if passed zero address of beneficiary(54ms)
    • Must fail if amount of vesting equal to 0(51ms)
    • Must fail if passed incorrect vesting period(58ms)
    • Must fail if passed incorrect vesting period(48ms)
    • Must fail if amount of vesting bigger then allocation(65ms)
    • Must create vesting correctly(81ms)
  • createVestingBatch
    • Must fail if sender isn't owner(56ms)
    • Must fail if passed arrays have different length(52ms)
    • Must create vesting multiple times for different users(103ms)
    • Must create vestings with different type for one user(101ms)
  • emergencyWithdraw
    • Must fail if sender isn't owner(61ms)
    • Must withdraw correct amount of tokens from vesting contract(164ms)
    • Must fail if there is no available tokens to withdraw(45ms)
  • testing vesting types calculation and withdraw
    • Withdraw function must fail if user doesn't have vestings
    • All vesting must return 0 if vestings haven't started yet(128ms)
    • Vesting type "Marketing" must give small part of vested tokens after creation of vesting(102ms)
    • Vestings with types "Founder" and "Rewards" must return 0 while lock period(47ms)
    • Vesting with type "Rewards" must return part of tokens after lock period(38ms)
    • Must return correct amount of withdrawable tokens for user with multiple vestings after withdraw(216ms)
    • Vesting type "Founder" must return correct amount of tokens(490ms)
    • Vestings must return all vested tokens after vesting's end(495ms)
  • revokeVestingOfUser
    • Must fail if user's vesting is irrevocable(233ms)
    • Must revoke vesting correctly(81ms)
    • Must fail if vesting has been already revoked(46ms)
    • Must revoke correct amount of user's tokens if user has claimed tokens(136ms)
  • burn
    • Must fail if sender doesn't have enougth tokens to burn(121ms)
    • Must burn tokens correctly(79ms)
  • burnFrom
    • Must fail if sender doesn't have enougth allowance(85ms)
    • Must fail if owner doesn't have enougth tokens(65ms)
    • Must burn tokens from another user correctly(58ms)

Contract: WhiteList

  • constructor
    • should grant roles to deployer correctly
  • addNewAddress
    • should revert if caller is not owner or MB contract(51ms)
    • should add new address to white list correctly(62ms)
    • should catch event
  • addNewAddressesBatch
    • should add new addresses to white list correctly(88ms)
    • should catch event
  • removeAddress
    • should revert if caller is not owner or MB contract(45ms)
    • should remove address from white list correctly(74ms)
    • should catch event
  • removeAddressesBatch
    • should remove addresses from white list correctly(66ms)
    • should catch event
  • getAllAddresses
    • should return empty array
    • should return all addresses correctly(93ms)
    • should return first part of all addresses correctly
    • should return one address with offset(length - 1)
    • should return empty array if offset is greater or equal array length(38ms)
    • should return empty array if limit is 0
  • isValidAddress
    • should return true if contract has such address, and false if doesn’t(60ms)

Contract: ContractRegistry

  • initialize
    • should correct set owner after initialize
    • should revert if try initialize second time
  • registerContract
    • should revert if
      • call from not Owner(40ms)
      • try register zero address
    • should success
      • register first key and emit event
        • check corect registration(39ms)
        • check emit event
      • register second key and emit event
        • check corect registration
        • check emit event
        • check first key not rewrite
      • update contract address after call second time with registered key
        • check corect registration
        • check emit event
  • unregisterContract
    • should revert if
      • call from not Owner
      • try call unregister for not registtered key
    • should success
      • unregister first key and emit event
        • check corect unregistration
        • check emit event
        • check second key not unregister
      • unregister second key and emit event
        • check corect unregistration
        • check emit event
  • registerContracts
    • should revert if
      • call from not Owner
      • try register zero address(38ms)
      • send array with different length
    • should success
      • register all keys and emit event
        • check emit event
        • should correct
          • check registration of key: 0(41ms)
          • check registration of key: 1
          • check registration of key: 2
  • isRegistered
    • Should return TRUE if key registered
    • Should return FALSE if key not registered
  • register
    • Should return correct address by key
    • Should return zero address if key not registered
  • getContractByKey
    • Should return correct address by key
    • Should revert if key not registered
  • getContractsByKeys
    • Should return correct addresses by keys
    • Should return zero array if send empty keys array
    • Should revert if one from keys not registered(56ms)

Contract: BaseEntity

  • initialize
    • should correct set owner after initialize
    • should correct set contractRegistry address after initialize
    • should revert if try initialize second time(43ms)
    • should revert if call from not initialize function(87ms)
    • should revert if try provide invalid owner address(126ms)
    • should revert if try provide invalid factory address(98ms)
  • functions
    • withdrawFromEntity
      • should fail
        • if caller not owner
        • if not enought erc20 tokens on contract(49ms)
        • if not enought native coins on contract
      • should success
        • transfer (100% - 1 token) erc20 from contract to recipient and emit event
          • correct change balances
          • correct emit event
        • transfer all erc20 from contract to recipient and emit event
          • correct change balances
          • correct emit event
        • transfer (100% - 0.1 ether) coin from contract to recipient and emit event
          • correct change balances
          • correct emit event
        • transfer all native coins from contract to recipient and emit event
          • correct change balances
          • correct emit event
    • approve
      • should fail
        • if caller not owner
        • if inner approve return false(57ms)
      • should success approve tokens and emit event
        • correct change allowance
        • correct emit event
      • should success approve tokens to less amount and emit event
        • correct change allowance
        • correct emit event
    • increaseAllowance
      • should fail
        • if caller not owner
        • if caller pass zero address as spender
        • if caller pass zero amount
      • should success increaseAllowance tokens and emit event
        • correct change allowance
        • correct emit event
    • decreaseAllowance
      • should fail
        • if caller not owner
        • if caller pass zero address as spender
        • if caller pass zero amount
        • if caller try to decrease more than approved
      • should success decreaseAllowance tokens and emit event
        • correct change allowance
        • correct emit event
      • _getEntityFactory
        • Should corectly return actual entityFactory from registry

Contract: CompanyEntity

  • initialize
    • should correct set owner after initialize(46ms)
    • should correct set contractsRegistry address after initialize
    • should revert if try initialize second time(40ms)
    • should revert if try provide not UserEntity address as owner(111ms)

Contract: ExpandedEntity

  • initialize
    • should correct set owner after initialize(56ms)
    • should correct set contractRegistry address after initialize
    • should revert if try initialize second time(43ms)
    • should revert if call from not initialize function(106ms)
    • should revert if try provide not UserEntity address as owner(107ms)
  • functions
    • isOwner
      • should success
        • return TRUE if user is owner of userEntity(69ms)
        • return TRUE if userEntity is owner of ExpandedEntity
        • return FALSE if user not owner
        • return FALSE if provided another userEntity which not owner
    • swapOwner
      • should fail if
        • caller not one from owners(41ms)
        • new owner is not UserEntity address(56ms)
      • should success
        • corectly change old userEntity owner to new userEntity and emits event
          • should correct emits events
          • should correct return new owner
          • should correct remove owner status from old owner(52ms)
          • should correct set owner status for new owner(41ms)

Contract: OwnerManager

  • initialize
    • should correct set owner after initialize
    • should correct emit event
    • should revert if try initialize second time(41ms)
    • should revert if call from not initialize function(86ms)
    • should revert if try provide invalid address as owner(132ms)
  • functions
    • getOwners
      • should success
        • return array with actual owner
        • return array if owners is more then one(81ms)
    • isOwner
      • should success
        • return TRUE if user is owner(69ms)
        • return FALSE if user not owner
        • return FALSE if provided address is _SENTINEL_OWNERS
    • swapOwner
      • should fail if
        • caller not one from owners
        • new owner is active owner in contract(40ms)
        • old owner is invalid address(71ms)
        • new owner is invalid address(83ms)
        • previus owner is not previous for old owner
      • should success
        • corectly change old owner to new and emits event
          • should correct emits events
          • should correct return new owner
          • should correct remove owner status from old owner
          • should correct set owner status for new owner
          • old owner shouldn't have rights to call swapOwner again(41ms)
          • getFirstOwner should return new owner
        • corectly change with a lot of owners
          • corectly change with a lot of owners(161ms)

Contract: ProjectEntity

  • initialize
    • should correct set owner after initialize(50ms)
    • should correct set contractsRegistry address after initialize
    • should revert if try initialize second time(40ms)
    • should revert if try provide not UserEntity address as owner(101ms)

Contract: ProjectEntity

  • initialize
    • should correct set owner after initialize
    • should correct set contractsRegistry address after initialize
    • should revert if try initialize second time
  • swapOwner
    • should fail if
      • caller not one from owners
    • should success
      • corectly change old userEntity owner to new userEntity and emits event
        • IMPORTANT: should correct change owner in EntityFactory
        • should correct emits events
        • should correct return new owner
        • should correct remove owner status from old owner
        • should correct set owner status for new owner

Contract: EntityFactory

  • initialize
    • should correct set owner after initialize
    • should correct set contractregistry address after initialize
    • should correct set upgradeableBeacon addresses by EntityTypes(53ms)
    • should revert if try initialize second time(38ms)
    • should revert if provide zero address to any parameters(165ms)
  • updateUpgradeableBeacon
    • should fail
      • if caller is not owner
      • if provide zero address
      • if provide incorrect entity type
    • should success update beacon and emit event
      • UserEntity(43ms)
      • ProjectEntity(48ms)
      • CompanyEntity(49ms)
  • createEntity
    • should fail
      • if provide incorrect entityType
      • if provide incorrect signature(126ms)
    • create UserEntity
      • should fail
        • if user have exists userEntity(248ms)
      • should success create userEntity and emit event
        • correct emit event
        • correct add entity address to whitelist
        • correct register entity with correct type
        • correct set initial owner
        • should success create userEntity for another user and emit event
          • correct emit event
          • correct add entity address to whitelist
          • correct register entity with correct type
          • correct set initial owner
          • Check user entity on correct deploy
            • should correct setup owner
            • should correct setup contractsRegistry
            • should correct setup beacon of Proxy
      • create CompanyEntity
        • should fail
          • if user haven't exists userEntity(94ms)
        • should success create CompanyEntity and emit event
          • correct emit event
          • correct add entity address to whitelist
          • correct register entity with correct type
          • correct set initial owner as UserEntity from owner
          • Check user entity on correct deploy
            • should correct setup owner(42ms)
            • should correct setup contractsRegistry
            • should correct setup beacon of Proxy
          • should success create second CompanyEntity for one user
            • check thats it's full new entity
        • should success create CompanyEntity for another user
          • correct emit event
          • correct add entity address to whitelist
          • correct register entity with correct type
          • correct set initial owner as UserEntity from owner
          • Check user entity on correct deploy
            • should correct setup owner
            • should correct setup contractsRegistry
            • should correct setup beacon of Proxy
          • should success create second CompanyEntity for one user
            • check thats it's full new entity
      • create ProjectEntity
        • should fail
          • if user haven't exists userEntity(93ms)
        • should success create ProjectEntity and emit event
          • correct emit event
          • correct add entity address to whitelist
          • correct register entity with correct type
          • correct set initial owner as UserEntity from owner
          • Check user entity on correct deploy
            • should correct setup owner
            • should correct setup contractsRegistry
            • should correct setup beacon of Proxy
          • should success create second ProjectEntity for one user
            • check thats it's full new entity
        • should success create ProjectEntity for another user
          • correct emit event
          • correct add entity address to whitelist
          • correct register entity with correct type
          • correct set initial owner as UserEntity from owner
          • Check user entity on correct deploy
            • should correct setup owner(44ms)
            • should correct setup contractsRegistry
            • should correct setup beacon of Proxy
          • should success create second ProjectEntity for one user
            • check thats it's full new entity
  • isOwnerOfUserEntity
    • should return FALSE if user not have userEntity
    • should return TRUE if user have userEntity
  • addOwnerToUserEntity
    • should fail
      • if caller is not registered userEntity
      • if entity already exists for new owner(64ms)
    • should success add new owner for userEntity and emit event
      • should correct check userEntity by new owner(47ms)
      • corect emit event
  • removeOwnerFromUserEntity
    • should fail
      • if caller is not registered userEntity(38ms)
    • should success remove owner from userEntity and emit event
      • should correct check userEntity by old owner
      • corect emit event

Contract: MilestoneBased

  • initialize
    • Must revert if the contract already initialized
    • Must revert if proxy admin addresses equals to zero address
    • Must revert if proxy admin addresses equals to zero address
    • Must revert if mBWallet addresses equals to zero address
    • Must revert if Roadmap implementation addresses equals to zero address
    • Must revert if Voting implementation addresses equals to zero address
    • Must revert if RoadmapStaking implementation addresses equals to zero
  • address
    • Must revert if Refund implementation addresses equals to zero address
    • Must revert if Voting implementation addresses equals to to zero address
  • createRoadmap
    • Must revert if passed address isn't ProjectEntity contract(54ms)
    • Must revert if sender isn't owner of passed projectEntity(57ms)
    • Must revert if funding token address equals to zero address(215ms)
    • Must revert if governance token address equals to zero address(151ms)
    • Must revert if fundsReleaseType is unvalid(169ms)
    • Must revert if voting duration equals to zero(227ms)
    • Must revert if minConsensusVotingPower equals to zero(208ms)
    • Must deploy Roadmap SCs correctly(482ms)
    • Must emit event correctly
  • setContractRegistry
    • Must revert if sender isn't owner(42ms)
    • Must revert if passed address equals to zero address
    • Must update address of ContractRegistry correctly(68ms)
  • updateImplementation
    • Must revert if sender isn't owner
    • Must revert if passed address equals to zero address
    • Must change implementation correctly(55ms)

Contract: Refund

  • initialize
    • Must revert if user passes zero address of contractRegistry address
    • Must revert if user passes zero address of governance token address
    • Must revert if user passes zero address of a roadmap contract
    • Must revert if user passes zero address of milestoneBased address
    • Must revert if the refund contract is already initialized
  • adding investments
    • Must revert if sender isn't a roadmap contract
    • Must revert if roadmap is already refunded(185ms)
    • Must add investments correctly(81ms)
  • refund
    • Must revert if sender isn't a roadmap contract
    • Must revert if remainder of investments are less than(43ms)
    • Must revert if tokens are not approved by roadmap contract(57ms)
    • Must refund correctly if the Refund contract is a keeper(101ms)
    • Must refund correctly if the Refund contract isn't a keeper(115ms)
    • Must revert if roadmap is already refunded(61ms)
  • claimInvestments
    • Must revert if roadmap isn't refunded yet(45ms)
    • Must revert if roadmap isn't a keeper(49ms)
    • Must revert if sender isn't investor
    • Must revert if passed entity isn't investor(54ms)
    • Must revert if passed address is zero address
    • Must revert if passed address isn't a entity contract
    • Must revert if sender isn't owner of entity(59ms)
    • Must claim rewards correctly(86ms)
    • Must claim rewards correctly using entity address(101ms)
  • getClaimableRefund
    • Must revert if roadmap isn't refunded
    • Must return 0 if passed address isn't investor
    • Must return correct amount of claimable tokens(59ms)

Contract: Refund

  • initialize
    • Must revert if user passes zero address as voting contract
    • Must revert if user passes zero address as Refund contract
    • Must revert if user passes zero address as ContractRegistry contract
    • Must revert if user passes zero address as ProjectEntity contract
    • Must revert if user passes zero address as funding token contract
    • Must revert if user passes wrong FundsReleaseType
    • Must revert if a Roadmap is already initialized
  • setFundsReleaseType
    • Must revert if sender isn't a Voting contract
    • Must revert if a Roadmap contract is already refunded(111ms)
    • Must set Roadmap State correctly(40ms)
  • fundRoadmap
    • Must revert if sender hasn't approved tokens(47ms)
    • Must revert if sender doesn't have enough tokens(74ms)
    • Must revert if a Roadmap is already refunded(113ms)
    • Must fund roadmap correctly(109ms)
  • fundRoadmap using Entity contract
    • Must revert if passed address is not entity contract(41ms)
    • Must revert if sender isn't entity owner(44ms)
    • Must revert if entity hasn't approved tokens(61ms)
    • Must revert if entity doesn't have enough tokens(105ms)
    • Must revert if a Roadmap is already refunded(206ms)
    • Must fund roadmap correctly(146ms)
  • addMilestone
    • Must revert if sender isn't voting contract(42ms)
    • Must revert if roadmap is already refunded(119ms)
    • Must revert if a milestone with passed id exists(162ms)
    • Must revert if passed invalid start date
    • Must revert if passed dates are not valid
    • Must revert if Roadmap contract doesn't have enough funds
    • Must add milestone correctly(128ms)
  • updateMilestone
    • Must revert if sender isn't voting contract(41ms)
    • Must revert if roadmap has alredy reverted(113ms)
    • Must revert if milestone doesn't exists
    • Must revert if roadmap hasn't enough funds(43ms)
    • Must revert if new dates are not correct(49ms)
    • Must update not started milestone correctly(163ms)
    • Must revert if milestone has started and StartDate is different than old one(47ms)
    • Must revert if end date timestamp is less than current timestamp
    • Must revert if end date timestamp is equal than current timestamp(47ms)
    • Must revert if new amount is less than withdrawed amount(104ms)
    • Must update started milestone correctly(161ms)
  • withdraw
    • Must revert if sender isn't owner of parent entity or voting contract(50ms)
    • Must revert if roadmap is refunded(140ms)
    • Must revert if milestone doesn't exist(89ms)
    • Must revert if milestone has status 'Suspended'(105ms)
    • Must revert if milestone isn't withdrawable(99ms)
    • Must revert if milestone doesn't have enough funds(59ms)
    • Must withdraw correctly using voting address(93ms)
    • Must withdraw correctly using owner of parent entity address(87ms)
  • removeMilestone
    • Must revert if roadmap is refunded(125ms)
    • Must revert if milestone doesn't exist
    • Must revert if milestone has started(43ms)
    • Must remove milestone correctly(84ms)
  • updateMilestoneVotingStatus
    • Must revert if sender isn't voter(40ms)
    • Must revert if roadmap is refunded(162ms)
    • Must revert if milestone doesn't exist(40ms)
    • Must revert if milestone hasn't started(44ms)
    • Must revert if new voting status is invalid(55ms)
    • Must update milestone voting status from Active to Suspended(70ms)
    • Must update milestone voting status from Active to Finished(69ms)
  • updateRoadmapState
    • Must revert if sender isn't a voter(185ms)
    • Must revert if roadmap is refunded(193ms)
    • Must update roadmap state correctly(112ms)
  • checkIsMilestoneWithdrawable
    • Must return false before start of milestone with funding strategy 'MilestoneStartDate'
    • Must return true after start of milestone with funding strategy 'MilestoneStartDate'
    • Must return false after start of milestone with funding strategy 'MilestoneEndDate'
    • Must return true after end of milestone with funding strategy 'MilestoneEndDate'

Contract: RoadmapStaking

  • initialize
    • must revert if the contract is already initialized
    • must revert if user passes zero address as _contractRegistry(74ms)
    • must revert if user passes zero address as _governanceToken(76ms)
    • must revert if user passes zero address as _voting(76ms)
    • must initialize correctly(110ms)
  • stake from sender
    • must revert if governane tokens are not approved by sender(40ms)
    • must revert if user tries to stake 0 tokens
    • must stake correctly(86ms)
  • stake from sender to another address
    • must revert if governane tokens are not approved by sender
    • must revert if user tries to stake 0 tokens
    • must revert if user tries to stake to zero address
    • must stake correctly(94ms)
  • stake from entity
    • must revert if governane tokens are not approved by entity(62ms)
    • must revert if user tries to stake 0 tokens(41ms)
    • must revert if user pass zero address as entity address
    • must revert if user pass not entity address
    • must revert if sender isn't owner of passed entity contract(44ms)
    • must revert if entity doesn't have enough balance(98ms)
    • must stake correctly from entity(125ms)
  • unstake
    • must revert if sender try to unstake 0
    • must revert if sender try to unstake more tokens than staked amount
    • must unstake all tokens correctly(87ms)
    • must unstake part of tokens correctly(91ms)
  • unstake using entity
    • must revert if sender try to unstake 0
    • must revert if sender try to unstake more tokens than staked amount(40ms)
    • must revert if passed address isn't entity contract
    • must revert if sender isn't owner of passed entity(47ms)
    • must unstake part of tokens correctly(92ms)
    • must unstake all tokens correctly(94ms)
  • getting voting power
    • must return correct voting power after staking(272ms)
    • must return correct voting power after unstake

Contract: TransparentProxyAdmin

  • upgradeBatch
    • must revert if sender isn't owner(41ms)
    • must revert if implementation equla to zero address(48ms)
    • must upgrade correctly(145ms)
  • upgradeBatch with multiple implementations
    • must revert if sender isn't owner(39ms)
    • must revert if arrays have different length
    • must revert if implementation equla to zero address
    • must upgrade correctly(139ms)

Contract: Voting

  • initialize
    • Must revert if Voting contract is already initialized
    • Must revert if contract registry equals to zero address(41ms)
    • Must revert if roadmap or votingPowerCalculator address equals to zero address(57ms)
    • Must revert if voting duration or min consensus voting power equals to zero(55ms)
    • Must initialize voting contract correctly(60ms)
  • setTimeLockBeforeVoting
    • Must revert if sender isn't a voting contract
    • Must set time lock before voting correctly(217ms)
  • setVotingDuration
    • Must revert if sender isn't a voting contract
    • Must revert if user try to set zero value(276ms)
    • Must set new for voting correctly(205ms)
  • setTimeLockBeforeExecution
    • Must revert if sender isn't a voting contract
    • Must set new for voting correctly(199ms)
  • setMinConsensusVotersCount
    • Must revert if sender isn't a voting contract
    • Must set new for voting correctly(217ms)
  • setMinConsensusVotingPower
    • Must revert if sender isn't a voting contract
    • Must revert if user try to set zero value(187ms)
    • Must set new for voting correctly(197ms)
  • addProposal
    • Must revert if passed arrays have different length
    • Must revert if passed proposal has zero options
    • Must revert if arrays for option has different length(63ms)
    • Must add proposal correctly(103ms)
  • vote
    • Must revert if proposal doesn't exist
    • Must revert if proposal isn't in voting period(42ms)
    • Must revert if option doesn't exist(54ms)
    • Must revert if option has already voted(155ms)
    • Must vote for a proposal correctly(93ms)
    • Must revote correctly(187ms)
  • vote using entity contract
    • Must revert if passed address isn't entity contract
    • Must revert if sender isn't owner of passed entity(58ms)
    • Must revert if proposal doesn't exist(43ms)
    • Must revert if proposal isn't in voting period(64ms)
    • Must revert if option doesn't exist(58ms)
    • Must revert if option has already voted(163ms)
    • Must vote for a proposal correctly(115ms)
    • Must revote correctly(216ms)
  • cancel vote
    • Must revert if proposal doesn't exist
    • Must revert if proposal has s period than Voting(44ms)
    • Must revert if voter hasn't voted in passed proposal(46ms)
    • Must cancel vote correctly(106ms)
  • cancel vote using entity
    • Must revert if passed address isn't address of entity
    • Must revert if sender isn't owner of passed entity(52ms)
    • Must revert if proposal doesn't exist(50ms)
    • Must revert if proposal has s period than Voting(60ms)
    • Must revert if voter hasn't voted in passed proposal(62ms)
    • Must cancel vote correctly(135ms)
  • update voting power
    • Must update voting power for all proposals correctly(303ms)
    • Must update voting power and delete proposal after voting period(293ms)
  • execution
    • Must revert if roadmap is attacked by reentrant attack(74ms)
    • Must revert if call the function not in Execution period
    • Must revert if proposal doesn't have option with max voting power(118ms)
    • Must revert if passed wrong option to execute(50ms)
    • Must revert if not enough voting power(62ms)
    • Must revert if execution is failed(144ms)

Contract: VotingPowerCalculator

  • initialize
    • should revert if the contract is already initialized
    • should revert if zero address passed as staking address(70ms)
  • getting voting power
    • must return zero voting power
    • must return correct voting power after staking(53ms)
    • must return correct voting power after staking(52ms)

Contract: SingleSignEntityStrategy

  • initialize
    • should correct set owner after initialize
    • should correct set contractsRegistry contract
    • should correct set trustedSigner
    • should revert if try deploy with zero trusted signer addres
    • should revert if try deploy with zero entity factory addres
  • functions
    • setTrustedSigner
      • should revert if caller is not owner
      • should revert if trusted signer try set zero address
      • should set trusted signer correctly and emit event(73ms)
    • isValid
      • should return FALSE if nonce is used(84ms)
      • should return FALSE if signature expired
      • should return FALSE if signer is not equal trusted signer
      • should return TRUE if signer is actual trusted signer(48ms)
      • should return FALSE if any from param was changed
        • if changed deadline(39ms)
        • if changed signer(50ms)
        • if changed id(42ms)
        • if changed nonce(49ms)
        • if changed entityFactory
        • if changed entity owner
        • if changed entityType
        • if changed v
        • if changed r
        • if changed s
    • useSignature
      • should revert
        • should revert if caller is not entityFactory(44ms)
        • should revert if signature is invalid(49ms)
      • should correctly use signature
        • should corecrty use signature and set used nonce(109ms)
        • Should corectly set nonce is used for user
        • should revert if used nonce which was use before(45ms)

Contract: SwapMile

  • initialize
    • should revert when one of required addresses is zero(152ms)
    • should revert when cooldownPeriod or withdrawPeriod equal to 0(128ms)
    • should revert when cooldownPeriod is greater than withdrawPeriod or equal(125ms)
    • should revert if the contract already initialized
  • staking
    • Should revert if passed entity isn't entity(228ms)
    • Should revert if sender isn't address of passed entity(184ms)
    • Should revert if amount of token to stake equal to Zero(279ms)
    • should revert to stake if user haven't approved enough tokens to stake(244ms)
    • should revert to stake if user doesn't have enough tokens to stake(294ms)
    • should stake from sender wallet(705ms)
    • should stake from userEntity(709ms)
    • should stake from passed entity(674ms)
  • requestWithdraw
    • Should revert if passed address isn't entity(48ms)
    • Should revert if sender isn't Owner of passed entity(53ms)
    • Should revert if passed zero amount of tokens(56ms)
    • Should revert if entiti's balance of sMILE tokens less than required amount to withdraw(50ms)
    • Should create request withdraw correctly(116ms)
  • cancel withdraw
    • Should revert if passed address isn't entity(40ms)
    • Should revert if sender isn't owner of passed entity(46ms)
    • Should revert if passed withdrawal Id is incorrect(40ms)
    • should cancel correctly(140ms)
  • withdraw
    • Should revert if passed address isn't entity(49ms)
    • Should revert if sender isn't owner of passed entity(51ms)
    • Should revert if request does not exist(47ms)
    • Should revert if passed request was created by not passed entity(51ms)
    • Should revert if entity doesn't have enough sMILE tokens(158ms)
    • should cancel withdraw request after withdraw period(133ms)
    • should withdraw correctly after cooldown period(178ms)
  • fee calculation check
    • should get fee after immidiatly withdraw(130ms)
    • should get fee after 1/5 cooldown period(147ms)
    • should get fee after 1/2 cooldown period(145ms)
    • should get fee after 3/5 cooldown period(158ms)
    • should get fee after cooldown period(142ms)
  • set cooldown and withdraw period
    • should revert if sender isn't admin(130ms)
    • should revert if new value is zero(147ms)
    • should revert to set cooldownPeriod if it greater or equal to withdrawPeriod(125ms)
    • should revert to set withdrawPeriod if it smaller or equal to cooldownPeriod(51ms)
    • should update cooldownPeriod correctly
    • should update withdrawPeriod correctly
  • addRewards
    • should revert if passed zero amount of tokens
    • should revert if sender doesn't have enogth MILE tokens(56ms)
    • should revert if sender doesn't have enogth MILE tokens(82ms)
    • should add rewards correctly(114ms)
  • withdrawUnusedFunds
    • should revert if sender isn't admin(122ms)
    • should revert if passed zero amount of tokens(38ms)
    • should revert if passed zero address
    • should revert of owner tries withdraw MILE tokens from pool(42ms)
    • should withdraw unused MILE(108ms)
    • should withdraw unused BNB(67ms)
    • should withdraw unused ERC20 token(109ms)
  • getRequestIdsByEntity & getRequestsByEntity
    • should return empty array if entity doesn't have any withdrawal requests
    • should return empty array due to incorrect limit
    • should return empty array due to incorrect offset
    • should return correct array of withdrawal requests(119ms)
    • should return correct array of withdrawal request with offset and limit(82ms)
  • get available sMILE to withdraw
    • should return 0 if entity doesn't have sMILE tokens(85ms)
    • should return amount of stake tokens
    • must change amount of withdrawable tokens after creating withdraw request(96ms)
562 passing(1m)

Tests written by Vidma auditors

Test Coverage

File
contracts\
MilestoneBased.sol 
contracts\entities\utils\
EntityAccessControler.sol
contracts\roadmaps\
Refund.sol
Roadmap.sol
RoadmapStaking.sol
TransparentProxyAdmin.sol
Voting.sol
VotingPowerCalculator.sol
All Files
File % Stmts % Branch % Funcs % Lines
contracts\ 100.00 91.67 100.00 98.11
MilestoneBased.sol  100.00 91.67 100.00 98.11
contracts\entities\utils\ 100.00 100.00 100.00 100.00
EntityAccessControler.sol 100.00 100.00 100.00 100.00
contracts\roadmaps\ 98.47 92.86 100.00 97.76
Refund.sol 100.00 100.00 100.00 100.00
Roadmap.sol 96.55 86.67 100.00 95.58
RoadmapStaking.sol 100.00 100.00 100.00 100.00
TransparentProxyAdmin.sol 100.00 100.00 100.00 100.00
Voting.sol 98.78 94.12 100.00 97.89
VotingPowerCalculator.sol 100.00 100.00 100.00 100.00
All Files 98.69 95.09 100.00 97.88

Test Results

Contract: MilestoneBased

  • initialize
    • should set owner correctly(46ms)
    • should revert if try initialize second time(73ms)
    • should revert if a zero address is passed(432ms)
  • createRoadmap
    • should revert if passed invalid project entity address(95ms)
    • should revert if caller is not entity owner(105ms)
    • should create roadmap and related contracts correctly(614ms)
    • should add created addresses to the whitelist correctly(53ms)
    • should catch event
  • setContractRegistry
    • should revert if caller isn’t owner(41ms)
    • should revert if a zero address is passed
    • should set registry address correctly(45ms)
    • should catch event
  • updateImplementation
    • should revert if caller isn’t owner(43ms)
    • should revert if a zero address is passed
    • should update implementation by key correctly(51ms)
    • should catch event

Contract: Refund

  • initialize
    • should set registry address correctly
    • should revert if try initialize second time
    • should revert if a zero address is passed(234ms)
  • addInvestments
    • should revert if caller isn’t roadmap
    • should add amount of tokens correctly(109ms)
  • refund
    • should revert if caller isn’t roadmap
    • should revert if remainder of investments is greater than total amount(45ms)
    • should transfer remainder of investments correctly(138ms)
  • claimRefund
    • should revert if sender doesn’t have investments(162ms)
    • should transfers remainder of investments to sender correctly(118ms)
    • should transfers remainder of investments to entity contract correctly(141ms)

Contract: Roadmap

  • initialize
    • should set contracts addresses correctly(60ms)
    • should revert if try initialize second time
    • should revert if a zero address is passed(138ms)
  • setFundsReleaseType
    • should revert if caller isn’t voter
    • should set release type correctly(61ms)
    • should catch event
  • fundRoadmap
    • should revert if passed address isn't an entity contract(46ms)
    • should revert if caller isn`t entity owner(50ms)
    • should revert if roadmap refunded(117ms)
    • should fund roadmap correctly(263ms)
    • should catch event
  • addMilestone
    • should revert if caller isn’t voting(43ms)
    • should revert if roadmap refunded
    • should revert if milestone has started(38ms)
    • should revert if passed invalid dates(40ms)
    • should revert if amount exceeds available balance(42ms)
    • should add milestone correctly(71ms)
    • should revert if milestone already exist(49ms)
    • should catch event
  • updateMilestone
    • should revert if caller isn’t voting
    • should revert if roadmap refunded
    • should revert if milestone doesn’t exist
    • should revert if passed invalid dates(62ms)
    • should revert if amount exceeds available balance(53ms)
    • should revert if the milestone has started and the new start date is different from the old one(45ms)
    • should revert if the milestone has started and the new end date is earlier than the current date(38ms)
    • should revert if the milestone has started and amount is less than the withdrawn amount(106ms)
    • should update milestone correctly(90ms)
    • should catch event
  • withdraw
    • should revert if milestone doesn’t exist(38ms)
    • should revert if milestone status is suspended(175ms)
    • should revert if milestone isn’t withdrawable(114ms)
    • should revert if amount exceeds available balance
    • should withdraw correctly(84ms)
    • should catch event
  • removeMilestone
    • should revert if milestone doesn’t exist(39ms)
    • should revert if milestone has started
    • should remove milestone correctly(144ms)
    • should catch event
  • updateMilestoneVotingStatus
    • should revert if milestone doesn’t exist(43ms)
    • should revert if milestone hasn’t started(90ms)
    • should update milestone voting status correctly(92ms)
    • should catch event
  • checkIsMilestoneWithdrawable
    • should return false if milestone isn`t withdrawable
    • should return true if milestone is withdrawable(112ms)
  • updateRoadmapState
    • should update roadmap state correctly(137ms)
    • should catch event

Contract: RoadmapStaking

  • initialize
    • should set voting and token addresses correctly
    • should revert if try initialize second time
    • should revert if a zero address is passed(127ms)
  • stake
    • should revert if a zero amount is passed
    • should revert if a zero address is passed
    • should transfer amount of governance tokens to the contract correctly(104ms)
    • should catch event
  • stakeTo
    • should revert if a zero amount is passed
    • should transfer amount of governance tokens to the contract correctly(87ms)
    • should increase the balance of staked governance token correctly
    • should catch event
  • stakeFromEntity
    • should revert if caller is not entity(42ms)
    • should revert if caller is not entity owner(60ms)
    • should revert if a zero amount is passed(41ms)
    • should transfer amount of governance tokens to the contract correctly(135ms)
    • should increase the balance of staked governance token correctly
    • should catch event
  • unstake
    • should return false if milestone isn`t withdrawable
    • should revert if caller is not entity owner(46ms)
    • should revert if a zero amount is passed
    • should revert if amount exceeds balance
    • should unstake governance tokens correctly(172ms)
    • should catch event
  • getVotingPowerByAddress
    • should return voting power correctly(52ms)

Contract: TransparentProxyAdmin

  • upgradeBatch
    • should revert if implementation address is zero(46ms)
    • should revert if arrays have different lengths
    • should update implementation correctly(234ms)
    • should catch event
  • upgradeAndCallBatch
    • should revert if implementation address is zero(62ms)
    • should revert if arrays have different lengths
    • should update implementation and call encoded function correctly(156ms)
    • should catch event

Contract: Voting

  • initialize
    • should initialize contract correctly(63ms)
    • should revert if try initialize second time
    • should revert if a zero address is passed(153ms)
    • should revert if a zero voting duration is passed(178ms)
  • setTimeLockBeforeVoting
    • Must revert if caller isn't voting contract
    • should set new time interval before voting correctly(206ms)
    • should catch event
  • setVotingDuration
    • should revert if zero duration is passed(361ms)
    • should set new voting duration correctly(230ms)
    • should catch event
  • setTimeLockBeforeExecution
    • should set new interval before execution correctly(194ms)
    • should catch event
  • setMinConsensusVotersCount
    • should set new minimal amount of voters correctly(222ms)
    • should catch event
  • setMinConsensusVotingPower
    • should revert if zero amount is passed(209ms)
    • should set new minimal amount of voting power correctly(218ms)
    • should catch event
  • addProposal
    • should revert if the arrays have different lengths
    • should revert if the options arrays have different lengths(74ms)
    • should revert if the arrays are empty
    • should add new proposal correctly(116ms)
    • should catch event
  • vote
    • should revert if proposal doesn’t exist
    • should revert if proposal isn’t in voting period(44ms)
    • should revert if options doesn’t exist(61ms)
    • should revert if caller isn’t entity owner(58ms)
    • should revert if passed address isn’t entity(38ms)
    • should revert if the proposal has already been voted(173ms)
    • should update implementation correctly(90ms)
    • should votes for an option using entity contract correctly(129ms)
    • should catch event
  • cancelVote
    • should revert if caller does not submit vote(177ms)
    • should cancel vote correctly(110ms)
    • should cancel vote submitted by entity correctly(153ms)
    • should catch event
  • updateVotingPower
    • should update voting power correctly(303ms)
    • should remove voted proposals correctly(265ms)
  • execution
    • should revert if call the function not in Execution period
    • Must revert if passed wrong option to execute(51ms)
    • Must revert if proposal already executed(221ms)
    • Must revert if not enough voting power(53ms)
    • Must revert if not enough voters(383ms)
    • should revert if execution is failed(161ms)
    • should execute proposal correctly(239ms)
    • should catch event
  • getOptionCount
    • should revert if proposal doesn’t exist
    • should return options count correctly(68ms)
  • getOptions
    • should revert if proposal doesn’t exist
    • should return options info correctly(390ms)
  • proposalTimeInterval
    • should return LockBeforeVoting time interval correctly
    • should return LockBeforeExecution time interval correctly(52ms)
    • should return Execution time interval correctly
    • should return AfterExecution time interval correctly

Contract: VotingPowerCalculator

  • initialize
    • should revert if try initialize second time
    • should revert if passed a zero address(85ms)
    • address of the RoadmapStaking contract should be set correctly
  • getVotingPowerByAddress
    • should call function with logic of calculation voting power correctly
  • supportsInterface
    • should return true if the passed interface is supported
    • should return false if the passed interface isn't supported
165 passing(22s)

We are delighted to have a chance to work with the milestoneBased team and contribute to your company's success by reviewing and certifying the security of your smart contracts.

The statements made in this document should be interpreted neither as investment or legal advice, nor should its authors be held accountable for decisions made based on this document.

Vidma is a security audit company helping crypto companies ensure their code and products operate safely and as intended, enabling founders to sleep soundly at night. We specialize in auditing DeFi protocols, layer one protocols, and marketplace solutions. Our team consists of experienced and internationally trained specialists. Our company is based in Ukraine, known for its strong engineering, cryptography, and cybersecurity culture.
4