Logo:
Name: TITAN X
Ticker Symbol: TITANX
Network: Ethereum
Contract Address: 0xF19308F923582A6f7c465e5CE7a9Dc1BEC6665B1
Purpose: TITAN X is a first-of-its-kind fair launch crypto with 62%+ buy & burn, 28%+ real ETH yield and is designed to be an application layer for other projects to build on top of TITAN X via the Proof of Burn functions built into the contract. Community Owned. Fair Launch. Had no pre-sale, no ico, no fund raises of any kind, completely fair launched. Immutable, trustless & permissionless code.
Project URL: https://app.titanx.win/mine
Project social media: Telegram, Twitter, YouTube
Contract Source Code: Link
Audit(s): Akshay Srivastav, DeadrosesXYZ, GogoTheAuditor

REVIEWED BY: Elmyre

Preface:

This is a complete code review of the TITANX smart contract project based on the available code in https://etherscan.io/address/0xf19308f923582a6f7c465e5ce7a9dc1bec6665b1#code.

The code is fairly complex, so I would advise anyone that is reading this document to also look at other reviews and analysis of the contract! Some issues or security concerns might not be covered here due to my lack of knowledge and understanding, so getting a second opinion is a good thing to keep in mind! This review is based on the deployed version of the code.

Note: Other security review about the same contract:

  • https://github.com/GeorgeHNTR/portfolio/blob/main/reports/solo/TitanX-Security-Review.pdf
  • https://github.com/deadrosesxyz/audits/blob/main/TITANX-sep-2023.md
  • https://github.com/akshaysrivastav/audits/blob/main/private-audits/titanx/titanx-sep-2023.md

Overview:

The TITANX smart contract project was created to allow users to mint TITANX tokens using their Ethereum. The minting of the tokens can be delayed in time to increase the amount of tokens minted. The contract was created in such a way that early minters will always receive more tokens than late adopters. On every mint, the Genesis Wallet (0xe5e0C13133782d967B002B3400E6Ebea5d9814C0) receives 8% of the minted value!

Users can stake their minted or bought tokens to earn a portion of the ETH sent to the contract. These payouts are cyclical and occur at different time intervals (8, 28, 90, 369 and 888 days). Users are only eligible to claim them if they have active stakes before the claim day for each of them. Multiple claim cycles can be claimed in one go.

Burning liquid tokens, mints or stakes CAN also allow the users to receive a portion of that ETH via the Burn Payout cycle of 28 days (after it was activated). Burning tokens also increases the amount of tokens minted for a specific address up to 8%.

The ETH received for the mints is split in the following ways:

  • Incentive fee for calling the distribution method (0.33%).
  • Genesis wallet (3%).
  • Buy and Burn address (62% but admin key allows to drain it).
  • Staking Payout Cycles (28%).
  • Burn Payout Cycle (7% when activated, else goes to the Buy and Burn address).

The contract supports multiple burning function that can be called by external contracts in order to burn user liquid tokens, mints or stakes based on approvals. These provide the same burning “benefits” but with up to an extra 8% rebate and/or builders fee, on the amount burned. Burning tokens via the burnMint function mints 8% of the burnt tokens to the Genesis wallet and provide no rebate or builder fee.

Approval given for burning Stakes and Mints are not ID based, which means that the approved contracts can (and are incentivised to) always decide to burn the ones that provide the biggest amount of burning rewards!

The contract provides multiple public view functions (getters), to provide a transparent way for external parties/websites to query the state of the contract, inspect global stake statistics, and retrieve detailed information about a user’s stakes. It allows for easy integration with external applications or interfaces that may require access to stake-related data.

Code Review:

The project is split into multiple solidity files and smart contracts, so I’ll start my review by analysing the utility files constant.sol, enum.sol and calcFunctions.sol. I’ll then move on to review the abstract smart contracts OwnerInfo, BurnInfo, StakeInfo, MintInfo and GlobalInfo, which are inherited by the main smart contract TITANX and the two interfaces defined interfaces it uses, ITitanOnBurn and ITitanX. To end, I’ll review the TITANX contract itself and how it interacts and integrates with the previous reviewed code.

The @OppenZepplin dependencies used are beyond the scope of this review. Any information regarding them can be found at https://docs.openzeppelin.com/contracts/4.x.x/.

constant.sol

This is simply a file that contains all the useful constant variables used by all other contracts and functions. The goal is to have them all segregated here to avoid creating duplicated entries for the same variables throughout the rest of the code while also providing a centralized way to verify and set them.

I won’t go through each of them here since they are very self-explanatory, but I will refer to them and their values while explaining and reviewing the remainder of the code.

enum.sol

This file contains all the enumerators used in the remainder of the code.

I won’t go through each of them here since they are very self-explanatory, but I will refer to them and their values while explaining and reviewing the remainder of the code.

Note: Enumerators, also known as enums, are a way to create user-defined types with a finite set of named values. They are useful for variables that can only have one of a few distinct values. They provide a way to create more readable and self-explanatory code by assigning names to these values and are also more gas efficient in terms of storage, comparison, and readability costs.

calFunctions.sol

This file contains multiple public pure utility functions which are used by the project’s smart contracts.

Note: Pure functions are those that do not read from or modify the contract’s state. They only operate on the provided inputs and do not interact with the blockchain’s state. Pure functions are deterministic, meaning that for the same input parameters, they will always produce the same output.

View and pure functions do not require transactions to be executed on the blockchain! As a result, they do not consume any gas when called by external applications and are more gas efficient when called internally or by other contracts, making them more cost-effective when retrieving data or performing computations.

