RSG

Smart Contract Audit Report

Audit Summary

RSG Audit Report RSG is building a new ERC-20 token.

For this audit, we reviewed the project team's RSG contract at 0x0b095f6eb5ff672232a0151ef022b0f9d465ccb9 on the Binance Smart Chain Mainnet.

Audit Findings

All findings in the RSG contract have been resolved.
Date: November 16th, 2023.
Updated: November 27th, 2023 to reflect updates made to the RSG contract that resolves all Findings.
Updated: April 19th, 2024 to reflect updates made to the RSG contract.
Updated: April 23rd, 2024 to reflect updates made to the RSG contract.
Updated: May 9th, 2024 to reflect the RSG contract's Mainnet address.

Finding #1 - RSG - High (Resolved)

Description: The payout() function to withdraw WETH from the contract can be called by any user as it does not contain a role-restricted modifier.
Risk/Impact: Any user can withdraw any amount of WETH from the contract at any time.
Recommendation: A modifier should be added to the payout() function to enforce that only the project team can withdraw WETH from the contract.
Resolution: The team has modified the payout() function to enforce that the caller must have been granted the Operator role.

Finding #2 - RSG - Informational (Resolved)

Description: Although the contract inherits the Ownable contract, the onlyOwner modifier is never used.
Recommendation: The Ownable contract should either be removed to reduce contract size and deployment costs or utilized in a way that fits the project team's intended functionality.
Resolution: The team has removed the Ownable contract.

Finding #3 - RSG - Informational (Resolved)

Description: Although the contract inherits the Pausable contract, the whenNotPaused modifier is never used.
Recommendation: The Pausable contract should either be removed to reduce contract size and deployment costs or utilized in a way that fits the project team's intended functionality.
Resolution: The team has removed the Pausable contract.

Finding #4 - RSG - Informational (Resolved)

Description: The WETH and taxPercentage state variables can only be set one time in the constructor but are not declared immutable.
Recommendation: The above state variables could be declared immutable for additional gas savings on each reference.
Resolution: The team has implemented the above recommendation.

Finding #5 - RSG - Low (Resolved)

Description: The following logic in the payout() function erroneously attempts to transfer ETH from the contract to the Rewards token address rather than to an address specified by the team.
uint256 myBalance = address(this).balance;
         
if (myBalance < params.amount) {
      console.log("RSG: Reverting, balance low");
      revert NotEnoughBalance();
}

payable(rewardsToken).transfer(params.amount);
Risk/Impact: If the Rewards token contract can accept ETH, ETH will be mistakenly sent to this contract rather than the intended team address. Otherwise, if the Rewards token contract is not designed to accept ETH, any attempt to send ETH to it will cause the transaction to revert.
Recommendation: The above logic should be modified to transfer ETH to the to address rather than the Rewards token address.
Resolution: The team has implemented the above recommendation.

Finding #6 - RSG - Informational (Resolved)

Description: The constructor and the configure() function allow the team to set taxPercentage to zero. If set to zero, all transfers that charge a fee will revert due to a divide-by-zero error.
Recommendation: The team could add a require statement to both the constructor and the configure() function that enforces that taxPercentage cannot be set to zero.
Resolution: The team has implemented the above recommendation.

Finding #7 - RSG - Informational (Resolved)

Description: The poolId state variable is not used in the contract.
Recommendation: The poolId state variable should either be removed or utilized in a way that fits the project team's intended functionality.
Resolution: The team has removed the poolId state variable from the contract.

Contract Overview

  • The total supply of the token is set to 420,000 $RSG.
  • No mint or burn functions are publicly accessible, though the circulating supply can be decreased by sending tokens to the 0x..dead address.
  • The contract charges a fee on transfers except when the tax system is disabled, if the sender or recipient is the contract itself or the 0x00 address, or if the sender has the Operator role.
  • The sender is automatically declared as the "winner" on every transfer, except when the transaction is a buy, in which case the recipient is declared as the winner.
  • All transfers that charge fees are considered a "winnable transfer" and a corresponding event is emitted.
  • The tokens collected through the fee are transferred to the contract.
  • Any user that has a positive token balance is added to the contract's list of holders.
  • Any user granted the Operator role can swap all of the tokens in the contract collected through fees for the Reward token and send the received Reward tokens to the Trust Fund address at any time. The caller will specify the minimum amount of Reward tokens that must be received in order for the transaction to successfully occur.
  • Any address granted the Operator role can end the current period and start the next one at any time. The token swapping functionality is automatically triggered during this process.
  • Any address granted the Operator role can withdraw any amount of tokens or ETH from the contract to any recipient address at any time.
  • Any address granted the Operator role can update the Router address at any time. During this process, the current operators, owner, and team addresses have their roles revoked and reassigned to the newly specified owner, operators, and team addresses.
  • Additionally, the Operator role can set the transfer fee to any percentage between 10% and 100% at any time.
  • Any address granted the Operator role can enable/disable fees at any time.
  • Any address granted the Operator role can pause/unpause all transfers at any time.
  • As the contract is implemented with Solidity v0.8.x, it is safe from any possible overflows/underflows.
  • The contract complies with the ERC-20 token standard.

