NodeGrid

Smart Contract Audit Report

Audit Summary

NodeManager Audit Report NodeGrid allows users to purchase Nodes of various tiers that pay rewards over time.

For this audit, we reviewed the team's FeeManager contract at 0x8ea832f3bec083cf5184b717ab10d231bde6c282 and NodeManager contract at 0x3f4f253bde540186e3695b7abebb59d8f095e3d8 on the Binance Smart Chain Testnet.

Audit Findings

Please ensure trust in the team prior to investing as they have substantial control in the ecosystem.
Date: April 6th, 2022.
Updated: April 11th, 2022 to reflect changes and updated contract addresses.

Finding #1 - FeeManager - High (Resolved)

Description: The transferETHToOperator() and transferFeeToOperator() functions are incorrectly iterating over the Operators list.
for (uint32 i = 0; i < operators.length; i++) {
  if (isOperator[operators[i]]) continue;
  if (j == countOperator-1) {
    transferETH(operators[i], _fee);
  } else {
    transferETH(operators[i], _feeEach);
    _fee = _fee.sub(_feeEach);
  }
  j++;
}
Risk/Impact: These functions will not distribute funds unless an Operator was previously removed. If an Operator was previously removed it will incorrectly distribute funds to removed Operators.
Recommendation: The loop should continue if the user is not an Operator.
Resolution: The team has implemented the solution described above.

Finding #2 - NodeManager - Medium (Resolved)

Description: The countOfNodes() function incorrectly calculates the tierId from the tierName.
Risk/Impact: Users will be able to exceed the individual limit of Nodes per tier in some situations.
Recommendation: The tierId should be one less than the tierMap:
uint8 tierId = tierMap[tierName] - 1;
Resolution: The team has implemented the solution described above.

Finding #3 - NodeManager - Medium (Resolved)

Description: The transfer() function does not check a user's total Node count.
Risk/Impact: Users can exceed the individual limit of Nodes by transferring Nodes to another user.
Recommendation: Check that a user's total number of Nodes will not exceed the limit during a transfer.
Resolution: The team has implemented the solution described above.

Finding #4 - NodeManager - Low (Resolved)

Description: The upgrade() function relies on getAmountsOut() to calculate the upgrade fee.
Risk/Impact: The value returned from getAmountsOut() can potentially be manipulated through the use of a flashloan allowing users to upgrade at a reduced cost.
Recommendation: Implement a Time Weighted Average Price (TWAP) Oracle or a trusted off-chain pricing mechanism such as ChainLink.
Resolution: The upgrade() function now uses the lesser price value from two pricing mechanisms.

Finding #5 - NodeManager - Informational (Resolved)

Description: The upgrade() function does not return any extra BNB sent to the function.
Risk/Impact: Users will lose any extra BNB accidentally sent to the function.
Recommendation: Require that the BNB sent to function is the correct amount.

Finding #6 - NodeManager & FeeManager - Informational (Resolved)

Description: The contracts are implemented in Solidity 0.8.0 which is inherently protected from underflows/overflows, but still make use of SafeMath.
Risk/Impact: All functions using SafeMath will have higher gas costs than necessary.
Recommendation: SafeMath can be safely removed.

Contracts Overview

  • As the contracts are implemented with Solidity v0.8.0, they are safe from any possible overflows/underflows.
  • The team must exercise caution when assigning the specified token to avoid using fee-on-transfer or ERC-777 compliant tokens.