The existing functions and their logic are as follows:

  • getBatchMintLadderCount:
    • Calculates the total number of mints based on the specified parameters for a batch mint ladder:
      • minDay: The minimum length of the batch mint ladder.
      • maxDay: The maximum length of the batch mint ladder.
      • dayInterval: The number of days between each batch mint.
      • countPerInterval: The number of mints per each batch mint.
    • If “maxDay” is less than “minDay” the function will return 0.
    • If “maxDay” and “minDay” are the same, or “dayInterval” is more than the difference between the two, the code will behave as if only one batch mint is to be created and return the same value as “countPerInterval”.
  • getIncentiveFeePercent:
    • Will always return the number 33 (Should have probably been a constant for gas efficiency).
  • getBatchMintCost:
    • Calculates the total ETH cost of a batch mint based on the on the specified parameters:
      • mintPower: The mint power for the batch mint (value between 1 and 100).
      • count: The number of mints.
      • mintCost: The current contract ETH cost for a 100-power mint.
    • calculateMintReward:
      • Calculates the amount of TITANX tokens to be minted for a mint based on the received parameters:
        • mintPower: The mint power for the batch mint (value between 1 and 100).
        • numOfDays: The mint duration (value between 1 and 280).
        • mintableTitan: The current contract amount of TITANX mintable for a 100-power mint.
        • EAABonus: The user early adoption bonus.
        • burnAmpBonus: The user amplifier bonus accrued for previously burned tokens.
      • The base reward formula is equivalent to:
        • mintableTitan * mintPower / 100 * numOfDays ( 1 – (numOfDays – 1) * 11 / 10000)
      • This is different from what is stated on the Project’s documents. This means that the rewards are lower than expected for mints after day 1 but this is to account for the daily decrease in maximum daily mintable TITANX tokens per mint!
      • The bonus are applied linearly to the previously mentioned base reward.
    • calculateMintPowerBonus:
      • Calculate TITANX bonus amount based on the difference between the current global mint power and the user’s mint power:
        • mintPowerBonus: The user mint power bonus at the time of mint creation (see UserMintInfo).
        • mintPower: The user mint power (1 to 100) (see UserMintInfo).
        • gMintPower: The global mint power at the time of mint creation (see TRankInfo).
        • globalMintPower: The current global mint power (see MintInfo’s “s_globalMintPower”).
      • If “globalMintPower” is less than or equal to “gMintPower” the function will return 0.
    • getMaxMintDays:
      • Simply returns 280 which is the max mint days.
    • getMaxMintsPerWallet:
      • Simply returns 1000 which is the max mint per wallet.
    • calculateClaimMintPenalty:
      • Calculates the mint claim penalties based on the number of seconds that passed from the moment the user was able to claim their mint. It is important to note that the duration of the mint starts counting from the block’s timestamp where the mint creation was completed.
      • After a 7 days grace period, the penalties are as follows:
        • 1 extra day: 1% penalty.
        • 2 extra days: 3% penalty.
        • 3 extra days: 8% penalty.
        • 4 extra days: 17% penalty.
        • 5 extra days: 35% penalty.
        • 6 extra days: 72% penalty.
        • 7+ extra days: 99% penalty.
      • getMaxStakeLength:
        • Simply return 3500 which is the maximum staking length.
      • calculateShares:
        • Calculates and returns the amount of shares a user in entitled to when creating a TITANX stake based on the stake amount and duration and the current contract’s share rate. Uses the calculateShareBonus to calculate the bonuses to add. The last 18 digits are the decimal places.
      • calculateShareBonus:
        • Calculates the share bonuses based on the stake amount and duration.
        • Guarantees the bonuses do not overtake the maximum limits (8% for Bigger Pays More and 350% for longer pays more).
        • The return value needs to be divided by 1011 to obtain the correct bonus percentage in decimal.
      • calculateEndStakePenalty:
        • Calculates the end stake penalty in percantage based on the received parameters:
          • stakeStartTs: The stake’s start timestamp in seconds.
          • maturityTs: The stake’s maturity timestamp is seconds.
          • currentBlockTs: The current block’s timestamp in seconds.
          • action: The StakeAction being performed.
        • If the stake as reached maturity, a penalty of 1% will be applied for each day above the 7 day grace period, up to 99%
        • If Maturity wasn’t reached and the StakeAction being performed is a BURN, no penalty is applied.
        • Emergency end stakes before 50% maturity are not allowed and there is a flat 50% penalty for all stakes ended before maturity.
      • min (should actually be called max):
        • Function that receives two uint256 values and returns the biggest of them.
      • max (should actually be called min):
        • Function that receives two uint256 values and returns the smallest of them.

OwnerInfo

The OwnerInfo is smart contract responsible for providing ownership functionality. It provides a reusable pattern for ownership in other contracts. Contracts that inherit from OwnerInfo, like the TITANX smart contract, can use the onlyOwner modifier to restrict certain functions to only be callable by the owner. Additionally, the ownership can be transferred or renounced as needed.

  • Inheritance:
    • Context: OpenZeppelin’s Context contract, providing basic contextual information about the current transaction, including the sender of the transaction and its data. (@OpenZeppelin/openzeppelin-contracts/blob/v4.4.1/contracts/utils/Context.sol).
  • State Variables:
    • s_owner: Private variable representing the current’s owner address.

The Constructor, on deployment, initializes the contract’s owner as the deployment address.

  • Modifiers:
    • onlyOwner:
      • Restricts the execution of a function to the current owner address. Uses _checkOwner.
  • External Only Owner Functions:
    • renounceOwnership:
      • Allows the current owner to renounce ownership to the zero address, effectively removing the contracts ownership (“admin key”).
    • transferOwnership:
      • Allows the current owner change ownership to another address.
  • Internal Functions:
    • _checkOwner:
      • Internal function that actually checks if the caller is the owner and reverts the transaction if not.
    • _setOwner:
      • Sets the contract owner to the provided address.

The ownership is used to change the Buy and Burn contract address and enable poll rewards. If the owner address is compromised, the buy and burn address can be changed to any UniswapV3 pair contract address and then burn all Titan X tokens to steal the WETH liquidity from the corresponding pool.

The ownership can also be changed or (even sold) to a third-party address. This new address will then be in control of the of the Buy and Burn contract address and can perform the above-mentioned exploit.

GlobalInfo

GlobalInfo is an abstract smart contract inherited by the TITANX main contract. It includes various state variables, events, and functions for managing global information, performing daily updates, and handling the ETH payout cycles (8, 28, 90, 369 and 888 days) for TITANX stakes.

It also makes use of the aforementioned enum.sol and constants.sol.

  • Immutable Variables:
    • i_genesisTs:
      • Immutable variable with the timestamp when the contract was deployed.
  • Daily Update Variables:
    • s_currentContractDay:
      • Tracks the current day of the contract.
    • s_currentshareRate:
      • Represents the staking Share Rate. Increased daily 0.03% from 800 to 2800 (x1018).
    • s_currentMintCost:
      • The ETH Mint Cost for a 100-power miner. Increases daily by 0.08% from 0.2 ETH until 1 ETH.
    • s_currentMintableTitan:
      • Represents the daily Mintable amount of TITANX per full power mint. Decreases 0.35% daily from 8 million to 800 (x1018).
    • s_currentMintPowerBonus:
      • Represents the current Mint Power Bonus. Decreases 0.35% daily from 35 until 0.0035.
    • s_currentEAABonus:
      • Represents the Early Adoption Amplifier bonus that starts at 10% and drops to 0 in 350 days.
  • Payout Tracking Variables and Mappings:
    • s_isGlobalPayoutTriggered:
      • Tracks if, on a specific day, any of the cycle payouts (8, 28, 90, 369, 888) was triggered.
    • s_cyclePayouts:
      • Mapping that tracks the payout for each of the stacking payout cycles.
    • s_cyclePayoutIndex:
      • Mapping that tracks the current index for every staking payout cycle.
    • s_cyclePayoutPerShare:
      • Nested mapping that tracks the CycleRewardPerShare data for each staking payout cycle and index.
    • s_addressCycleToLastClaimIndex:
      • Nested mapping that tracks the UserCycleClaimIndex data for each user and staking payout cycle.
    • s_nextCyclePayoutDay:
      • Mapping that records the next payout day for each of the staking payout cycles.
  • Structs:
    • CycleRewardPerShare:
      • Holds information about a staking payout cycle’s day and ETH payout per share:
        • day: The day of the payout.
        • payoutPerShare: The amount of ETH to be paid per stacking share.
      • UserCycleClaimIndex:
        • Holds information regarding a user’s last payout reward claim index for cycleIndex, burnCycleIndex and sharesIndex so calculation starts from the following index.
          • cycleIndex: The user’s last stacking payout cycle index.
          • burnCycleIndex: The user’s last burn payout cycle index.
          • sharesIndex: The index associated with the last change in a user’s stacking shares (see s_addressIdToActiveShares from sol).
  • Events:
    • GlobalDailyUpdateStats:
      • Event emitted during daily updates, capturing various contract statistics. Can be triggered more than once daily if the function _dailyUpdate was not run every day.
  • Modifiers:
    • dailyUpdate:
      • Modifier used in multiple functions is sol and TITANX.sol to call the _dailyUpdate function before other functions are run.

