Axion - Smart Contract Audit Report

Summary

Axion Audit Report Axion is an ethical, community-driven cryptocurrency that rewards long-term investing with high-yield interest rates and weekly dividends.

We initially reviewed Axion’s Auction and Staking contracts at commit 3e6e1a83b440b0e6629dc455667ecb71567455c3 on GitHub. We later updated our findings after the implementation of a series of recommendations, based on commit ae162c056db394a91b89b097b5314e2e705a34f7. The mainnet addresses as of the date of this report are listed below. Please note we have not reviewed other parts of the Axion suite of smart contracts.

  • Auction (Upgradable Proxy): 0xCc9bEC9EE79259C7757a24C288fB5CEAbC9ca40B
  • Auction (Current Implementation): 0x8cf5f583d6d35488220f91b9b388e53ba38bbd9d
  • Staking (Upgradable Proxy): 0x1920d646574E097c2c487F69F40814F95d45bf8C
  • Staking (Current Implementation): 0xf6b44397c8756ed95ff138554e5d6349c62bf885


    • Notes on the Staking Contract:
    • Token holders can elect to time-lock their Axion tokens into the staking contract in exchange for ‘shares’, representing a certificate of deposit and a right to future rewards.
    • Users select the lockup period for their tokens when depositing their stake, with a maximum duration of slightly over 15 years.
    • The amount of shares and rewards a user recieves for their stake depends upon the staker’s staked amount of AXN, the total amount staked by all users, the start date of the stake, and the end date of the stake. The base minimum rate of return is 8% APY.
    • This calculation also features a share factor that multiplies the amount of shares by a certain value depending on the stake duration: 0-5 years: share factor = 1x; 5-10 years: share factor = 2x; 10-15 years: share factor = 3x. This implies that a user's stake will double after 5 years, triple after 10 years, and quadruple after 15 years.
    • Users also have the ability to utilize their existing Axion V1 stakes (if applicable) to earn rewards in the new staking contract.
    • Penalties may be incurred by stakers who unstake earlier than their commitment, or who fail to claim their rewards in a timely manner. Penalties have been temporarily suppressed for the launch of the platform.

    • Notes on the Auction Contract:
    • Outside of traditional DEXs, Axion Token can be acquired by participating in one of the “Daily Auctions” and spending ETH as a bid for a portion of the Auction pool.
    • The price of the tokens to be sold at auction are dynamically determined by the amount of tokens for sale and the total amount of ETH that has be deposited for the auction on that paticular day.
    • A price floor exists for tokens sold in the pool. The minimum price is determined by calculating the time-weighted average price (TWAP) of the token on Uniswap; which is flash loan resistant.
    • Auction winnings are automatically staked into the staking contract for a minimum of 60 days. Any early unstaking penalties would be sent back to auction.
    • The Auction has two different modes - Normal and VCA (Venture Capital).
    • In the VCA Auction, users can contribute ETH which will be swapped into the token of the day and to provide dividend rewards for stakers.
    • In the normal auction, users contribute ETH which is swapped into Axion (a buyback), which increases the price. The Axion tokens bought are sent to the staking contract to provide rewards to stakers.
    • The Axion tokens sold in the Daily Auction are sourced from penalties users incur for unstaking early, or not claiming rewards in a timely manner.
    • When the manager sets the token(s) of the day, they also set percentage(s) of each token along with it and this proportion is used in calculating prices when bidding in the VCA.

    • General Notes:
    • The project’s GitHub contain a series of passing test cases related to the contracts in scope for this review.
    • Axion lead developer/maintainer has worked extensively with our team to properly implement our security recommendations.
    • We have worked with the team to check the addresses assigned to each role on the live contracts to ensure only the proper addresses have control.
    • Proper structuring of logic to prevent re-entrancy attacks.
    • Utilization of SafeMath to prevent overflows.


    • Audit Findings Summary:
    • No security issues from outside attackers were identified.
    • Ensure trust in the team as they have notable power in the ecosystem. The team's cooperation through the audit process and focus on admin control makes us belive they are trustworthy.
    • Date: March 10th, 2021

    External Threats - Audit Results

    Vulnerability CategoryNotesResult
    Arbitrary Storage WriteN/APASS
    Arbitrary JumpN/APASS
    Delegate Call to Untrusted ContractN/APASS
    Dependence on Predictable VariablesN/APASS
    Deprecated OpcodesN/APASS
    Ether ThiefN/APASS
    ExceptionsN/APASS
    External CallsN/APASS
    Flash LoansN/APASS
    Integer Over/UnderflowN/APASS
    Multiple SendsN/APASS
    OraclesN/APASS
    SuicideN/APASS
    State Change External CallsN/APASS
    Unchecked RetvalN/APASS
    User Supplied AssertionN/APASS
    Critical Solidity CompilerN/APASS
    Overall Contract Safety PASS

    Auction Contract

    Smart Contract Graph

    Contract Inheritance

    
     ($) = payable function
     # = non-constant function
     
     Int = Internal
     Ext = External
     Pub = Public
     
     + [Lib] EnumerableSetUpgradeable 
        - [Prv] _add #
        - [Prv] _remove #
        - [Prv] _contains
        - [Prv] _length
        - [Prv] _at
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
    
     + [Lib] AddressUpgradeable 
        - [Int] isContract
        - [Int] sendValue #
        - [Int] functionCall #
        - [Int] functionCall #
        - [Int] functionCallWithValue #
        - [Int] functionCallWithValue #
        - [Int] functionStaticCall
        - [Int] functionStaticCall
        - [Prv] _verifyCallResult
    
     +  Initializable 
        - [Prv] _isConstructor
    
     +  ContextUpgradeable (Initializable)
        - [Int] __Context_init #
           - modifiers: initializer
        - [Int] __Context_init_unchained #
           - modifiers: initializer
        - [Int] _msgSender
        - [Int] _msgData
    
     +  AccessControlUpgradeable (Initializable, ContextUpgradeable)
        - [Int] __AccessControl_init #
           - modifiers: initializer
        - [Int] __AccessControl_init_unchained #
           - modifiers: initializer
        - [Pub] hasRole
        - [Pub] getRoleMemberCount
        - [Pub] getRoleMember
        - [Pub] getRoleAdmin
        - [Pub] grantRole #
        - [Pub] revokeRole #
        - [Pub] renounceRole #
        - [Int] _setupRole #
        - [Int] _setRoleAdmin #
        - [Prv] _grantRole #
        - [Prv] _revokeRole #
    
     + [Lib] SafeMathUpgradeable 
        - [Int] add
        - [Int] sub
        - [Int] sub
        - [Int] mul
        - [Int] div
        - [Int] div
        - [Int] mod
        - [Int] mod
    
     + [Int] IUniswapV2Router01 
        - [Ext] factory
        - [Ext] WETH
        - [Ext] addLiquidity #
        - [Ext] addLiquidityETH ($)
        - [Ext] removeLiquidity #
        - [Ext] removeLiquidityETH #
        - [Ext] removeLiquidityWithPermit #
        - [Ext] removeLiquidityETHWithPermit #
        - [Ext] swapExactTokensForTokens #
        - [Ext] swapTokensForExactTokens #
        - [Ext] swapExactETHForTokens ($)
        - [Ext] swapTokensForExactETH #
        - [Ext] swapExactTokensForETH #
        - [Ext] swapETHForExactTokens ($)
        - [Ext] quote
        - [Ext] getAmountOut
        - [Ext] getAmountIn
        - [Ext] getAmountsOut
        - [Ext] getAmountsIn
    
     + [Int] IUniswapV2Router02 (IUniswapV2Router01)
        - [Ext] removeLiquidityETHSupportingFeeOnTransferTokens #
        - [Ext] removeLiquidityETHWithPermitSupportingFeeOnTransferTokens #
        - [Ext] swapExactTokensForTokensSupportingFeeOnTransferTokens #
        - [Ext] swapExactETHForTokensSupportingFeeOnTransferTokens ($)
        - [Ext] swapExactTokensForETHSupportingFeeOnTransferTokens #
    
     + [Int] IToken 
        - [Ext] mint #
        - [Ext] burn #
    
     + [Int] IAuction 
        - [Ext] callIncomeDailyTokensTrigger #
        - [Ext] callIncomeWeeklyTokensTrigger #
        - [Ext] addReservesToAuction #
    
     + [Int] IStaking 
        - [Ext] externalStake #
        - [Ext] updateTokenPricePerShare ($)
        - [Ext] addDivToken #
    
     + [Int] IAuctionV1 
        - [Ext] auctionBetOf #
    
     +  Auction (IAuction, Initializable, AccessControlUpgradeable)
        - [Int] _updatePrice #
        - [Prv] _swapEthForToken #
        - [Ext] bid ($)
        - [Int] bidInternal #
        - [Int] ventureBid #
        - [Int] bidCommon #
        - [Int] getUniswapLastPrice
        - [Int] getUniswapMiddlePriceForDays
        - [Ext] withdraw #
        - [Ext] withdrawV1 #
        - [Int] withdrawInternal #
        - [Ext] callIncomeDailyTokensTrigger #
           - modifiers: onlyCaller
        - [Ext] addReservesToAuction #
           - modifiers: onlyCaller
        - [Ext] callIncomeWeeklyTokensTrigger #
           - modifiers: onlyCaller
        - [Pub] calculateNearestWeeklyAuction
        - [Int] getCurrentDay
        - [Pub] getCurrentAuctionId
        - [Pub] calculateStepsFromStart
        - [Int] _calculatePayoutWithUniswap
        - [Int] _calculatePayout
        - [Prv] _calculateRecipientAndUniswapAmountsToSend #
        - [Prv] _calculateRefAndUserAmountsToMint
        - [Int] _saveAuctionData #
        - [Pub] initialize #
           - modifiers: initializer
        - [Ext] setReferrerPercentage #
           - modifiers: onlyManager
        - [Ext] setReferredPercentage #
           - modifiers: onlyManager
        - [Ext] setReferralsOn #
           - modifiers: onlyManager
        - [Ext] setAutoStakeDays #
           - modifiers: onlyManager
        - [Ext] setVentureAutoStakeDays #
           - modifiers: onlyManager
        - [Ext] setDiscountPercent #
           - modifiers: onlyManager
        - [Ext] setPremiumPercent #
           - modifiers: onlyManager
        - [Ext] setMiddlePriceDays #
           - modifiers: onlyManager
        - [Ext] setupRole #
           - modifiers: onlyManager
        - [Ext] setAuctionMode #
           - modifiers: onlyManager
        - [Ext] setTokensOfDay #
           - modifiers: onlyManager
        - [Ext] auctionsOf_
        - [Ext] getAuctionModes
        - [Ext] getTokensOfDay
        - [Ext] getVentureAutoStakeDays
    							

    Staking Contract

    Smart Contract Graph

    Contract Inheritance

    
     ($) = payable function
     # = non-constant function
     
     Int = Internal
     Ext = External
     Pub = Public
     
     + [Lib] SafeMathUpgradeable 
        - [Int] add
        - [Int] sub
        - [Int] sub
        - [Int] mul
        - [Int] div
        - [Int] div
        - [Int] mod
        - [Int] mod
    
     + [Lib] MathUpgradeable 
        - [Int] max
        - [Int] min
        - [Int] average
    
     + [Lib] EnumerableSetUpgradeable 
        - [Prv] _add #
        - [Prv] _remove #
        - [Prv] _contains
        - [Prv] _length
        - [Prv] _at
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
    
     + [Lib] AddressUpgradeable 
        - [Int] isContract
        - [Int] sendValue #
        - [Int] functionCall #
        - [Int] functionCall #
        - [Int] functionCallWithValue #
        - [Int] functionCallWithValue #
        - [Int] functionStaticCall
        - [Int] functionStaticCall
        - [Prv] _verifyCallResult
    
     +  Initializable 
        - [Prv] _isConstructor
    
     +  ContextUpgradeable (Initializable)
        - [Int] __Context_init #
           - modifiers: initializer
        - [Int] __Context_init_unchained #
           - modifiers: initializer
        - [Int] _msgSender
        - [Int] _msgData
    
     +  AccessControlUpgradeable (Initializable, ContextUpgradeable)
        - [Int] __AccessControl_init #
           - modifiers: initializer
        - [Int] __AccessControl_init_unchained #
           - modifiers: initializer
        - [Pub] hasRole
        - [Pub] getRoleMemberCount
        - [Pub] getRoleMember
        - [Pub] getRoleAdmin
        - [Pub] grantRole #
        - [Pub] revokeRole #
        - [Pub] renounceRole #
        - [Int] _setupRole #
        - [Int] _setRoleAdmin #
        - [Prv] _grantRole #
        - [Prv] _revokeRole #
    
     + [Int] IERC20Upgradeable 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     + [Int] IToken 
        - [Ext] mint #
        - [Ext] burn #
    
     + [Int] IAuction 
        - [Ext] callIncomeDailyTokensTrigger #
        - [Ext] callIncomeWeeklyTokensTrigger #
        - [Ext] addReservesToAuction #
    
     + [Int] IStaking 
        - [Ext] externalStake #
        - [Ext] updateTokenPricePerShare ($)
        - [Ext] addDivToken #
    
     + [Int] ISubBalances 
        - [Ext] callIncomeStakerTrigger #
        - [Ext] callOutcomeStakerTrigger #
        - [Ext] callOutcomeStakerTriggerV1 #
        - [Ext] createMaxShareSession #
        - [Ext] createMaxShareSessionV1 #
    
     + [Int] IStakingV1 
        - [Ext] sessionDataOf
        - [Ext] sessionsOf_
    
     +  Staking (IStaking, Initializable, AccessControlUpgradeable)
        - [Pub] initialize #
           - modifiers: initializer
        - [Ext] sessionsOf_
        - [Ext] stake #
           - modifiers: pausable
        - [Ext] externalStake #
           - modifiers: onlyExternalStaker,pausable
        - [Int] stakeInternal #
        - [Int] _initPayout #
        - [Pub] calculateStakingInterest
        - [Ext] unstake #
           - modifiers: pausable
        - [Ext] unstakeV1 #
           - modifiers: pausable
        - [Pub] getAmountOutAndPenalty
        - [Pub] makePayout #
        - [Ext] readPayout
        - [Int] _getPayout #
        - [Int] _getStakersSharesAmount
        - [Int] _getShareRate
        - [Ext] restake #
           - modifiers: pausable
        - [Ext] restakeV1 #
           - modifiers: pausable
        - [Int] unstakeInternal #
        - [Int] unstakeV1Internal #
        - [Int] unstakeInternalCommon #
        - [Int] stakeInternalCommon #
        - [Ext] withdrawDivToken #
        - [Ext] getTokenInterestEarned
        - [Int] getTokenInterestEarnedInternal
        - [Int] rebalance #
        - [Int] setTotalSharesOfAccountInternal #
           - modifiers: pausable
        - [Ext] setTotalSharesOfAccount #
        - [Ext] updateTokenPricePerShare ($)
           - modifiers: onlyAuction
        - [Ext] addDivToken #
           - modifiers: onlyAuction
        - [Int] updateShareRate #
        - [Ext] setShareRateScalingFactor #
           - modifiers: onlyManager
        - [Ext] maxShare #
           - modifiers: pausable
        - [Ext] maxShareV1 #
           - modifiers: pausable
        - [Int] maxShareUpgrade
        - [Int] maxShareInternal #
        - [Pub] calculateStepsFromStart
        - [Ext] setMaxShareEventActive #
           - modifiers: onlyManager
        - [Ext] getMaxShareEventActive
        - [Ext] setMaxShareMaxDays #
           - modifiers: onlyManager
        - [Ext] setTotalVcaRegisteredShares #
           - modifiers: onlyMigrator
        - [Ext] setPaused #
        - [Ext] getPaused
        - [Ext] getMaxShareMaxDays
        - [Ext] setupRole #
           - modifiers: onlyManager
        - [Ext] getDivTokens
        - [Ext] getTotalSharesOf
        - [Ext] getTotalVcaRegisteredShares
        - [Ext] getIsVCARegistered
    							


    Fixes & Improvements

    Auction Contract:
  • Declaration of variables as constant and functions external to save gas.

  • Staking Contract:
  • Rearrange logic in function stakeInternal() to save gas.
  • Rearrange logic in function withdrawDivToken(tokenAddress) to prevent potential reentrancy attacks.