NodeManager Contract:
  • Any user may use this contract to create a Node of a specified tier by paying the creation cost for that tier of Node in a specified token.
  • Blacklisted addresses may not create, upgrade, transfer, compound, or claim rewards from Nodes.
  • Each user may have a maximum number of total Nodes as well as a maximum number of Nodes per tier.
  • When enabled, users may transfer Nodes to other users at the cost of a transfer fee; all unclaimed rewards after fees will be paid to the sender before the transfer occurs.
  • Users will earn rewards over time in the specified token based on the Node's tier, the amount of time since the last rewards claim, and the claim interval.
  • If a "Boost NFT" contract has been set, users may have an additional rewards multiplier; the NFT contract was out of scope for this audit so we are unable to give an assessment in regards to security.
  • Users may claim all pending rewards for all of their Nodes at any time.
  • Users may elect to compound their rewards.
  • Compounding allows users to use their pending rewards to pay the creation cost of any number of Nodes of any tier; any remaining rewards after the Node creation will be paid out to the user.
  • Users may elect to upgrade their Nodes.
  • In order to upgrade, users must burn Nodes equal to the ratio of the cost of the starting tier and ending tier.
  • The team should exercise caution when setting the cost for each tier as any division when calculating the number of Nodes required to upgrade will be truncated.
  • If the user does not have enough Nodes to complete the upgrade, they may pay the creation cost of the remaining Nodes required to upgrade.
  • There is an additional upgrade fee associated with upgrading to each tier that may be paid in BNB or the specified token.
  • Users may also "pay" for all or a specified number of their Nodes; paying for a Node will increase the "limited time" of the Node.
  • Users may pay for 1 to 12 months at a time.
  • The fee must be paid in BNB unless a separate fee token has been specified.
  • The owner may mint any number of Nodes of any tier to any address at no cost at any time.
  • The owner may allocate any number of Nodes to any address through the use of a Merkle Tree. Users must claim the Nodes themselves after they are allocated.
  • The owner may add any address to the blacklist at any time.
  • The owner may update the max number of Nodes each address may have to any value at any time.
  • The owner may update the Fee Manager, Boost NFT and fee token address at any time.
  • The owner may toggle the ability to transfer Nodes at any time.
  • The owner may add a new Node tier and update the values of any Node tier at any time.
  • The owner may remove a Node tier at any time.
  • The owner may burn any Node from any user at any time.
FeeManager Contract:
  • This contract is used to collect fees from and transfer rewards to users in a specified token.
  • Sufficient tokens must be supplied to the contract or users will be unable to claim rewards.
  • When tokens are collected as fees, a portion is distributed between the Treasury and Operator address while the remaining amount stays within the contract for rewards distributions.
  • When enabled, the Manager address may swap any amount of tokens in the contract for BNB which is subsequently transferred to any specified address.
  • The Manager may transfer any amount of the specified token from the contract to any address at any time.
  • The owner may set the upgrade fee between any two tiers of Nodes to any value at any time.
  • The owner may withdraw any amount of the specified token or BNB from the contract at any time.
  • The owner may update the Manager and Treasury addresses at any time.
  • The owner may add or remove an address as an Operator at any time.
  • The owner may toggle ETH transfers at any time.
  • The owner may update the allocation of Operator, Treasury, and Rewards fee distributions at any time.
  • The owner may update the fee associated with transferring Nodes at any time.
  • The owner may update the specified token at any time.

Audit Results

Vulnerability CategoryNotesResult
Arbitrary Jump/Storage WriteN/APASS
Centralization of Control
  • The team retains ownership controls described above.
  • There are instances of uncapped fees.
  • The NodeManger owner may burn any Node at any time.
  • The FeeManager owner may withdraw all BNB and rewards tokens from the contract.
  • The NodeManager owner may add any address to the blacklist.
WARNING
Compiler IssuesN/APASS
Delegate Call to Untrusted ContractN/APASS
Dependence on Predictable VariablesN/APASS
Ether/Token TheftN/APASS
Flash LoansN/APASS
Front RunningN/APASS
Improper EventsN/APASS
Improper Authorization SchemeN/APASS
Integer Over/UnderflowN/APASS
Logical IssuesN/APASS
Oracle IssuesN/APASS
Outdated Compiler VersionN/APASS
Race ConditionsN/APASS
ReentrancyN/APASS
Signature IssuesN/APASS
Unbounded LoopsN/APASS
Unused CodeN/APASS
Overall Contract Safety WARNING

NodeManager Contract

Smart Contract Audit - Inheritance