The Constructor, on deployment, sets the genesis timestamp and the initial values for the daily update variables mentioned above.

  • Private and Internal Functions:
    • _dailyUpdate:
      • Internal function that calculates and update the “daily update variables” and reset payout trigger flags.
      • Emits the GlobalDailyUpdateStats event with the updated variable values.
    • _initFirstSharesCycleIndex:
      • Initializes the cycle indexes for a user (addresses) if they are making their first stake(s).
      • The cycle indexes for cycle days (8, 28, 90, 369, 888) will be the next cycle payout indexes (last payout index + 1) to make sure they are disqualified from past payouts.
    • _calculateCycleRewardPerShare:
      • Calculates the ETH payout per staking share for a specific cycle day and updates the associated state variables based on the received parameters:
        • cycleNo: The cycle to calculate rewards for (8, 28, 90, 369, 888).
        • Reward: The total ETH rewards to be paid on the associated cycle.
        • globalActiveShares: The total amount of staking shares in the ecosystem.
      • _updateUserClaimIndexes:
        • Updates user claim cycleIndex and shareIndex for a specific payout cycle if necessary.
      • _updateUserBurnCycleClaimIndex:
        • Updates user’s last claimed burn cycle index (burnIndex) for a specific 28-day burn cycle.
      • _setGlobalPayoutTriggered:
        • Sets the s_isGlobalPayoutTriggered variable to YES. This is reset on every _dailyUpdate
      • _setCyclePayoutPool:
        • Adds a reward amount to a specific staking payout cycle in the s_cyclePayouts
      • _setNextCyclePayoutDay:
        • Calculates and updates the next payout day for a specific payout cycle.
        • The formula is based on current contract day to make sure the value is correct if for some reason more than one payout cycle was skipped.
  • Public View Functions (Getters):
    • getCurrentBlockTimeStamp:
      • Returns the current block timestamp.
    • getCurrentContractDay:
      • Returns the current contract day.
    • getCurrentMintCost:
      • Returns the current mint cost.
    • getCurrentShareRate:
      • Returns the current share rate.
    • getCurrentMintableTitan:
      • Returns the current mintable amount of TITANX.
    • getCurrentMintPowerBonus:
      • Returns the current mint power bonus.
    • getCurrentEAABonus:
      • Returns the current Early Adoption Amplifier bonus.
    • getCurrentCycleIndex:
      • Returns the current cycle index for the specified cycle day.
    • getGlobalPayoutTriggered:
      • Returns whether a payout has been triggered successfully for any payout cycle.
    • getCyclePayoutPool:
      • Returns the distributed pool reward for the specified payout cycle day.
    • getPayoutPerShare:
      • Returns the calculated ETH payout per staking share and payout day for the specified payout cycle day and index.
    • getUserLastClaimIndex:
      • Returns the user’s last claimed shares payout indexes for the specified payout cycle.
    • getUserLastBurnClaimIndex:
      • Returns the user’s last claimed burn payout index for the specified burn cycle.
    • genesisTs:
      • Returns the contract deployment block timestamp.
    • getNextCyclePayoutDay:
      • Returns the next payout day for the specified payout cycle.

MintInfo

MintInfo is an abstract smart contract inherited by the TITANX main contract and contains variables and functions specifically designed for tracking TITANX token minting and associated statistics, bonus, and rewards.

It handles mint associated actions, namely mint creation and claiming and provides several view functions to retrieve all minting information. The emitted events allow external systems to track and respond to mint-related activities and the custom errors help provide clarity and specificity in handling exceptional situations during the minting and claiming processes in the contract.

