Smart Contract Audit Report
REX is creating a new and unique ecosystem involving customizable Stakes which can be transferred, divided, listed on a DEX, and more. The project also includes auctions, lotteries, airdrops, and two tokens which provide benefits to holders.
For this audit, we reviewed the following contracts on the Binance Smart Chain Mainnet:
- MREX contract at 0x76837D56D1105bb493CDDbEFeDDf136e7c34f0c4.
- TREX contract at 0xA4d97197d7c2FaDf1C8e2226d03AAD8Ac1583b9C.
- RexToken contract at 0xb25583E5e2dB32b7FCbffe3f5e8E305C36157E54.
- RexDEX contract at 0x3D11149b23C90379295681e773864A5a5d2b0D90.
- RexAirdrop contract at 0xd65b42a7FeF267a2E79cbD3b3C8672C1ECE35828.
- RexDailyAuction contract at 0x0bA69EdF05AbE71028f82202Bb394a64C224dDF5.
A Medium finding and a low finding remain present; these have been acknowledged by the team. In addition, centralized aspects are present.
Date: May 4th, 2022.
Updated: May 9th, 2022 to reflect changes from commit f62ca4ce08b2ecbd56e9e4517b97f69b1c9a2430 to commit d8e22be92a443fa92038f55f6f734b5ba041744a.
Updated: June 17th, 2022 to reflect changes from commit d8e22be92a443fa92038f55f6f734b5ba041744a to commit bcd436458a5bd471b0729ff2e6f56311187c60dd.
Updated: September 16th, 2022 to include mainnet addresses.
Finding #1 - RexToken - High (Resolved)Description: The current Launch Day is set to Feb 22, 2022.
Risk/Impact: The project will start on an incorrect Day and various intended functionality within the project will be lost.
Recommendation: The Launch Day should be set to a future date.
Resolution: The Launch Day has been updated to Friday, June 30th, 2022 at 5:00 PM (GMT).
Finding #2 - RexDailyAuction - Medium (Resolved)Description: The Stake penalty for withdrawing rewards early in the _checkRewardAmountbyID() function is intended to be increased for Stakes which were created by users who received a share discount, but is incorrect. The Stake penalty is increased for discounted irrevocable Stakes when it should be increased for discounted non-irrevocable Stakes. Since users are not permitted to withdraw rewards early from irrevocable Stakes, this code will never be reached by an irrevocable Stake.
Risk/Impact: Users will not receive the proper Stake penalty for non-irrevocable Stakes and can potentially earn extra rewards by withdrawing their rewards and restaking.
Recommendation: The team should update the Stake penalty calculation to the following:
Resolution: The team has implemented the above recommendation.
sharesPenalty = _stakesShares( rewardAmount, remainingDays, stake.isIrrTrex == 2 ? globals.sharePrice.mul(70).div(100) : globals.sharePrice.mul(95).div(100)
Finding #3 - RexDailyAuction - MediumDescription: The pseudo-randomness functionality used to calculate Big Pay Day winners is weak and should be improved upon. In the current system, a number of winners are selected by selecting a number of indices from the beginning or the end of the eligible user list on even or odd days, respectively. On each external function call, two users are pseudo-randomly selected and have their positions in the list swapped in an attempt to randomize the users at the start and end of the list. If not enough swapping occurs, users may remain in winning or losing indices in the list, resulting in some users getting multiple Big Pay Days and others getting none.
Risk/Impact: Some users may unfairly be more likely to receive more Big Pay Days than other users.
Recommendation: The team should update this logic to improve randomness. One possible solution would be to randomly select a position in the list, and select users starting from the selected index. In the case where an index close to the end of the list is selected, the selected winners should wrap around to the front of the list. Note that if this change is implemented, contracts should be prevented from triggering Big Pay Days due to the ability to revert.
Update: The team has acknowledged and elected not to address this finding.
Finding #4 - MREX, TREX, RexToken, RexDailyAuction, RexDEX - Medium (Resolved)Description: The isContract() and _notContract() functions do not ensure that an address is not a contract. These functions are used to prevent contracts from buying MREX and TREX through their respective contracts, creating Stakes, sending initial liquidity through the RexDailyAuction contract, being used as a referral address in the RexDailyAuction contract, purchasing listed Stakes, being used as a referrer, and receiving TREX and REX airdrops. If these functions are called in a contract's constructor, it will not be recognized as a contract.
Risk/Impact: Contracts can be created to bypass these limitations by executing logic in the constructor. This could allow a contract to take a flashloan of MREX or TREX if liquidity pools are available in order to receive their benefits.
Recommendation: The team should instead implement the following code where applicable to check if the caller is a contract:
Update: The above recommendation has been implemented to disallow contracts from creating Stakes, donating BUSD to the RDA contract, and purchasing listed Stakes. It is still possible for contracts to bypass the other mentioned functionality.
require(msg.sender == tx.origin);
Resolution: The team has implemented the above recommendation.
Finding #5 - RexDailyAuction - LowDescription: The pseudo-randomness used to shuffle users and to add users to a pseudo-random index in the list relies on block attributes.
Risk/Impact: Malicious miners have the ability to manipulate block attributes to a certain extent in order to potentially produce more favorable results.
Recommendation: Chainlink can be used as a reliable source of randomness.
Update: The team has acknowledged and elected not to address this finding.
Finding #6 - TREX - Informational (Resolved)Description: The maxTotalSupply() function is incorrect. There is no maximum total supply of the token, as any amount of TREX can be airdropped and minted at any time. In addition, the formula to determine the current maximum supply is incorrect.
Risk/Impact: Contract functionality is not impacted; however, the maxTotalSupply() function will return an inaccurate value.
Recommendation: The team should limit the number of TREX which can be airdropped and correct the function's calculation or simply remove the function.
Resolution: The team has removed this function.
Finding #7 - TREX, RexDEX, RexDailyAuction - Informational (Resolved)Description: The following variables are not declared constant, but are never updated:
Recommendation: These variables should be declared constant for gas saving purposes.
TREX.DEVELOPMENT_ADDR, TREX.MARKETING_ADDR, TREX.priceRise, RexDEX.DEVELOPMENT_ADDR, RexDEX.MARKETING_ADDR, RexDEX.busd_address.
Resolution: The team has declared these variables constant.
Finding #8 - RexToken, RexDailyAuction - Informational (Resolved)Description: The following variables declared, but never used:
Recommendation: These variables can be removed for gas saving purposes.
RexDailyAuction.FACTORY, Declaration.MIN_STAKING_DAYS, Declaration.MAX_STAKING_DAYS.
Resolution: The team has removed these variables.
- As the contracts are implemented with SafeMath, they are safe from any possible overflows/underflows.
- The total and maximum supply of $MREX is 10,000.
- At the time of writing this report, there are 1,860 holders.
- 4.7% of the total supply is held by the MREX-BUSD PancakeSwap Pair contract.
- The next five holders own a cumulative 9.37% of the total supply.
- The Token Definer Role, granted to the deployer only, has the ability to transfer this contract's BNB balance to the Donate address at any time.
- This contract originally allowed users to purchase $MREX using BNB at a price of 0.1 BNB each; however, the maximum $MREX supply has been minted so users are no longer able to make purchases.
- No burn function exists, though the circulating supply can be decreased by sending tokens to the 0x..dead address.
- While users were not able to make an $MREX purchase which would result in them exceeding a balance of 20 tokens, users can still transfer and receive $MREX to exceed this amount.
- The owner was previously able to airdrop any number of TREX tokens to a list of addresses at any time, but has renounced ownership.
- A user can only claim their airdrop balance once.
- Users can purchase one TREX token at a time through this contract at a starting price of 500 BUSD.
- Contracts are not permitted to purchase TREX tokens.
- Each time 100 tokens are sold, the price is increased by 5 BUSD.
- If the contract's BUSD balance is less than the current BUSD price multiplied by number of unsold airdropped tokens, 80% of this BUSD is stored in the contract for airdrop sales, 10% is sent to the marketing address, and 10% is sent to the development address.
- If the contract balance is above this threshold, all of the BUSD is instead transferred to the marketing address.
- If the contract's BUSD balance is greater than or equal to the product of the current price and number of unsold tokens, the user's BUSD is transferred directly to the team's marketing address.
- A maximum of 40,000 tokens can be sold.
- Users who have been airdropped TREX tokens can sell them individually at the current price given the contract has a sufficient BUSD balance.
- Upon selling, the user's token is burned and they are transferred the appropriate BUSD amount.
- It is not guaranteed that this contract will have enough BUSD for users to sell their airdropped tokens.
- Users are intended to be able to sell 10% of their tokens upon deployment, increasing by 10% every 3 days.
- This contract allows users to "stake" tokens in order to earn a portion of each Day's generated REX.
- Certain functionality of the contract depends on the Day of the contract.
- The contract will begin on Day 0; Day 1 will begin once 24 hours have passed from the contract's specified "Launch Time", where Days will then be incremented as expected.
- Users can create a new Stake at any time with a specified amount, length, and description.
- They must also specify whether the Stake is "irrevocable" or not.
- The amount Staked is burned from the user.
- When creating a Stake directly through this contract, users must stake at least 0.000000000001 REX, and their stake time must be between 7 and 3,653 days, inclusive.
- Their Stake's share amount is based on the current share price.
- Users will be awarded bonus shares to their Stake based on the staking length. The bonus percentage per day increases by 5%/365 at each year mark.
- If a user is holding at least 1 TREX token, they will receive a 20% discount on the share price, thus increasing the number of shares their Stake is granted.
- Irrevocable stakes will be granted 25% additional shares, but cannot be ended early or have rewards withdrawn from them early.
- Contracts are not permitted to create Stakes.
- Users can end an Active Stake once its final Day is reached, or end the Stake early if their Stake is non-irrevocable.
- When ending, users will have their initially burned principal amount minted back to them plus any rewards earned, after any penalties are deducted.
- Rewards earned will come from a portion of the Day's generated amount from each Day staked based on their share amount.
- Users will have 1% of their reward amount subtracted per week after the grace period of 14 Days from their Stake's end time has passed.
- If withdrawing before 100% of the stake time has passed, users will pay a fee on their principal amount. This fee will decrease linearly from 90% on the Stake's first day to 10% on the Stakes final day before ending.
- Users can withdraw rewards from their Active Stake at any time if it is not irrevocable.
- The number of staking days to withdraw rewards from is specified.
- A penalty will be taken from the Stake's share total if withdrawing rewards before the Stake's end time. This will reduce the Stake's rewards earned in the future.
- The penalty amount is based on the time of withdrawal, not the number of withdraw days specified.
- A user can "transfer" their Active Stake to another user if rewards have not been withdrawn from it.
- Upon transferring, a new Stake is created for the recipient with the same attributes and a new ID.
- The sender's Stake is marked as transferred and can no longer be withdrawn from.
- Contracts are not permitted to transfer Stakes.
- A user can split their Stake at any time if rewards have not been withdrawn from it.
- The user can specify any amount of the original Stake to be split off into the new Stake as long as the resulting stake amounts are both greater than the minimum Stake amount of .000000000001 REX.
- The Stake's shares are split proportionally to the percentage of the split amount.
- A new ID is generated for the new Stake and is assigned to the user.
- Split Stakes cannot be split again.
- Users can use this contract to list an Active Stake on the DEX contract for any price greater than 5 REX tokens if it has not been withdrawn from.
- The duration of the listing must be between 1 and 30 days, inclusive.
- At least 10% of the Stake's duration must pass before it can be listed.
- Additionally, Stakes can only be listed once Day 111 is reached.
- While listed, the Stake is marked as Inactive and cannot be transferred, renamed, ended, or have rewards withdrawn from it.
- The DEX contract is used to create and track the Listing.
- Users can cancel their listing or purchase other Stake Listings through the DEX contract.
- A user can update any of their Active Stakes' descriptions at any time.
- The Token Definer Role was previously able to update the Airdrop, RDA, DEX, TREX token, and Pair contracts at any time.
- The Token Definer has renounced their Role to the 0x0 address at any time, preventing Token Definer-only functions from being called.
- The Airdrop and RDA contracts can mint any amount of tokens to any address at any time.
- This contract facilitates listing, purchasing, and canceling Stake Offers.
- When listing a Stake, a price in BUSD, offer duration, and Stake ID are specified.
- The Offer will then be created and marked as Active.
- While a Stake is listed, it will be marked as Inactive in the REX contract.
- Users can only use the list function by using the REX Contract's offerStake() function.
- A buyer can purchase any Active Offer within the duration from its creation time.
- If the buyer holds no MREX, an additional 2% of the Offer price is taken as a fee and split between a Marketing address and a Development address.
- No fee is taken if the buyer holds MREX.
- The offer price is transferred from the buyer to the seller of the Stake.
- A new Stake is then created from the REX contract with the same attributes of the seller's Stake of the listed ID, and the seller's Stake is closed.
- Contracts are not permitted to purchase listed Stakes.
- A seller can also cancel their Offer at any time which marks it as inactive and restores the Stake as Active through the REX contract.
- The contract's creator is granted the Token Definer Role upon deployment.
- The Token Definer Role can grant Airdrops to users at any time.
- When claiming, users will be minted their claimable amount in REX tokens.
- Users can also elect to directly stake their claimable amount, which will create a new irrevocable Stake in the REX contract with the user's specified duration and with a description of "🤴 AIRDROP".
- A user's claimable amount must be greater than 0.000000000001 REX in order to stake.
- Users will earn a bonus percentage to their amount staked based on their staking duration.
- The bonus percentage increases linearly from 10% at 30 days to a maximum of 50% at 600 days.
- The specified staking period must be between 30 and 3,653 days, inclusive.
- Users can only claim or stake their Airdrops between Day 2 and Day 222, inclusive.
- The current Day is determined by the associated REX token contract.
- The Token Definer was previously able to update the REX token contract at any time.
- The Token Definer has renounced their Role to the 0x0 address, preventing Token Definer-only functions from being called.
- Users can send BUSD to this contract before Day 1 to be added as initial REX/BUSD liquidity in order to receive claimable LP tokens in the future.
- Users do not have to supply REX tokens to pair with the BUSD; they will be minted and paired by the contract.
- The BUSD must be sent in increments of 100, up to a maximum total of 500,000 BUSD per address.
- The total BUSD sent for initial liquidity is capped at 10 million.
- The user's share of the total resulting LP tokens is proportional to their share of the total amount deposited for initial liquidity.
- On Day 222, 10% of the user's claimable LP tokens can be withdrawn. The remaining amount will vest in increments of 10% every 30 days after.
- Users can "donate" BUSD to this contract once per day between Day 1 and Day 222 in order to earn shares of this contract's daily generated REX and to potentially become eligible to participate in "Big Pay Days".
- Contracts are not permitted to donate BUSD or provide initial liquidity.
- The daily amount of REX generated decreases each Day.
- The donation amount must be at least 100 BUSD and can reach a maximum of 50,000 BUSD, or 100,000 if they hold at least 1 TREX token.
- A 2% bonus is added on to the share amount for each MREX token held by the user, up to a limit of 5 MREX.
- A referral address can be specified, reserving an additional 10% share bonus to the donator and reserving a 10% share bonus to the referrer.
- No bonus is granted if the donator's own address or the 0x0 address is used as the referrer.
- Of the BUSD amount, 75% is reserved for BUSD liquidity, 5% is transferred to a marketing address, and 5% is sent to a development address.
- The referrer is also granted up to 5% of the BUSD based on the referrer's MREX token balance, where each MREX token held will entitle them to 1% of the BUSD.
- If the referrer does not hold at least 5 MREX, the remainder will be reserved for the Treasury.
- The 5% referral amount is instead reserved for the Treasury if the 0x0 address or the user's own address is specified as the referrer.
- The remaining 10% is reserved for liquidity adds.
- The referrer can claim any BUSD rewards earned until Day 251, where it will be forfeited.
- The referrer can claim their REX rewards from the Day after they are granted it until Day 251, where it will be forfeited.
- The amount of REX minted to the user is dependent on their share amount multiplied by the Day's ratio, which is the ratio of the Day's generated REX amount to Day's total shares.
- Any time an external function is called, the contract will check if any REX Days need to be processed. A Day is only processed once one hour into the next Day is reached.
- If a Day needs to be processed, the caller will have a portion of their transaction costs refunded to them if the contract has a sufficient balance.
- On Day 1, up to 100,000 of the BUSD provided as initial liquidity is paired with minted REX at a ratio of 7,143 REX per BUSD.
- The resulting LP tokens are stored in this contract until they can be withdrawn by contributors.
- Excess BUSD, if any, is added with minted REX as liquidity on each transaction over the duration between Day 3 and 203, adding to the contract's LP token total.
- When processing transactions between Day 2 and 250, a portion of the reserved BUSD for liquidity from donations is paired with minted REX tokens and is also added as liquidity. These resulting LP tokens are sent to the 0x0 address.
- The maximum total amount of BUSD for liquidity adds per transaction is capped at 1000. Up to 500 of this BUSD comes from excess BUSD, and the remainder from reserved BUSD.
- Contracts cannot call any functions that trigger liquidity adds.
- Users can claim irrevocable Stakes for Days in which they have donated BUSD.
- Users can only claim Stakes between Days 2 and Day 259, inclusive.
- The user will specify the Stake's duration, which must be between 222 and 3,653 Days, inclusive.
- The Stake's amount is equal to their unclaimed portion of each Day's total shares multiplied by the Day's ratio.
- The Stake's description will be set to "🤴 AUCTION".
- Once a user has claimed a Stake, they become eligible for Big Pay Days.
- A user can also permanently forfeit their eligibility to participate in Big Pay Days and claim their REX rewards immediately instead of through a Stake. These claims can also only occur between Day 2 and Day 259.
- Big Pay Days occur each day between Day 2 and 250, where the total amount in the BUSD Pool is split and distributed pseudo-randomly to up to 400 eligible users.
- Users can earn up to their total amount of BUSD contributed back once per Day. This amount could be less if there is not a sufficient amount of BUSD in the pool.
- A user can also only claim a maximum of 2% of the total pool amount as a whale prevention mechanism.
- If over 50,000 BUSD remains in the pool, any user can trigger another Big Pay to occur, split instead between 222 users.
- Users must claim any Big Pay Day rewards before Day 251 in order to have the BUSD transferred to them.
- After Day 251 and before Day 258, the Treasury is opened and all remaining BUSD in the contract is distributed proportionally to the donors who have not received a Big Pay Day.
- The BUSD includes any BUSD remaining in the BUSD Pool, any BUSD reserved for the Treasury, and any BUSD from unclaimed Big Pay Days and referrals.
- On Day 259, all remaining BUSD and BNB are transferred to the Marketing address.
- The Gas Refunder Role can transfer any token to the Market address after Day 259, excluding LP tokens.
- The Token Definer Role was previously able to update the REX, TREX, and Pair addresses at any time.
- The Token Definer has renounced its role.
|Arbitrary Jump/Storage Write
|Centralization of Control
|Delegate Call to Untrusted Contract
|Dependence on Predictable Variables
|Block attributes used for the Daily Auction's Big Pay Days can be manipulated by miners to achieve more favorable results.
|Improper Authorization Scheme
|As described in Finding #3, the current randomness functionality could result in some users having a higher chance of receiving Big Pay Days.
|Outdated Compiler Version
|Overall Contract Safety
Contract Source Summary and Visualizations
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.