Smart Contract Audit - Graph


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 + [Int] IUniswapV2Router01 
    - [Ext] factory
    - [Ext] WETH
    - [Ext] addLiquidity #
    - [Ext] addLiquidityETH ($)
    - [Ext] removeLiquidity #
    - [Ext] removeLiquidityETH #
    - [Ext] removeLiquidityWithPermit #
    - [Ext] removeLiquidityETHWithPermit #
    - [Ext] swapExactTokensForTokens #
    - [Ext] swapTokensForExactTokens #
    - [Ext] swapExactETHForTokens ($)
    - [Ext] swapTokensForExactETH #
    - [Ext] swapExactTokensForETH #
    - [Ext] swapETHForExactTokens ($)
    - [Ext] quote
    - [Ext] getAmountOut
    - [Ext] getAmountIn
    - [Ext] getAmountsOut
    - [Ext] getAmountsIn

 + [Int] IUniswapV2Router02 (IUniswapV2Router01)
    - [Ext] removeLiquidityETHSupportingFeeOnTransferTokens #
    - [Ext] removeLiquidityETHWithPermitSupportingFeeOnTransferTokens #
    - [Ext] swapExactTokensForTokensSupportingFeeOnTransferTokens #
    - [Ext] swapExactETHForTokensSupportingFeeOnTransferTokens ($)
    - [Ext] swapExactTokensForETHSupportingFeeOnTransferTokens #

 + [Lib] Address 
    - [Int] isContract
    - [Int] sendValue #
    - [Int] functionCall #
    - [Int] functionCall #
    - [Int] functionCallWithValue #
    - [Int] functionCallWithValue #
    - [Prv] _functionCallWithValue #

 + [Lib] SafeMath 
    - [Int] add
    - [Int] sub
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] div
    - [Int] mod
    - [Int] mod

 + [Int] IERC20 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 + [Int] IERC20Upgradeable 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 + [Lib] AddressUpgradeable 
    - [Int] isContract
    - [Int] sendValue #
    - [Int] functionCall #
    - [Int] functionCall #
    - [Int] functionCallWithValue #
    - [Int] functionCallWithValue #
    - [Int] functionStaticCall
    - [Int] functionStaticCall
    - [Int] verifyCallResult

 +  Initializable 
    - [Prv] _isConstructor

 +  FeeManager (Initializable)
    - [Pub] initialize #
       - modifiers: initializer
    - [Pub] transferOwnership #
       - modifiers: onlyOwner
    - [Pub] bindManager #
       - modifiers: onlyOwner
    - [Pub] setTreasury #
       - modifiers: onlyOwner
    - [Pub] setOperator #
       - modifiers: onlyOwner
    - [Pub] enableTransferETH #
       - modifiers: onlyOwner
    - [Pub] removeOperator #
       - modifiers: onlyOwner
    - [Pub] setRateRewardsPoolFee #
       - modifiers: onlyOwner
    - [Pub] setRateTreasuryFee #
       - modifiers: onlyOwner
    - [Pub] setRateOperatorFee #
       - modifiers: onlyOwner
    - [Pub] setRateTransferFee #
       - modifiers: onlyOwner
    - [Pub] bindToken #
       - modifiers: onlyOwner
    - [Pub] transferTokenToOperator #
       - modifiers: onlyManager
    - [Pub] transferFeeToOperator #
       - modifiers: onlyManager
    - [Pub] transferETHToOperator ($)
       - modifiers: onlyManager
    - [Pub] transferFee #
       - modifiers: onlyManager
    - [Pub] transferETH #
       - modifiers: onlyManager
    - [Pub] transfer #
       - modifiers: onlyManager
    - [Pub] transferFrom #
       - modifiers: onlyManager
    - [Pub] withdraw #
       - modifiers: onlyOwner
    - [Pub] withdrawETH #
       - modifiers: onlyOwner
    - [Pub] getAmountETH
       - modifiers: onlyManager
    - [Pub] getAmountFee

FeeManager Contract

Smart Contract Audit - Inheritance