It also makes use of the aforementioned calcFunctions.sol, enum.sol and constants.sol.

  • Custom Errors:
    • TitanX_InvalidMintLength:
      • Thrown if the provided mint length is 0 or exceeds 280 days when starting a mint.
    • TitanX_InvalidMintPower:
      • Thrown if the provided mint power is 0 or exceeds 100.
    • TitanX_NoMintExists:
      • Thrown if an attempt is made to claim or burn a mint that does not exist.
    • TitanX_MintHasClaimed:
      • Thrown if an attempt is made to claim a mint that has already been claimed.
    • TitanX_MintNotMature:
      • Thrown if an attempt is made to claim a mint that has not reached maturity.
    • TitanX_MintHasBurned:
      • Thrown in if an attempt is made to claim a mint that has already been burned.
  • State Variables and Mappings:
    • s_globalTRank:
      • Tracks the global tRank of the ecosystem (number of created mints).
    • s_globalMintClaim:
      • Tracks the total number of mints claimed.
    • s_globalMintBurn:
      • Tracks the total number of mints burned.
    • s_globalTitanMinting:
      • Tracks the total amount of TITANX mintable (not accounting for the Mint Power Bonus).
    • s_globalTitanMintPenalty:
      • Tracks the total amount of TITANX lost on mint penalties.
    • s_globalMintPower:
      • Tracks the global ecosystem mint power (sum of all mint power ever created).
    • s_addressMId:
      • Mapping of users and their latest mint ID.
    • s_addressMIdToTRankInfo:
      • Nested mapping that stores TRankInfo for a specific user and mint ID.
    • s_tRankToMintInfo:
      • Mapping that associates the tRank (mint number) with the UserMintInfo.
  • Structs:
    • UserMintInfo:
      • Holds information about a user’s mint:
        • mintPower: The mint power used when creating the mint.
        • numOfDays: The mint duration.
        • mintableTitan: The amount of TITANX tokens mintable when claiming the mint. Includes the Early Adoption Amplifier and Burn Amplifier Bonuses but NOT the Mint Power Bonus.
        • mintStartTs: The mint’s creation timestamp.
        • maturityTs: The mint’s maturity timestamp.
        • mintPowerBonus: The mint power bonus at time of creation (starts at 35 and drops by 0.35% per day until it reaches 0.0035).
        • EAABonus: Early adoption amplifier bonus at time of creation (starts at 10% and drops to 0 in 350 days).
        • mintedTitan: The amount of TITANX tokens minted (0 until the user claims).
        • mintCost: The amount of ETH the user paid to create the mint.
        • status: The mint status (ACTIVE, CLAIMED or BURNED).
      • TrankInfo:
        • Holds specific information associated with a user’s mint in s_addressMIdToTRankInfo.
          • tRank: The tRank associated with the user mint.
          • gMintPower: The global mint power when the user’s mint was created.
        • UserMint:
          • Structure that combines all mint related information for a specific user.
            • mID: The mint ID.
            • tRank: The mint tRank.
            • gMintPower: The global mint power at mint creation.
            • UserMintInfo: The struct with the same name.
  • Events:
    • MintStarted:
      • Emitted when a new mint is started with all the mint related information.
    • MintClaimed:
      • Emitted when a mint is claimed with all the mint related information.
  • Public View Functions (Getters):
    • getUserLatestMintId:
      • Returns the latest mint ID for a user.
    • getUserMintInfo:
      • Returns UserMintInfo for a specific user and mint ID.
    • getUserMints:
      • Returns an array of UserMint structures containing all information of a user’s mints.
    • getTotalMintBurn:
      • Returns the total number of mints burned.
    • getGlobalTRank:
      • Returns the current global tRank (number of mints ever created).
    • getGlobalMintPower:
      • Returns the current global mint power.
    • getTotalMintClaim:
      • Returns the total number of mints claimed.
    • getTotalActiveMints:
      • Returns the total number of active mints (all mints minus the claimed and burned ones).
    • getTotalMinting:
      • Returns the total amount of mintable TITANX tokens (excluding the Mint Power Bonus).
    • getTotalMintPenalty:
      • Returns the total amount of TITANX tokens lost on mint penalties.
  • Internal Functions:
    • _startMint:
      • Creates a new mint for a user based on the received parameters and updates all the relevant state variables.
      • Guarantees that the number of days and mint power are within the valid values, reverting the transaction, if necessary, with the appropriate error.
      • Uses the previously mentioned calculateMintReward function from sol.
    • _startBatchMint:
      • Initiates a batch of new mints all with the same parameters as each other.
      • Uses the _startMint function inside of a for loop to achieve this.
      • Updates the MintInfo global variables via the _updateMintStats
    • _startbatchMintLadder:
      • Initiates multiple batches of new mints with different lengths based on the received time intervals.
      • Uses the _startMint function inside of a for loop to achieve this.
      • All individual batches are created with the same number of mints.
      • Updates the MintInfo global variables via the _updateMintStats
    • _updateMintStats:
      • Updates the s_globalTRank, s_globalMintPower and s_globalTitanMinting based on the received parameters.
    • _claimMint:
      • Handles the claim of a user’s mint based on the received mint ID and MintAction (CLAIM or BURN).
      • If there is no mint associated with the received user/ID or the mint was already claimed or burned, the code will revert the transaction with the appropriate error.
      • Only allows claims after the mint reaches maturity.
      • Also allows mints to be burned at any time with no penalty.
      • Calculates the claim rewards via the _claculateClaimReward function and returns it.
      • The s_globalTitanMinting is reduced by the mint’s mintableTitan
    • _batchClaimMint:
      • Handles the claim of up to 100 of a user’s active mints.
      • Calculates the claim rewards for each mint, via the _claculateClaimReward function, and returns their sum.
      • The s_globalTitanMinting is reduced by the sum of all mint’s mintableTitan
    • _calculateClaimReward:
      • Calculates the final reward with bonuses and penalties for a mint claim or mint burn.
      • The Mint Power Bonus and Late Claim Penalties are only applied to mint claims. They are calculated via the calculateMintPowerBonus and calculateClaimMintPenalty functions from sol, respectively.
      • All necessary global variables are updated and the MintClaimed event is emitted.

BurnInfo

BurnInfo is an abstract smart contract inherited by the TITANX main contract and contains variables and functions specifically designed for tracking TITANX token burning and associated rewards. It is mainly used to calculate the 28 days ETH payout cycle and the user’s burn amplifier bonus when minting. It makes use of the aforementioned calcFunctions.sol, enum.sol and constants.sol.

  • State Variables and Mappings:
    • s_totalTitanBurned:
      • Variable that tracks the total amount of TITANX tokens burned across all users and projects.
    • s_userBurnAmount:
      • Mapping used to keep track of each user’s amount of burned TITANX tokens.
    • s_project_BurnAmount:
      • Mapping used to keep track of each project’s (smart contract) amount of burned TITANX tokens.
    • s_projectUser_BurnAmount:
      • A nested mapping that tracks the total TITANX burned by each user within a specific project.
    • s_cycle28TotalBurn:
      • Mapping of the total amount of TITANX burned per 28 days cycle.
    • s_userCycle28TotalBurn:
      • Mapping of the total amount of TITANX burned per user and per 28 days cycle.
    • s_cycle28BurnPayoutPerToken:
      • Mapping that stores the 28 days cycle ETH payout per amount of token burned to be distributed to users that burned their tokens.
  • Events:
    • TitanBurned:
      • Emitted when TITANX tokens are burned.
      • It includes information such as the user’s address, project address (if any), burn pool cycle index, burned amount, and the burn source (MINT, STAKE or LIQUID).
  • Public View Functions (Getters):
    • getUserBurnAmplifierBonus:
      • Calculates and returns the burn amplifier bonus in percentage with 18 decimals for a user.
      • The bonus is applied linearly and is capped at 8% for total of 80 billion or more tokens.
    • getTotalBurnTotal:
      • Returns the total amount of TITANX burned across all users and projects.
    • getUserBurnTotal:
      • Returns the total amount of TITANX burned by a specific user.
    • getProjectBurnTotal:
      • Returns the total amount of TITANX burned by a specific project (contract).
    • getProjectUserBurnTotal:
      • Returns the total amount of TITANX burned by a specific user within a specific project.
    • getCycleBurnTotal:
      • Returns the total amount of TITANX burned in a specific 28-day cycle.
    • getCycleBurnPayoutPerToken:
      • Returns the ETH payout per token burned distributed to users in a specified 28-day cycle.
  • Internal Functions:
    • _updateBurnAmount:
      • Function used to update the burn amounts for users, projects, and cycles based on the received parameters:
        • user: The address that belongs to the use that burned TITANX tokens.
        • project: The address of the smart contract that burned TITANX (optional).
        • amount: The amount of TITANX tokens burned.
        • cycleIndex: The current associated 28 days cycle index.
        • source: The source of the burned tokens (MINT, STAKE or LIQUID).
      • It also emits the TitanBurned
    • _calculateCycleBurnRewardPerToken:
      • This function calculates the burn reward per TITANX burned, based on the total reward and total Titan burned in the current cycle.
      • The calculation is a simple division with a scaling factor of 1018 for increased precision.
      • It stores the reward data in s_cycle28BurnPayoutPerToken.
    • _getUserCycleBurnTotal:
      • View function that returns the total amount of TITANX burned by a specific user within a specific cycle.

