Arcadeum

Smart Contract Audit Report

Audit Summary

Arcadeum Audit Report Arcadeum is a new betting platform which allows users to wager USDT on various games. The platform also includes multiple tokens and staking functionality.

For this audit, we reviewed the following contracts on the Arbitrum Mainnet:

As the GameLimbo, GameRockPaperScissors, and GameCoinFlip contracts are not verified at the time of this report, they are not included in the scope of this audit.

Audit Findings

A Low finding was identified and the team should consider resolving this issue. In addition, centralized aspects are present.
Date: February 28th, 2023.

Finding #1 - Player - Low

Description: The setAvatar() function will revert when a user chooses an Avatar unlocked instead of reverting when the Avatar is locked.
Risk/Impact: Users will have all avatars automatically unlocked. When an Avatar is "unlocked" for a user, it will incorrectly lock it instead.
Recommendation: The setAvatar() function should revert when a user's chosen Avatar is locked.
Resolution: The team has not yet addressed this issue.

Finding #2 - ALP, House, Console, FeeToken, & Player - Informational

Description: These contracts contain a receive() function, but have no way to withdraw the blockchain's native currency.
Recommendation: A withdraw function should be added, or the receive() function should be removed to avoid any funds from being trapped.

Finding #3 - Player - Informational

Description: The following code exists in the setUsername() function, which assigns a Player struct to a storage variable, then updates it unnecessarily.
Types.Player storage _player = players[msg.sender];
usernameTaken[_player.username] = false;
_player.username = _username;
usernameTaken[_player.username] = true;
players[msg.sender] = _player;
Recommendation: As updating this storage variable directly updates the mapping it is set to, the last mentioned line is not needed and can be removed for gas savings.

Contracts Overview

  • This platform utilizes AirNode for intended randomness, which relies on off-chain functionality that was not reviewed within the scope of this audit.
  • The contracts utilize ReentrancyGuard to prevent against reentrancy attacks in applicable functions.
  • As the contracts are implemented with Solidity v0.8.0, they are safe from any possible overflows/underflows.
ALP Contract:
  • This contract allows users to deposit USDT in exchange for minted ALP tokens.
  • Whitelisted users can deposit USDT into the contract at any time.
  • Non-Whitelisted users cannot begin depositing until the owner has "opened" the contract.
  • A deposit fee is taken and is distributed between the xARC, sARC, and esARC FeeTracker contracts.
  • 70% is deposited into the xARC contract, and 15% is deposited into both the sARC and esARC contracts.
  • The user is then minted ALP tokens representing their share of total USDT in the contract.
  • Users can withdraw at any time, which burns their ALP tokens in order to receive their USDT value.
  • A withdrawal fee is taken from the USDT redemption amount and distributed to the previously mentioned FeeTracker contracts with the same ratios.
  • This contract is used by the House contract to transfer funds that are earned and lost from games.
  • The House contract can pay a winner at any time, which transfers USDT from this contract to a specified address.
  • The House can also "receive a loss" at any time, which transfers USDT from the user to this contract.
  • Information for each user's deposit and withdrawal is registered in the associated esArcIncentiveManager contract.
  • As the esArcIncentiveManager contract was not included in the scope of this audit, we are unable to provide an assessment with regards to security or functionality.
  • The owner can remove all deposit and withdrawal fees at any time. Once fees have been removed, they can no longer be updated.
  • The owner can update the deposit or withdrawal fee to up to 1% unless fees have been removed.
  • The owner can add or remove any user from the Depositor Whitelist at any time.
  • The owner can update the esArcIncentiveManager contract at any time.
ARC Contract:
  • The owner is minted 10 million tokens upon deployment
  • Users can burn their tokens or tokens they have an allowance of at any time.
  • Any address can initiate a "claim" at any time. This calls the associated NonfungiblePositionManager contract's collect() function, which is intended to transfer both ARC tokens and WETH to this contract.
  • The resulting ARC tokens are burned, and the WETH unwrapped and deposited into an associated LPFeeReceiver contract.
  • As the NonfungiblePositionManager and LPFeeReceiver contracts were not included in the scope of this audit, we are unable to provide an assessment with regards to their security or functionality.
  • This contract complies with the ERC-20 standard.
  • The owner can update the LPFeeReceiver contract at any time.
  • The owner can update the token ID, used for NonfungiblePositionManager contract interaction, at any time.