RSG Bot Scripts Overview

In the course of this audit, additional analysis was performed on a collection of Typescript files used to determine winners that are paid out in the RSG contract. We have reviewed each file provided to us and its functionality, however, it is important to note that, unlike Smart Contracts, the scripts being run can be changed at any time so we cannot guarantee that the scripts provided to us will be the same ones run by the team.

PeriodInfo Class:
  • This class is used to generate and maintain the information used when determining transfers eligible to win during a specified period.
  • A transfer is eligible to win during the specified period if it was determined to be a "winnable transfer" in the RSG contract and a corresponding event was emitted.
  • The transfer must have additionally occurred during the specified period to be an eligible winner in that period.
  • This file additionally determines a "seed" used when generating a pseudorandom number to determine winners.
  • The seed is defined as a string consisting of the block and sender of the first eligible transfer in the period and the block and sender of the last eligible transfer in the period.
  • As the first transfer during a period is known beforehand and the end of the period is predictable, it is possible to potentially influence the outcome of this function.
Owners Class:
  • This class is used to maintain a set of owners.
  • Each owner is associated with a wallet address and an amount.
  • Additionally, a unique set is maintained with the wallet address and the total amount owned by the address.
Winners Class:
  • This class is used to determine 7 winner addresses.
  • One winner is determined from all eligible transfers in the period. This user will receive 10% of the rewards pool.
  • An additional 6 winners are determined from eligible transfers on the first 6 days of the period. These winners will receive 2% of the rewards pool.
  • If any rewards payout would be below the minimum amount set in the config file the winner will forfeit their reward.
  • The winners are determined using a pseudorandom number generator. The seed for this number generator is calculated in the PeriodInfo class.
Payout Class:
  • This class is intended to payout winnings to the winners determined in the Winners file.
  • However, the pay() function is not called in any of the files within the scope of this audit so we cannot guarantee the manner in which information is passed to the function is determined.
  • Each winner passed to the function is paid their "winnings" from the RSG contract.
  • Any remaining rewards in the pool are split among the owners passed to the function. If the amount would be less than the minimum payment set in the config file the user will forfeit their rewards.
tokenOwners.ts:
  • This file is used to create a set of Owners as defined in the owners file for a specified NFT.
  • The file will request all of the owners of the NFT and the corresponding "amount".
  • This data will be passed to the owners file where it is handled as described above.

Audit Results

Vulnerability Category Notes Result
Arbitrary Jump/Storage Write N/A PASS
Centralization of Control Any Operator address can set the transfer fee to any percentage between 10% and 100% at any time. WARNING
Compiler Issues N/A PASS
Delegate Call to Untrusted Contract N/A PASS
Dependence on Predictable Variables The seed phrase used to determine the pseudorandom numbers in the Winners class can potentially be influenced. WARNING
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

Inheritance Chart

Smart Contract Audit - Inheritance

Function Graph

Smart Contract Audit - Graph