StakeInfo

StakeInfo is an abstract smart contract inherited by the TITANX main contract. It provides functionality to handle (TITANX) staking, including various data structures, mappings, and events to manage user stakes, calculate rewards and penalties, and different statistics.

Users can start, end, or burn stakes, to earn ETH rewards based on a percentage of the amount of ETH sent to the contract via TITANX minting. These payouts are handled in multiple cyclical cycles of 8, 28, 90, 369, and 888 days and are equally divided by the total amount of existing staking shares in the ecosystem. Users are attributed shares when they perform a stake based on the amount of TITANX tokens locked and length of the stake.

It also makes use of the aforementioned calcFunctions.sol, enum.sol and constants.sol.

  • Custom Errors:
    • TitanX_InvalidStakeLength:
      • Thrown when the provided stake length (number of days) is outside the allowed range (28 to 3500 days).
    • TitanX_RequireOneMinimumShare:
      • Thrown when the calculated number of shares for a stake is less than the required minimum (1 share).
    • TitanX_ExceedMaxAmountPerStake:
      • NOT USED.
    • TitanX_NoStakeExists:
      • Thrown when attempting to perform an operation (e.g., end or burn) on a stake that does not exist for the given user.
    • TitanX_StakeHasEnded:
      • Thrown when trying to end a stake that has already reached its maturity and has been ended.
    • TitanX_StakeNotMatured:
      • Thrown when attempting to end another user’s stake before it has matured (to avoid penalties).
    • TitanX_StakeHasBurned:
      • Thrown when trying to end a stake that has already been burned.
    • TitanX_MaxedWalletStakes:
      • Thrown when a user attempts to start a new stake, but the maximum number of allowed stakes per wallet has been reached (1000 stakes).
  • State Variables and Mappings:
    • s_globalStakeId:
      • The global stake ID for the last created stake in the ecosystem. Also serves as a counter for the number of stakes ever created.
    • s_globalShares:
      • Total number of stacking shares ever created in the ecosystem.
    • s_globalExpiredShares:
      • Total number of stacking shares ever expired in the ecosystem.
    • s_globalTitanStaked:
      • Current total amount of TITANX tokens staked.
    • s_globalStakePenalty:
      • Total amount of end stake penalties accumulated over time.
    • s_globalStakeEnd:
      • Total number of stakes ever ended.
    • s_globalStakeBurn:
      • Total number of stakes ever burned.
    • s_addressSId:
      • Mapping that tracks the stake ID for each user (address). Also serves as a counter for the number of stakes the user has made.
    • s_addressSIdToGlobalStakeId:
      • Nested mapping that associates a stake’s global ID with its user and stake ID.
    • s_globalStakeIdToStakeInfo:
      • Mapping that associates a stake’s UserStakeInfo to the global stake ID.
    • s_userSharesIndex:
      • Mapping that tracks the shares index for each user (address). The share index is increased every time the user’s amount of staking shares increases or decreases (based on starting or ending stakes). This is useful for s_addressIdToActiveShares
    • s_addressIdToActiveShares:
      • Nested mapping that associated a user’s UserActiveShares info with the it’s address and latest index.
      • This is used to guarantee that any new shares the user creates are only considered for payouts that were not yet triggered (see _calculateUserCycleReward from TITANX).
  • Structs:
    • UserStakeInfo:
      • Holds information about a user’s stake.
        • titanAmount: Amount of TITANX tokens staked.
        • Shares: Number of shares the stake has.
        • numOfDays: The duration of the stake.
        • stakeStartTs: The stake’s starting timestamp.
        • maturityTs: The stake’s maturity timestamp.
        • Status: The current stake status (ACTIVE, ENDED or BURNED).
      • UserStake:
        • Combines a stake’s global stake ID with its user stake ID and UserStakeInfo.
      • UserActiveShares:
        • Keeps track of a user’s number of active shares and the day it was updated.
  • Events:
    • StakeStarted:
      • Emitted when a user starts a new stake. Relevant information is also sent with the event.
    • StakeEnded:
      • Emitted when a stake is ended or burned. Relevant information is also sent with the event.
  • Internal and Private Functions:
    • _startStake:
      • Creates a new stake for a user, making sure all the staking parameters are within the valid values.
      • If the stake is created before a payout cycle being triggered for the current day, the user will still be eligible to receive the ETH payouts for it.
      • The user shares are calculated via the calculateShares function from sol.
      • Updates all necessary state variables and shares stats via the _updateSharesStats
      • Returns 1 if this is the first stake being created for the user and emits the StakeStarted
    • _endStake:
      • Allows users to END or BURN a stake, calculating and returning the TITANX staked principle minus any occurred penalties (using the _calculatePrinciple function).
      • Verifies if the stake exists and was not already ENDED or BURNED.
      • Allows to end stakes for others IF they already reached maturity (to avoid accruing fees)!
      • Updates all necessary state variables and shares stats via the _updateSharesStats
    • _updateSharesStats:
      • Updates share-related statistics, including the global shares, expired shares, amount of TITANX staked and the user’s active shares and update day.
    • _calculatePrinciple:
      • Calculates and returns a stake’s principle minus any applied penalties (if any).
      • Penalties are calculated via the calculateEndStakePenalty function from sol.
    • getUserActiveShares:
      • View function that returns the active stacking shares for a user at a specific shares index.
    • getUserActiveSharesDay:
      • View function that returns user’s update day for a specific stacking shares index (The day at which the active shares was updated for the specified index).
  • Public View Functions (Getters):
    • getGlobalShares:
      • Returns s_globalShares.
    • getGlobalExpiredShares:
      • Returns s_globalExpiredShares.
    • getGlobalActiveShares:
      • Returns the currently stacking active shares in the ecosystem (s_globalSharess_globalExpiredShares).
    • getTotalTitanStaked:
      • Returns s_globalTitanStaked.
    • getGlobalStakeId:
      • Returns s_globalStakeId.
    • getGlobalActiveStakes:
      • Returns the current number of active stakes (s_globalStakeId – s_globalStakeEnd).
    • getTotalStakeEnd:
      • Returns s_globalStakeEnd.
    • getTotalStakeBurn:
      • Returns s_globalStakeBurn.
    • getTotalStakePenalty:
      • Returns s_globalStakePenalty.
    • getUserLatestShareIndex:
      • Returns the latest share index for a specific user (see s_userSharesIndex).
    • getUserCurrentActiveShares:
      • Returns the current active shares for a specific user.
    • getUserStakeInfo:
      • Returns the UserStakeInfo data a specific user and stake ID.
    • getUserStakes:
      • Returns an array of UserStake containing all the information regarding a user’s stakes.

ITitanOnBurn

ITitanOnBurn is an interface designed to allow other contracts or systems to be notified or take specific actions whenever tokens are burned within the implementing contract. Contracts that implement this interface must provide a definition for its function.