FeeToken contract:
  • An associated FeeTracker contract is created upon deployment, and its ownership is subsequently transferred to the owner of this contract.
  • The total Fee Token supply is minted to the owner upon deployment.
  • Users can burn their tokens or tokens they have an allowance of at any time.
  • When tokens are transferred, minted, or burned, the sender and recipient's pending FeeTracker earnings are claimed for them, and their FeeTracker share balance is updated to their new Fee Token balance.
  • Blacklisted addresses are excluded from the mentioned FeeTracker functionality and rewards.
  • The owner can add or remove any address from the Blacklist at any time.
  • This contract and the 0x0 address are added to the Blacklist upon deployment.
esARC Contact:
  • This contract is an implementation of the FeeToken contract with added "locking" functionality.
  • A user can lock any amount of esARC tokens in this contract in order to withdraw ARC tokens once one year has passed.
  • If a user locks additional tokens while their lock is still active, their lock timer will reset.
  • A user can end their lock once a year has passed from their last lock, which will burn their locked esARC tokens and transfer the user an equal amount of ARC tokens.
  • The team should ensure that this contract holds a sufficient ARC token balance in order to facilitate ARC transfers.
sARC Contract:
  • This contract is an implementation of the FeeToken contract with added staking and unstaking functionality.
  • Users can stake their ARC tokens at any time, which transfers them to this contract.
  • In return, users are minted the equivalent amount of sARC tokens.
  • Users can unstake at any time, burning their sARC tokens in exchange for their staked ARC tokens.
xARC Contract:
  • This contract is an implementation of the FeeToken contract with added "staking" functionality.
  • Users can "stake" their ARC tokens at any time, which burns them and mints the user the equivalent amount of xARC tokens.
  • As ARC tokens are burned upon staking, there is no unstaking functionality.
FeeTracker Contract:
  • This contract is used to collect USDT rewards and distribute them to holders of the associated Fee Token.
  • The deployer of the contract is set as the FeeToken address.
  • Contracts that have been added as a "yield source" can deposit USDT into the contract at any time.
  • A user will earn a percentage of deposited USDT equal to their share of the total Fee Token supply.
  • Users can manually withdraw their accumulated earnings at any time.
  • The owner can add any address as a yield source at any time.
House Contract:
  • This contract facilitates payments and wager functionality.
  • Supported Game contracts use this contract to open and close wagers.
  • When opening a wager, a Game contract provides information about the user, game, bet amount, number of rolls, payout, referrer, and other relevant data.
  • A user's bet amount cannot exceed the USDT balance of the ALP contract or the maximum permitted bet for the Game.
  • The USDT bet amount plus a betting fee is transferred from the user to this contract.
  • The betting fee percentage is determined by the Player's level or VIP status within the contract.
  • Bronze, Silver, Gold, and Black tier VIP members will pay a 0.3%, 0.15%, 0.1%, or 0.05% betting fee, respectively.
  • If the user is not a VIP member, they will pay a 1% fee, decreased by .01% for each level to a minimum fee of 0.5% at level 50 and above users.
  • Betting fees are floored at the contract's minimum betting fee.
  • Betting fees are capped at 5 USDT, or 3 USDT if the user is a VIP.
  • 20% of the betting fee is sent to the user's referrer, which can be set only once.
  • The remainder of the fee is deposited into the xARC, sARC, and esARC FeeTracker contracts using the same distribution rates used in the ALP contract.
  • When a wager is closed, the user receives any USDT they are owed from the wager.
  • If their payout amount is less than their original stake, the contract's profits are sent to the ALP address.
  • If the user made a profit on their wager, they are transferred their wager amount from this contract and profits from the ALP contract.
  • The user receives experience points (XP) towards their level at the end of their wager depending on the size of their bet, up to a maximum of 100 XP.
  • The user receives an additional 100 XP if they collect a profit on their wager.
  • The owner can decrease the betting fee at any time, but cannot increase it.
  • The owner can update the referrer cut to any amount between 0% and 80% of the betting fee at any time.