Functions Overview


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public

 +  Context 
    - [Int] _msgSender
    - [Int] _msgData

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

 + [Int] IERC20Metadata (IERC20)
    - [Ext] name
    - [Ext] symbol
    - [Ext] decimals

 + [Int] IERC20Errors 

 + [Int] IERC721Errors 

 + [Int] IERC1155Errors 

 +  ERC20 (Context, IERC20, IERC20Metadata, IERC20Errors)
    - [Pub]  #
    - [Pub] name
    - [Pub] symbol
    - [Pub] decimals
    - [Pub] totalSupply
    - [Pub] balanceOf
    - [Pub] transfer #
    - [Pub] allowance
    - [Pub] approve #
    - [Pub] transferFrom #
    - [Int] _transfer #
    - [Int] _update #
    - [Int] _mint #
    - [Int] _burn #
    - [Int] _approve #
    - [Int] _approve #
    - [Int] _spendAllowance #

 + [Int] IAccessControl 
    - [Ext] hasRole
    - [Ext] getRoleAdmin
    - [Ext] grantRole #
    - [Ext] revokeRole #
    - [Ext] renounceRole #

 + [Lib] Math 
    - [Int] max
    - [Int] min
    - [Int] average
    - [Int] ceilDiv
    - [Int] mulDiv
    - [Int] mulDiv
    - [Int] sqrt
    - [Int] sqrt
    - [Int] log2
    - [Int] log2
    - [Int] log10
    - [Int] log10
    - [Int] log256
    - [Int] log256

 + [Lib] SignedMath 
    - [Int] max
    - [Int] min
    - [Int] average
    - [Int] abs

 + [Lib] Strings 
    - [Int] toString
    - [Int] toString
    - [Int] toHexString
    - [Int] toHexString
    - [Int] toHexString
    - [Int] equal

 + [Int] IERC165 
    - [Ext] supportsInterface

 +  ERC165 (IERC165)
    - [Pub] supportsInterface

 +  AccessControl (Context, IAccessControl, ERC165)
    - [Pub] supportsInterface
    - [Pub] hasRole
    - [Int] _checkRole
    - [Int] _checkRole
    - [Pub] getRoleAdmin
    - [Pub] grantRole #
       - modifiers: onlyRole
    - [Pub] revokeRole #
       - modifiers: onlyRole
    - [Pub] renounceRole #
    - [Int] _setupRole #
    - [Int] _setRoleAdmin #
    - [Int] _grantRole #
    - [Int] _revokeRole #

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

 + [Lib] TransferHelper 
    - [Int] safeTransfer #

 +  Pausable (Context)
    - [Pub]  #
    - [Pub] paused
    - [Int] _requireNotPaused
    - [Int] _requirePaused
    - [Int] _pause #
       - modifiers: whenNotPaused
    - [Int] _unpause #
       - modifiers: whenPaused

 +  Ownable (Context)
    - [Pub]  #
    - [Pub] owner
    - [Int] _checkOwner
    - [Pub] renounceOwnership #
       - modifiers: onlyOwner
    - [Pub] transferOwnership #
       - modifiers: onlyOwner
    - [Int] _transferOwnership #

 + [Int] IUniswapV3SwapCallback 
    - [Ext] uniswapV3SwapCallback #

 + [Int] ISwapRouter (IUniswapV3SwapCallback)
    - [Ext] exactInputSingle ($)
    - [Ext] exactInput ($)
    - [Ext] exactOutputSingle ($)
    - [Ext] exactOutput ($)

 + [Int] IERC721 (IERC165)
    - [Ext] balanceOf
    - [Ext] ownerOf
    - [Ext] safeTransferFrom #
    - [Ext] safeTransferFrom #
    - [Ext] transferFrom #
    - [Ext] approve #
    - [Ext] setApprovalForAll #
    - [Ext] getApproved
    - [Ext] isApprovedForAll

 + [Int] IERC721Metadata (IERC721)
    - [Ext] name
    - [Ext] symbol
    - [Ext] tokenURI

 + [Int] IERC721Enumerable (IERC721)
    - [Ext] totalSupply
    - [Ext] tokenOfOwnerByIndex
    - [Ext] tokenByIndex

 + [Int] IPoolInitializer 
    - [Ext] createAndInitializePoolIfNecessary ($)

 + [Int] IERC721Permit (IERC721)
    - [Ext] PERMIT_TYPEHASH
    - [Ext] DOMAIN_SEPARATOR
    - [Ext] permit ($)

 + [Int] IPeripheryPayments 
    - [Ext] unwrapWETH9 ($)
    - [Ext] refundETH ($)
    - [Ext] sweepToken ($)

 + [Int] IPeripheryImmutableState 
    - [Ext] factory
    - [Ext] WETH9

 + [Lib] PoolAddress 
    - [Int] getPoolKey

 + [Int] INonfungiblePositionManager (IPoolInitializer, IPeripheryPayments, IPeripheryImmutableState, IERC721Metadata, IERC721Enumerable, IERC721Permit)
    - [Ext] positions
    - [Ext] mint ($)
    - [Ext] increaseLiquidity ($)
    - [Ext] decreaseLiquidity ($)
    - [Ext] collect ($)
    - [Ext] burn ($)

 +  ERC20Liquidity (ERC20, Ownable)
    - [Pub]  #
    - [Int] _configure #
    - [Int] _swapTokensForEth #

 +  RSG (ERC20, AccessControl, ERC20Liquidity, Pausable)
    - [Pub]  #
       - modifiers: ERC20,Ownable,ERC20Liquidity
    - [Pub] configure #
       - modifiers: onlyRole
    - [Ext]  ($)
    - [Int] _update #
    - [Ext] roleTest
       - modifiers: onlyRole
    - [Ext] collectTax #
       - modifiers: onlyRole
    - [Ext] payout #

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.