It defines a single external function:

  • onBurn:
    • The purpose of this function is to handle actions or perform logic when tokens are burned (destroyed/removed) by a user. It received the following parameters:
      • user: The address of the user who initiated the burn.
      • Amount: The amount of tokens being burned.

Although this interface is not directly inherited by the TITANX smart contract, the contract uses it to validate which smart contracts are supported by the code’s burning functions.

Only those that implement this interface can call the burnTokensToPayAddress, burnTokens, burnStakeToPayAddress, burnStake and burnMint TITANX functions (like I assume Hyper and others will).

ITITANX

ITITANX is an interface defines functions related to the balance of TITANX tokens, retrieving the contract’s balance, minting LP tokens, and burning LP tokens. Other contracts that implement this interface must provide the actual logic for these functions.

It defines the following external function:

  • balanceOf:
    • This function is used to get the balance of TITANX tokens for the specified address (user).
  • getBalance:
    • This function is used to get the balance of the implementing contract. It seems to retrieve the contract’s own balance.
  • mintLPTokens:
    • This function is used to mint LP (Liquidity Provider) tokens.
  • burnLPTokens:
    • This function is used to burn (destroy/remove) LP (Liquidity Provider) tokens.

Although this interface is not directly inherited by the TITANX smart contract, the contract does indeed have these function. This means that this interface can be used by other smart contracts that interact with TITANX in order to get the necessary information or call the functions directly (for example, the BuyAndBurn contract).

TITANX


TITANX
is the main smart contract of the entire projects and either inherits or uses all the previously mentioned code.

Other than the getter function, it provides all the functions that external contracts or users need to call in order to interact with the project and use all the features it provides.

  • Inheritance:
    • ERC20: OpenZeppelin’s ERC20 contract, providing basic token functionality. (@OpenZeppelin/openzeppelin-contracts/blob/release-v4.8/contracts/token/ERC20/ERC20.sol).
    • ReentrancyGuard: OpenZeppelin’s ReentrancyGuard contract, make the nonReentrant modifier available, which can be applied to functions to make sure there are no nested calls to them that might became an attack vector in the code. (@OpenZeppelin/openzeppelin-contracts/blob/release-v4.8/contracts/security/ReentrancyGuard.sol).
    • GlobalInfo, MintInfo, StakeInfo, BurnInfo, OwnerInfo: The previously mentioned code, meaning that all explained logic and functions are available to be used by the TITANX smart contract.
  • Custom Errors:
    • TitanX_InvalidAmount:
      • Thrown when an invalid amount of tokens are received as token.
    • TitanX_InsufficientBalance:
      • Thrown when the amount TITANX a user has is insufficient for a specific action.
    • TitanX_NotSupportedContract:
      • Thrown when the contract trying to interact with the burn function does not implement the ITitanOnBurn
    • TitanX_InsufficientProtocolFees:
      • Thrown when the user has not enough ETH to mint TITANX tokens.
    • TitanX_FailedToSendAmount:
      • Thrown when the contract fails to send ETH to and user or contract.
    • TitanX_NotAllowed:
      • Thrown when the caller does not have permission to call a specific function.
    • TitanX_NoCycleRewardToClaim:
      • Thrown when there is no ETH reward available to be claimed for any cycle for a specific user.
    • TitanX_NoSharesExist:
      • Thrown when there are no staking shares in the ecosystem (no stake was done or is active).
    • TitanX_EmptyUndistributeFees:
      • Thrown when there is no ETH when the cycle payouts or the ETH distribution are called.
    • TitanX_InvalidBurnRewardPercent:
      • Thrown when the _burnBefore function is called with invalid values for the burn reward percentage (the sum cannot be bigger than 8%).
    • TitanX_InvalidBatchCount:
      • Thrown when a batch mint count is not within the valid limits (1 to 100).
    • TitanX_InvalidMintLadderInterval:
      • Thrown when a mint ladder tries to be created with a 0 mint interval.
    • TitanX_InvalidMintLadderRange:
      • Thrown when batchMintLadder is not called with valid minimum and maximum days.
    • TitanX_MaxedWalletMints:
      • Thrown when more than 1000 mints are tried to be created in a single wallet.
    • TitanX_LPTokensHasMinted:
      • Thrown if the LP tokens have already been minted and the mintLPTokens function is called again.
    • TitanX_InvalidAddress:
      • Thrown when a function tries to interact with the zero address received as a parameter.
    • TitanX_InsufficientBurnAllowance:
      • Thrown when a contract/project tries to burn more user mints or stakes than he approved of.
  • State Variables and Mappings:
    • s_genesisAddress:
      • Stores the genesis wallet address.
    • s_buyAndBurnAddress:
      • Stores the buy and burn contract address.
    • s_undistributedEth:
      • Tracks the ETH collected by the contract that was not already distributed.
    • s_cycleBurnReward:
      • Tracks the 28 days burn cycle ETH reward from the moment the ETH is distributed until the payout is triggered.
    • s_initialLPMinted:
      • Tracks if initial LP tokens have been minted.
    • s_burnPoolEnabled:
      • Tracks if the burn pool reward was already enabled.
    • s_allowanceBurnMints:
      • Nested mapping that stores the number of mint allowed to be burned by specific project for a user.
    • s_allowanceBurnStakes:
      • Nested mapping that stores the number of stakes allowed to be burned by specific project for a user.
  • Events:
    • ProtocolFeeReceived:
      • Emitted when a mint is created, and ETH was received by the contract.
    • ETHDistributed:
      • Emitted when the current undistributed ETH is distributed.
    • CyclePayoutTriggered:
      • Emitted when an ETH cycle payout is triggered.
    • RewardClaimed:
      • Emitted when a user claims and ETH payout from one of the payout cycles.
    • ApproveBurnStakes:
      • Emitted when a user approves stakes to be burned by another contract/address.
    • ApproveBurnMints:
      • Emitted when a user approves mints to be burned by another contract/address.