Player Contract:
  • This contract is used to store Player data and allow users to update their Avatar, username, and referrer.
  • Any contract included in the "XP Sources" list can grant any amount of XP to a Player.
  • The required experience for a given level, EXP(n), can be represented as follows: EXP(n) = (n(n+1)/2) * 100.
  • The platform's level cap is 100.
  • A Player is deemed a VIP if they meet any of the following requirements:
    • Level 1 VIP: The Player holds either at least a 2,000 sARC balance, 1,000 xARC balance, or has reached level 45.
    • Level 2 VIP: The Player holds either at least a 6,000 sARC balance, 3,000 xARC balance, or has reached level 50.
    • Level 3 VIP: The Player holds either at least a 15,000 sARC balance, 7,500 xARC balance, or has reached level 70.
    • Level 4 VIP: The Player holds either at least a 80,000 sARC balance, 40,000 xARC balance, or has reached level 100.
  • Any contract included in the "Avatar Unlocker" list can unlock any Avatar ID for any user.
  • A user can update their username if they have reached at least level three.
  • The username cannot be empty or already taken.
  • A user can update their Avatar ID to any ID that they have unlocked at any time.
  • The owner can add an address to the XP Sources list or Avatar Unlocker list at any time.
Console Contract:
  • This contract is used to register and fetch supported Games on the platform.
  • The owner can add a new Game at any time, specifying the Game's name, address, edge, and whether it is live or not.
  • An ID is assigned to the registered Game.
  • The owner can edit the attributes of an existing Game at any time.
  • The owner can update the "gas per roll" to any amount up to 10^16 at any time.
  • The owner can update the minimum bet size to any amount up to 10^6 at any time.
RNG Contract:
  • This contract is used for all intended randomness functionality throughout the platform.
  • Upon construction, the associated AirnodeRRPV0 contract's setSponsorshipStatus() function is called.
  • Only registered and live Game contracts or addresses included in the Caller Whitelist can initiate randomness requests.
  • A request for a single number or a list of numbers can be made at any time.
  • This will initiate a request using the associated AirnodeRRPV0 contract.
  • Only the AirnodeRRPV0 contract can fulfill randomness requests.
  • The owner can add or remove any address from the Caller Whitelist at any time.
  • The owner can update the airnode, endpoint, and sponsor wallet parameters used for AirnodeRRPV0 requests at any time.
Game Contract:
  • This contract is used for base functionality shared across all Games mentioned in the scope of this audit.
  • Upon creation, the Game's ID, multi-bet support, maximum multi-bet amount, required random numbers to be requested per roll, and supporting contract addresses are set.
  • To play a Game, a user specifies the number of rolls, bet amount, stake amount, referrer, and data relating to the specific Game.
  • The user must supply the platform's required "gas per roll" amount in the blockchain's native currency. This amount does not increase based on the number of user specified rolls.
  • This amount is transferred to the RNG contract's Sponsor wallet.
  • The user's bet amount must be larger than the Game's registered minimum bet size.
  • Once the bet is validated using the specific Game's validation functionality, a random number list request is made using the associated RNG contract. This uses its associated AirnodeRRPV0 contract for randomness.
  • The wager is then opened through the House contract, where payment is transferred.
  • Once the request is fulfilled, Game-specific functionality is triggered using the resulting numbers.
  • The owner can update the maximum multi-bet amount to any amount between 1 and 100 unless multi-bets are disabled.
  • The maximum bet size of a Game is equal to the Game's "edge" percentage of the ALP contract's USDT balance divided by the Game's maximum payout for the bet.
  • The team should ensure that the Game ID of a newly added Game matches its registered ID in the Console contract.
GameDice Contract:
  • This Game allows users to bet that a "rolled" number between 1 and 101 will be greater than the user's selected number between 2 and 98.
  • This contract uses the Game contract for its base functionality.
  • A user's betting number must be a number between 2 and 98 in order to be considered valid.
  • The user's payout is determined by their selected number, where if the user selects a larger number, they receive a larger payout.
  • The payout floor for a user is 1.01x their bet amount when selecting 2, and a ceiling of 49.5x their bet amount when betting 98.
  • A user can roll multiple times at once while multi-betting is enabled for the Game.
  • Once winnings have been determined, the wager is closed in the House contract where the user receives any payment and XP earned.
GameRouletteV3 Contract:
  • This Game implements roulette functionality, where users can split their bets between up to 38 numbers.
  • This contract uses the Game contract for its base functionality.
  • Users can split their total stake amount across any numbers between 0 and 37.
  • If the rolled number between 0 and 37 is equal to one of the numbers that the user bet on, their winnings are equal to their amount bet on the number multiplied by 36.
  • A user can roll multiple times at once while multi-betting is enabled for the Game.
  • Once winnings have been determined, the wager is closed in the House contract where the user receives any payment and XP earned.