Smart Contract Audit - Graph


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 + [Int] IUniswapV2Router01 
    - [Ext] factory
    - [Ext] WETH
    - [Ext] addLiquidity #
    - [Ext] addLiquidityETH ($)
    - [Ext] removeLiquidity #
    - [Ext] removeLiquidityETH #
    - [Ext] removeLiquidityWithPermit #
    - [Ext] removeLiquidityETHWithPermit #
    - [Ext] swapExactTokensForTokens #
    - [Ext] swapTokensForExactTokens #
    - [Ext] swapExactETHForTokens ($)
    - [Ext] swapTokensForExactETH #
    - [Ext] swapExactTokensForETH #
    - [Ext] swapETHForExactTokens ($)
    - [Ext] quote
    - [Ext] getAmountOut
    - [Ext] getAmountIn
    - [Ext] getAmountsOut
    - [Ext] getAmountsIn

 + [Int] IUniswapV2Router02 (IUniswapV2Router01)
    - [Ext] removeLiquidityETHSupportingFeeOnTransferTokens #
    - [Ext] removeLiquidityETHWithPermitSupportingFeeOnTransferTokens #
    - [Ext] swapExactTokensForTokensSupportingFeeOnTransferTokens #
    - [Ext] swapExactETHForTokensSupportingFeeOnTransferTokens ($)
    - [Ext] swapExactTokensForETHSupportingFeeOnTransferTokens #

 + [Lib] Address 
    - [Int] isContract
    - [Int] sendValue #
    - [Int] functionCall #
    - [Int] functionCall #
    - [Int] functionCallWithValue #
    - [Int] functionCallWithValue #
    - [Prv] _functionCallWithValue #

 + [Lib] SafeMath 
    - [Int] add
    - [Int] sub
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] div
    - [Int] mod
    - [Int] mod

 + [Int] IERC20 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 + [Int] IERC20Upgradeable 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 + [Lib] AddressUpgradeable 
    - [Int] isContract
    - [Int] sendValue #
    - [Int] functionCall #
    - [Int] functionCall #
    - [Int] functionCallWithValue #
    - [Int] functionCallWithValue #
    - [Int] functionStaticCall
    - [Int] functionStaticCall
    - [Int] verifyCallResult

 +  Initializable 
    - [Prv] _isConstructor

 +  FeeManager (Initializable)
    - [Pub] initialize #
       - modifiers: initializer
    - [Pub] transferOwnership #
       - modifiers: onlyOwner
    - [Pub] bindManager #
       - modifiers: onlyOwner
    - [Pub] setTreasury #
       - modifiers: onlyOwner
    - [Pub] setOperator #
       - modifiers: onlyOwner
    - [Pub] enableTransferETH #
       - modifiers: onlyOwner
    - [Pub] removeOperator #
       - modifiers: onlyOwner
    - [Pub] setRateRewardsPoolFee #
       - modifiers: onlyOwner
    - [Pub] setRateTreasuryFee #
       - modifiers: onlyOwner
    - [Pub] setRateOperatorFee #
       - modifiers: onlyOwner
    - [Pub] setRateTransferFee #
       - modifiers: onlyOwner
    - [Pub] bindToken #
       - modifiers: onlyOwner
    - [Pub] transferTokenToOperator #
       - modifiers: onlyManager
    - [Pub] transferFeeToOperator #
       - modifiers: onlyManager
    - [Pub] transferETHToOperator ($)
       - modifiers: onlyManager
    - [Pub] transferFee #
       - modifiers: onlyManager
    - [Pub] transferETH #
       - modifiers: onlyManager
    - [Pub] transfer #
       - modifiers: onlyManager
    - [Pub] transferFrom #
       - modifiers: onlyManager
    - [Pub] withdraw #
       - modifiers: onlyOwner
    - [Pub] withdrawETH #
       - modifiers: onlyOwner
    - [Pub] getAmountETH
       - modifiers: onlyManager
    - [Pub] getAmountFee

About Solidity Finance

Solidity Finance was founded in 2020 and quickly grew to have one of the most experienced and well-equipped smart contract auditing teams in the industry. Our team has conducted 1000+ 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 across 1500 projects!.
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 Solidity Audit?

Typically, a smart contract audit is a comprehensive review process designed to discover logical errors, security vulnerabilities, and optimization opportunities within code. A Solidity 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.