The Constructor, on deployment, initializes the contract with the name “TITAN X” and symbol “TITANX“. It also sets the genesis wallet (0xe5e0C13133782d967B002B3400E6Ebea5d9814C0) and buy and burn address (0x1393ad734EA3c52865b4B541cf049dafd25c23a5) based on the received parameters (if they are not the zero address). At the same time, the constructors for all classes it inherits are also run with the results previously mentioned for each of them.

  • Administrative Functions (Owner or Genesis only):
    • setBuyAndBurnContractAddress:
      • Allows the contract owner to change the buy and burn address.
      • The address can be changed to the contract address of any UniswapV3 pair. This means the owner can burn all TITANX tokens in that pool (via the burnLPTokens function) and steal the WETH liquidity.
    • enableBurnPoolReward:
      • Simply allows the owner to enable the 28-day cycle burn pool rewards.
    • setNewGenesisAddress:
      • Allows the current genesis address to set a new genesis address.
      • Doesn’t pose any security risk other than the fact that the unique rewards that only the genesis wallet gets can be funnelled to another wallet.
    • mintLPTokens:
      • Mints all initial TITANX Liquidity Provider tokens for the Buy and Burn address and sets s_initialLPMinted as true.
    • burnLPTokens:
      • Burns all the Buy and Burn contract’s TITANX tokens.
  • Mint Functions:
    • startMint (External payable):
      • Allows the user to create a new mint.
      • Guarantees the maximum mint per wallet is not exceeded (1000).
      • Uses getBatchMintLadderCount from calcFunctions and _startMint and _updateMintStats from MintInfo.
      • Processes the received ETH via the _protocolFees
    • batchMint (External Payable):
      • Similar to startMint but allows the user to create a batch mint.
      • Uses _startBatchMint from MintInfo.
    • batchMintLadder (External Payable):
      • Similar to startMint but allows the user to create laddered batches of mints.
      • Guarantees all time parameters received are within the valid boundaries.
      • Uses _startbatchMintLadder from MintInfo.
    • claimMint (External):
      • Allows users to claim a matured mint. It calls the _claimMint function from MintInfo.
      • The TITANX tokens are minted at the end by internally calling the _mintReward
    • batchClaimMint (External):
      • Allows users to claim up to 100 of their matured mints via the _batchClaimMint function from MintInfo.
      • The TITANX tokens are minted at the end by internally calling the _mintReward
    • _mintReward (Private):
      • Function that actually mints the TITANX tokens to the user’s address.
      • The number of tokens minted will depend on the returned reward amount calculated by the _claimMint or _batchClaimMint
      • It also mints 8% of the reward to the genesis address (not 1% as described)!
    • _protocolFees (Private):
      • Calculated the necessary ETH to successfully create a mint.
      • Any extra ETH received is sent back to the user and the rest is added to the contract’s undistributed ETH balance.
  • Stake Functions:
    • startStake (External):
      • Allows users to create a TITANX stake with a specified amount and duration.
      • The tokens are burned for the duration of the stake.
      • If it’s the first user’s stake, the necessary state variables are initialized.
      • Uses the _startStake function from StakeInfo.
    • endStake (External):
      • Allows a user to end its own stake based on the stake ID.
      • Uses the _endStake function from StakeInfo.
      • Mints back the “staked” tokens minus any penalties.
    • endStakeForOthers (External):
      • Similar to endStake but allows ending a matured stake on behalf of another user based on the stake ID.
  • Distribution and Payout Functions:
    • manualDailyUpdate (External):
      • Allows anyone to call dailyUpdate manually without running any other code.
    • distributeETH (External):
      • Distributes the collected ETH via the _distributeETH function based on a specific set of rules.
      • Sends a portion of the distributed ETH to the caller address (the incentive fee), the buy and burn address and the genesis wallet via with the _sendFunds
    • triggerPayouts (External):
      • Triggers the cycle payouts (basically sets the rewards to be claimed) for any cycle where the current contract’s day is equal or higher to the cycle’s payout day.
      • Only executes if there is at least one active staking share in the ecosystem.
      • Distributes the ETH using the _distributeETH function and then calls the _triggerCyclePayout function for every cycle (8, 28, 90, 369, 888).
      • If any payout is actually triggered, sets the global daily payout flag as true (check s_isGlobalPayoutTriggered from GlobalInfo).
      • Distributed funds are also sent to the necessary addresses with _sendFunds.
    • _triggerCyclePayout (Private):
      • Trigger the payout for the specified cycle if the current contract’s day is equal or higher to the cycle’s payout day and there is any reward to be distributed to stakers.
      • Calculates the payout per staking share with the _calculateCycleRewardPerShare
      • If the cycle is number 28 and there is a burn reward to be distributed, also calculates the burn cycle reward via the _calculateCycleBurnRewardPerToken from BurnInfo.
      • Emits the CyclePayoutTriggered event when successful.
    • _distributeETH (Private):
      • Defines how the amount of undistributed ETH will be allocated and makes the necessary calculations. Emits the ETHDistributed
      • The ETH is split as follows:
        • Incentive Fee (for calling the function): 0.33% (Deducted from the next calculations).
        • Buy and Burn: 62%.
        • Burn Cycle: 7% (If the burn pool is not enabled, goes to the Buy and Burn).
        • Genesis Wallet: 3%.
        • Staking Payouts: 28%
          • Cycle 8: 28%
          • Cycle 28: 28%
          • Cycle 90: 18%
          • Cycle 369: 18%
          • Cycle 888: 8%
        • Uses the _setCyclePayoutPool from GlobalInfo to updat the staking cycle payout rewards.
      • _sendFunds (Private):
        • Sends the contract’s accumulated ETH to the necessary wallets based on the _distributeETH calculations.
        • The funds are sent using the _sendViaCall function to the caller (incentive fee), the buy and burn address and genesis wallet.
      • _sendViaCall (Private):
        • Simply sends the specified amount of ETH to the received address using the call
        • Reverts the transaction if the sent failed.
      • claimUserAvailableETHPayouts (External):
        • Allows a user to claim all their available staking payouts up to this point (if any) by calling the _claimCyclePayout for each of the existing payout cycles.
        • Sends the appropriate amount of ETH to the user with the _sendViaCall function and emits the RewardClaimed
      • claimUserAvailableETHBurnPool (External):
        • Allows a user to claim all their available burn payouts up to this point (if any) by calling the _claimCyclePayout for cycle 28 with BURN PayoutClaim.
        • Sends the appropriate amount of ETH to the user with the _sendViaCall function and emits the RewardClaimed
      • _claimCyclePayout (Private):
        • Calculates the user rewards for the received cycle and PayoutClaim with the _calculateUserCycleReward
        • Updates the necessary claim indexes (see s_addressCycleToLastClaimIndex from GlobalInfo).
      • _calculateUserCycleReward (Private View):
        • Calculates all user staking rewards for the specified payout cycle from the last executed claim (see s_addressCycleToLastClaimIndex’s shareIndex).
        • Makes sure that, for the calculations, the correct number of shares are considered for each of the previously missing claims.
        • When called by claimUserAvailableETHBurnPool, calculates the user’s burn reward for the 28-day cycle from the last executed claim (see s_addressCycleToLastClaimIndex’s burnIndex).
        • For example, the function works as follows for the 8-day cycle:
          • If we are at day 65, never claimed, and had two stakes, one created on day 10 and another on day 39, both with 100 shares:
            • Wouldn’t be entitled to the 1st of the 8-day cycle claims.
            • Would be entitled to the 2nd, 3rd, and 4th of the 8-day cycle claims for 100 shares.
            • Would be entitled to the 5th, 6th, 7th, and 8th of the 8-day cycle claims for 200 shares.
  • Users Burn Functions:
    • userBurnMint (External):
      • Allows users to burn one of their mints based on mint ID.
      • Uses the _endStake function from StakeInfo and _updateBurnAmount function from BurnInfo.
    • userBurnStake (External):
      • Allows users to burn one of their stakes based on stake ID.
      • Uses the _claimMint function from MintInfo and _updateBurnAmount function from BurnInfo.
    • userBurnTokens (Public):
      • Allows users to burn their liquid TITANX tokens based on the specified amount (if not 0).
      • Uses the _updateBurnAmount function from BurnInfo.
  • Other Projects Burn Functions (callable by contracts that implement ITitanOnBurn):

 