GameSlide Contract:
  • This game allows users to make bets with various odds and payout options.
  • This contract uses the Game contract for its base functionality.
  • Users must choose a number between 0 and 6 to bet on.
  • A number between 1 and 105 is then rolled, where the user wins if the rolled number falls within the range corresponding to their selected option.
  • The windows and payouts are as follows, where all ranges are inclusive:
    • Option 0 wins a 2x payout if the rolled number falls between 1 and 50.
    • Option 1 wins a 4x payout if the rolled number falls between 51 and 75.
    • Option 2 wins a 10x payout if the rolled number falls between 76 and 85.
    • Option 3 wins a 20x payout if the rolled number falls between 86 and 90.
    • Option 4 wins a 25x payout if the rolled number falls between 91 and 94.
    • Option 5 wins a 50x payout if the rolled number falls between 95 and 96.
    • Option 6 wins a 100x payout if the rolled number is equal to 97.
  • Numbers 98 through 105 are not covered by any chosen option.
  • A user can roll multiple times at once while multi-betting is enabled for the Game.
  • Once winnings have been determined, the wager is closed in the House contract where the user receives any payment and XP earned.
GameWheel Contract:
  • This Game allows users to choose a number between 1 and 3 in order to earn various reward amounts.
  • A number from 1 to 104 is rolled, where the user wins various payouts if the rolled number falls within ranges corresponding to their selected option.
  • The windows and payouts are as follows, where all ranges are inclusive:
    • Option 0 wins a 1.6x payout if the rolled number falls between 91 and 100, or a 1.2x payout for numbers between 21 and 100.
    • Option 1 wins a 3x payout if the rolled number falls between 91 and 100, a 2x payout for numbers between 71 and 100, or a 1.5x payout for numbers between 51 and 100.
    • Option 2 wins a 10x payout if the rolled number falls between 91 and 100.
  • Numbers 101 through 104 are not covered by any chosen option.
  • A user can roll multiple times at once while multi-betting is enabled for the Game.
  • Once winnings have been determined, the wager is closed in the House contract where the user receives any payment and XP earned.
VestingContractA Contract:
  • This contract is used to distribute specified ALP and ARC token amounts to a predefined list of users.
  • Users can claim 31% of their ARC tokens immediately after deployment.
  • Once one week has passed from deployment, users can claim 23% of their ARC tokens and 30% of their ALP tokens.
  • Once two weeks have passed from deployment, users can claim 23% of their ARC tokens and 30% of their ALP tokens.
  • Once three weeks have passed from deployment, users can claim the remaining 23% of their ARC tokens and the remaining 40% of their ALP tokens.
  • The owner can withdraw any tokens or ETH from the contract at any time.
  • The owner can update users' ALP distribution amounts at any time.
  • The owner must ensure that this contract contains enough funds for distribution to users.
VestingContractB Contract:
  • This contract is used to distribute specified ARC amounts to a predefined list of users.
  • The ARC token vesting and distribution percentages are equal to those mentioned in the VestingContractA contract.
  • The owner can withdraw any tokens or ETH from the contract at any time.
  • The owner must ensure that this contract contains enough funds for distribution to users.

Audit Results

Vulnerability Category Notes Result
Arbitrary Jump/Storage Write N/A PASS
Centralization of Control
  • The owner and mentioned Whitelisted addresses have the permissions described above.
  • Any address registered as a "Game" can withdraw funds from the ALP contract using the House contract.
  • The owner can edit the attributes of an existing Game at any time.
  • The owner can withdraw any funds from the Vesting contracts at any time.
  • WARNING
    Compiler Issues N/A PASS
    Delegate Call to Untrusted Contract N/A PASS
    Dependence on Predictable Variables N/A PASS
    Ether/Token Theft N/A PASS
    Flash Loans N/A PASS
    Front Running N/A PASS
    Improper Events N/A PASS
    Improper Authorization Scheme N/A PASS
    Integer Over/Underflow N/A PASS
    Logical Issues N/A PASS
    Oracle Issues N/A PASS
    Outdated Compiler Version N/A PASS
    Race Conditions N/A PASS
    Reentrancy N/A PASS
    Signature Issues N/A PASS
    Sybil Attack N/A PASS
    Unbounded Loops N/A PASS
    Unused Code N/A PASS
    Overall Contract Safety   PASS

    Contract Source Summary and Visualizations

    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.