Burn Liquid:

  • burnTokensToPayAddress (Public):
    • Burns a specified (non-zero) amount of a user’s TITANX via the _burnLiquidTitan
    • Only projects to which the user gave approval to are able to run it on behalf of him (see _spendAllowance from ERC20).
    • Only projects that implement ITitanOnBurn are able to successfully run it (see _burnBefore).
    • After the tokens are burned, the user’s burn records are updated via the _burnAfter function, and the user rebate and reward payback fees are calculated and minted for the expected addresses.
  • burnTokens (Public):
    • Same as burnTokensToPayAddress but the payback fee is paid to the caller (msg.sender).
  • _burnLiquidTitan (Private):
    • Implements all logic described in burnTokensToPayAddress verifying if the received amount is valid (more than 0 and the user has enough tokens) and by calling the _spendAllowance (from ERC20), _burnbefore, _burn (from ERC20) and _burnAfter

 

Burn Mints:

  • approveBurnMints (Public):
    • Function that allows the user to set allowances for another project/address to be able to burn a number of mints on its behalf.
    • The code does not allow the user to specify the mint to burn, only how many! This means that the project can only decide to burn the biggest mints!
    • Emits the ApproveBurnMints
  • burnMint (Public):
    • Allows other projects to burn mints on behalf of a user given a mint ID by calling the _burnMint function.
    • Only projects to which the user gave approval to are able to run it on behalf of him (see _spendAllowance).
    • Only projects that implement ITitanOnBurn are able to successfully run it (see _burnBefore).
    • Does not have any user rebate fee or reward payback fee but instead mint 8% of the burned mint to the Genesis address!
  • _burnMint (Private):
    • Implements all logic described in burnMint by calling the _spendBurnMintAllowance, _burnbefore, _claimMint, _mint (from ERC20) and _burnAfter
  • _spendBurnMintAllowance (Private):
    • Updates the user’s burn mint allowance for a specific project by reducing by one.
    • If the user approved an unlimited value, nothing it done.
    • If the current allowance is zero, the function reverts.

Burn Stakes:

  • approveBurnStakes (Public):
    • The same has approveBurnMints but for stakes. Also, does not allow to specify the stakes.
  • burnStakeToPayAddress (Public):
    • Similar to burnTokensToPayAddress but for stakes. Burn a specified stake via the _burnStake
    • Only projects to which the user gave approval to are able to run it on behalf of him (see _spendBurnStakeAllowance).
    • Also ends the stake via the _endStake function by setting it as burned.
  • burnStake (Public):
    • Same as burnStakeToPayAddress but the payback fee is paid to the caller (msg.sender).
  • _burnStake (Private):
    • Implements all logic described in burnStakeToPayAddress by calling the _ _spendBurnStakeAllowance, _burnbefore, _endStake (from StakInfo) and _burnAfter
  • _spendBurnStakeAllowance (Private):
    • Updates the user’s burn stake allowance for a specific project by reducing by one.
    • If the user approved an unlimited value, nothing it done.
    • If the current allowance is zero, the function reverts.

Common Functions:

  • _burnbefore (Private):
    • Is called by every burning function, be it for mints, stakes or liquid tokens.
    • Verifies if the reward payback and user rebate percentages together to now surpass the 8% limit.
    • Asserts if the project calling the function implements ITitanOnBurn.
  • _burnAfter (Private):
    • After any burn event (be it for mints, stakes or liquid tokens) the user’s burn records are updated, and the user rebate and reward payback fees are calculated and minted for the received addresses.

Note: All public and external functions which impact the ecosystem’s state have the dailyUpdate and nonReentrant modifiers applied to them. This is to guarantee that _dailyUpdate function is always called to keep contract state correctly updated before any interaction and that those same functions have re-entrancy protection!

  • Public View Functions (Getters):
    • getBalance:
      • Returns the contract’s ETH balance.
    • getUndistributedEth:
      • Gets the undistributed ETH balance, which tracks the protocol fees collected until they are distributed.
    • getUserETHClaimableTotal:
      • Calculates the total ETH payout claimable by a user across all cycles using _calculateUserCycleReward.
    • getUserBurnPoolETHClaimableTotal:
      • Gets the total claimable ETH rewards from the burn pool for the specified user.
    • getTotalPenalties:
      • Gets the total penalties accumulated from minting and staking.
    • getCycleBurnPool:
      • Gets the total reward amount in the burn pool.
    • getCurrentUserBurnCyclePercentage:
      • Calculates the current burn cycle percentage for the caller (msg.sender). It indicates the proportion of the user’s burned tokens relative to the total burned tokens in the current cycle.
      • Returns the percentage scaled by 1018.
    • getUserCycleBurnTotal:
      • Gets the total amount of TITANX tokens burned by the specified user in the current burn cycle.
    • isBurnPoolEnabled:
      • Checks if the burn pool reward is enabled.
    • allowanceBurnStakes:
      • Returns the remaining number of stakes that a spender contract/address is allowed to burn on behalf of a user.
    • allowanceBurnMints:
      • Returns the remaining number of mints that spender contract/address is allowed to burn on behalf of a user.

Conclusion & Security Concerns:

Based on all the reviewed code, I believe it is working as intended and no security concerns where found. Regardless, I believe some important considerations need to be mentioned:

  1. Contrary to what is written in the documentation, the Genesis wallet receives 8% of every minted value. This makes it so the Genesis wallet became the majority holder of the TITANX tokens very fast (Which it already is).
  2. The genesis wallet also receives 8% of the burned mints by third party contracts that use the burnMint function, contributing to A).
  3. The Buy and Burn address can be changed by the contract’s owner. This, together with the fact that the owner can burn all TITANX tokens held by the Buy and Burn address, makes it so the owner is able to drain all WETH held by it. This constitutes a liability for 62% of the ETH funds.
  4. When using 3rd party contracts for burning their mints or stakes, users must be extra careful when giving allowances, or they risk having more tokens/shares burnt than intended, since they are not ID based.
  5. The way the mint reward is calculated is not exactly what is described in the project’s documents, so rewards may be a bit lower than expected.

Other than these concerns, I believe the code was not well optimised gas wise, which might make transactions more expensive than they could be. This may prove to be a problem for future users of the project on Ethereum.

B9.xyz IS NOT OPTIMIZED TO BE VIEWED USING THE CURRENT RESOLUTION. IF YOU ARE USING A MOBILE PHONE, PLEASE ROTATE AND USE LANDSCAPE MODE.

Scroll to Top