GalaxyGoggle - Audit Report
Summary
GalaxyGoggle is protocol that uses a treasury to back the value of its token, and includes a staking contract where users can earn rewards.
For this audit, we reviewed the following contracts on the Avalanche blockchain mainnet:
- TimeERC20Token contract at 0xf2f7ce610a091b94d41d69f4ff1129434a82e2f0.
- MEMOries contract at 0x2482ec3928adf1718caa5956608684f5a54e14d0.
- TimeStaking contract at 0xbd79c01140cee7040f8f5e935b72e13540a801b6.
- Distributor contract at 0x7f6e28b4d35769397ee0a0936d4d9f06a7d44069.
- StakingWarmup contract at 0x5da00ceb825d60af1f2e84d58b631eeba6dc2362.
- TimeTreasury contract at 0xd5f922e23693e552793fe0431f9a95ba67a60a23.
- TimeBondingCalculator contract at 0x3e0b7bbad42445dc760059f085d56a86963793c1.
Notes on the Contracts:
TimeERC20Token Contract:MEMOries Contract:
- This contract defines the GalaxyGoggle ($GG) ERC-20 token.
- At the time of this audit, the total supply is 1,723,183.519918 $GG tokens.
- Anyone can burn their own tokens, or tokens they are approved to spend, at any time.
- The Vault address can mint any amount of tokens to any address at any time.
- Currently, 86.94% of the total supply is held in the TimeStaking contract, 7.46% is in Joe LP, and 1.08% is held in a TimeBondDepository contract
- Of the LP tokens, 91.91% is held in the TimeTreasury contract and 6.96% is held by a single wallet.
- The owner is able to set the Vault address to any address at any time.
- The contract implements the EIP-2612 standard in order to support permits which allows for gasless approvals to be made via signatures.
- The contract complies with the ERC-20 token standard.
- As the contract utilizes the SafeMath library, it is protected against any underflow/overflow attacks.
TimeStaking Contract:
- This contract defines the Staked GalaxyGoggle ($sGG) ERC-20 token.
- At the time of this audit, the total supply is 141,726,636.198893 $sGG tokens.
- There are no burn functions present, but anyone can send their tokens to the 0x..dead address at any time, which will reduce the circulating supply.
- Only the TimeStaking contract address can trigger a rebase, which will increase the total supply based on the profit accumulated in the TimeStaking contract.
- The newly minted tokens are distributed proportionally amongst holders in a frictionless manner.
- Currently, 98.1% of the total supply is held in the TimeStaking contract, 0.36% is held in the StakingWarmup contract, and 0.05% is held in the Wrapped sGG token contract
- The $sGG token should not be added as part of a token pair for any liquidity pool; if the team decides to create a liquidity pool, the sync() function will have to be called on the liquidity pool in order to absorb any tokens earned from the rebase into the liquidity pool.
- The contract implements the EIP-2612 standard in order to support permits which allows for gasless approvals to be made via signatures.
- The contract complies with the ERC-20 token standard.
- As the contract utilizes the SafeMath library, it is protected against any underflow/overflow attacks.
Distributor Contract:
- Anyone can use this contract to stake GalaxyGoggle tokens and earn rewards in Staked GalaxyGoggle ($sGG) tokens.
- As the contract allows anyone to stake on behalf of any address, users can choose to lock the deposit functionality for their address. Users can unlock deposits for their address at any time.
- Upon staking, an equivalent amount of $sGG tokens are transferred from the contract to the Warmup contract controlled by the team.
- Staked funds are locked for a number of epoch periods determined by the project team.
- The length of each epoch period is determined by the team on deployment and cannot be modified.
- The epoch can only be advanced by calling the rebase() function.
- Anyone can manually trigger the rebase() function which will rebase the $sGG token once the end time of the current epoch has elapsed.
- The rebase() function is called automatically before every stake, and can optionally be called before an unstake.
- The rebase() function will use the profit collected from the epoch to mint new $sGG tokens which are distributed amongst holders.
- The profit is effectively the amount of $GG tokens in the contract that are not currently staked.
- The Distributor contract is called within the rebase() function, which will mint an appropriate amount of $GG tokens to the contract as profit based on the excess reserve amounts in the Treasury contract.
- The Locker contract address can also contribute a "bonus" amount of $sGG tokens to the profit at any time. As the Locker contract address is currently unset, our team has not provided an assessment of the Locker contract based on security.
- The Locker contract address can also retrieve any amount of $sGG tokens from the contract, but only up to the amount that it has contributed.
- In order to unstake, users must first claim their $sGG tokens.
- Users can only claim once the expiry time of their stake has elapsed.
- Upon claiming, the contract uses the Warmup contract to transfer staked amount of $sGG tokens plus any tokens earned as reflections to the user.
- Upon unstaking, the user exchanges their $sGG tokens for an equivalent amount of $GG tokens.
- The user can emergency withdraw their staked amount of $GG tokens from the contract at any time, forfeiting any $sGG rewards.
- The Manager address can set the Distributor, Warmup, and Locker contract addresses to any address only one time; Currently, the Distributor and Warmup contract addresses are set and cannot be changed.
- The Manager address can set the lock period for staked funds to any value at any time.
- As the contract utilizes the SafeMath library, it is protected against any underflow/overflow attacks.
StakingWarmup Contract:
- Anyone can use this contract to distribute epoch rewards in $GG tokens to a list of recipient addresses specified within the contract.
- Each recipient address has its own reward rate, which determines the amount of rewards that are minted to the recipient address.
- Followed by the distribution, the reward rate of each recipient address is increased or decreased one step at a time, depending on the adjustment settings associated with the recipient address, until the target adjustment rate is met.
- The Policy address retains control of the contract and can add any recipient address to the distribution list. The project team must exercise caution and as to not add the same recipient address more than once.
- The Policy address can remove any recipient address from the distribution list at any time. Note that while recipient address and reward rate data is reset, the array which stores the recipient addresses is not re-adjusted to account for the null spaces. Therefore, the project team should exercise caution when adding and removing recipient addresses. As the length of the array can only grow, this could cause the loop processing the addresses to exceed the block gas limit.
- The Policy address can set reward rate, the target reward rate, and the instruction to increase or decrease the reward rate at any time.
- The Policy address may propose to transfer the Policy role to any address, but the appointed address must accept the role in order to complete the role transfer.
- As the contract utilizes the SafeMath library, it is protected against any underflow/overflow attacks.
TimeTreasury Contract:
- This contract contains a single function that is only intended to be used by the TimeStaking contract in order to transfer any amount of $sGG tokens from the contract to the specified recipient.
- The team is responsible for ensuring the contract is supplied with enough tokens to support the transfers.
- As the contract utilizes the SafeMath library, it is protected against any underflow/overflow attacks.
TimeBondingCalculator Contract:
- Any approved Reserve Depositor can deposit any approved Reserve Token into the Treasury Reserves and receive $GG tokens in a 1:1 ratio in return.
- Any approved Liquidity Depositor can deposit any approved Liquidity Token into the Treasury Reserves and receive an equivalent value of $GG tokens in return.
- Any approved Reserve Spender can withdraw any approved Reserve Token from the Treasury Reserves in exchange for $GG tokens in a 1:1 ratio; the $GG tokens are subsequently burned.
- Any approved Debtor can borrow any approved Reserve Token from the Treasury Reserves against their balance of $sGG tokens.
- The Debtor can repay their incurred debt using $GG tokens or any approved Reserve Token; if repaid using $GG tokens, they are subsequently burned.
- Any Liquidity Manager can withdraw Liquidity Tokens from the Treasury Reserves in any amount that exceeds the value of the total supply of $GG tokens.
- Any Reserve Manager can withdraw value in excess of the value of the total supply of $GG tokens in the form of any token from the Treasury Reserves.
- Any Reward Manager can mint an amount of $GG tokens to any address up until the value of the tokens in the Treasury Reserve is matched.
- The Manager can fetch the value of each Reserve and Liquidity token in the Treasury Reserves in order to update the total value of all the tokens in the Reserves.
- The Manager can queue any address to be added as a Reserve Depositor, Reserve Spender, Liquidity Depositor, Debtor, Reserve Manager, Liquidity Manager, Reward Manager, Reserve Token, or Liquidity Token.
- After the wait time has elapsed, the Manager must manually trigger the toggle() function in order to add the queued address to the appropriate list.
- The project team should exercise caution and ensure to only use trusted stablecoins as Reserve Tokens and trusted LP tokens as Liquidity Tokens, or the Treasury Reserve valuation will not be accurate.
- As the contract utilizes the SafeMath library, it is protected against any underflow/overflow attacks.
- This contract is intended to be used to provide a valuation for each Liquidity Token asset defined in the Treasury.
- The valuations are derived by doubling the square root of Uniswap's constant product for reserves in order to account for both assets in the liquidity pair.
- A portion of the total valuation is returned based on the proportion of LP tokens the user is looking to value to the total supply of the LP tokens.
- As the contract utilizes the SafeMath library, it is protected against any underflow/overflow attacks.
Audit Findings Summary
- No security threats from outside attackers were identified.
- Ensure trust in the team as they have substantial control in the ecosystem.
- Date: December 21st, 2021
External Threat Results
Vulnerability Category | Notes | Result |
---|---|---|
Arbitrary Storage Write | N/A | PASS |
Arbitrary Jump | N/A | PASS |
Centralization of Control | N/A | PASS |
Delegate Call to Untrusted Contract | N/A | PASS |
Dependence on Predictable Variables | N/A | PASS |
Deprecated Opcodes | N/A | PASS |
Ether Thief | N/A | PASS |
Exceptions | N/A | PASS |
External Calls | N/A | PASS |
Integer Over/Underflow | N/A | PASS |
Multiple Sends | N/A | PASS |
Suicide | N/A | PASS |
State Change External Calls | N/A | Pass |
Unchecked Retval | N/A | PASS |
User Supplied Assertion | N/A | PASS |
Critical Solidity Compiler | N/A | PASS |
Overall Contract Safety | PASS |
TimeERC20Token Contract
($) = payable function
# = non-constant function
+ [Lib] EnumerableSet
- [Prv] _add #
- [Prv] _remove #
- [Prv] _contains
- [Prv] _length
- [Prv] _at
- [Prv] _getValues
- [Prv] _insert #
- [Int] add #
- [Int] remove #
- [Int] contains
- [Int] length
- [Int] at
- [Int] getValues
- [Int] insert #
- [Int] add #
- [Int] remove #
- [Int] contains
- [Int] length
- [Int] at
- [Int] getValues
- [Int] insert #
- [Int] add #
- [Int] remove #
- [Int] contains
- [Int] length
- [Int] at
- [Int] getValues
- [Int] insert #
- [Int] add #
- [Int] remove #
- [Int] contains
- [Int] length
- [Int] at
- [Int] add #
- [Int] remove #
- [Int] contains
- [Int] length
- [Int] at
+ [Int] IERC20
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ [Lib] SafeMath
- [Int] add
- [Int] sub
- [Int] sub
- [Int] mul
- [Int] div
- [Int] div
- [Int] mod
- [Int] mod
- [Int] sqrrt
- [Int] percentageAmount
- [Int] substractPercentage
- [Int] percentageOfTotal
- [Int] average
- [Int] quadraticPricing
- [Int] bondingCurve
+ ERC20 (IERC20)
- [Pub] #
- [Pub] name
- [Pub] symbol
- [Pub] decimals
- [Pub] totalSupply
- [Pub] balanceOf
- [Pub] transfer #
- [Pub] allowance
- [Pub] approve #
- [Pub] transferFrom #
- [Pub] increaseAllowance #
- [Pub] decreaseAllowance #
- [Int] _transfer #
- [Int] _mint #
- [Int] _burn #
- [Int] _approve #
- [Int] _beforeTokenTransfer #
+ [Lib] Counters
- [Int] current
- [Int] increment #
- [Int] decrement #
+ [Int] IERC2612Permit
- [Ext] permit #
- [Ext] nonces
+ ERC20Permit (ERC20, IERC2612Permit)
- [Pub] #
- [Pub] permit #
- [Pub] nonces
+ [Int] IOwnable
- [Ext] owner
- [Ext] renounceOwnership #
- [Ext] transferOwnership #
+ Ownable (IOwnable)
- [Pub] #
- [Pub] owner
- [Pub] renounceOwnership #
- modifiers: onlyOwner
- [Pub] transferOwnership #
- modifiers: onlyOwner
+ VaultOwned (Ownable)
- [Ext] setVault #
- modifiers: onlyOwner
- [Pub] vault
+ TimeERC20Token (ERC20Permit, VaultOwned)
- [Pub] #
- modifiers: ERC20
- [Ext] mint #
- modifiers: onlyVault
- [Pub] burn #
- [Pub] burnFrom #
- [Pub] _burnFrom #
MEMOries Contract
($) = payable function
# = non-constant function
+ [Lib] SafeMath
- [Int] add
- [Int] sub
- [Int] sub
- [Int] mul
- [Int] div
- [Int] div
- [Int] mod
- [Int] mod
- [Int] sqrrt
- [Int] percentageAmount
- [Int] substractPercentage
- [Int] percentageOfTotal
- [Int] average
- [Int] quadraticPricing
- [Int] bondingCurve
+ [Lib] Address
- [Int] isContract
- [Int] sendValue #
- [Int] functionCall #
- [Int] functionCall #
- [Int] functionCallWithValue #
- [Int] functionCallWithValue #
- [Prv] _functionCallWithValue #
- [Int] functionStaticCall
- [Int] functionStaticCall
- [Int] functionDelegateCall #
- [Int] functionDelegateCall #
- [Prv] _verifyCallResult
- [Int] addressToString
+ [Int] IERC20
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ ERC20 (IERC20)
- [Pub] #
- [Pub] name
- [Pub] symbol
- [Pub] decimals
- [Pub] totalSupply
- [Pub] balanceOf
- [Pub] transfer #
- [Pub] allowance
- [Pub] approve #
- [Pub] transferFrom #
- [Pub] increaseAllowance #
- [Pub] decreaseAllowance #
- [Int] _transfer #
- [Int] _mint #
- [Int] _burn #
- [Int] _approve #
- [Int] _beforeTokenTransfer #
+ [Lib] Counters
- [Int] current
- [Int] increment #
- [Int] decrement #
+ [Int] IERC2612Permit
- [Ext] permit #
- [Ext] nonces
+ ERC20Permit (ERC20, IERC2612Permit)
- [Pub] #
- [Pub] permit #
- [Pub] nonces
+ [Int] IOwnable
- [Ext] manager
- [Ext] renounceManagement #
- [Ext] pushManagement #
- [Ext] pullManagement #
+ Ownable (IOwnable)
- [Pub] #
- [Pub] manager
- [Pub] renounceManagement #
- modifiers: onlyManager
- [Pub] pushManagement #
- modifiers: onlyManager
- [Pub] pullManagement #
+ MEMOries (ERC20Permit, Ownable)
- [Pub] #
- modifiers: ERC20,ERC20Permit
- [Ext] initialize #
- [Ext] setIndex #
- modifiers: onlyManager
- [Pub] rebase #
- modifiers: onlyStakingContract
- [Int] _storeRebase #
- [Pub] balanceOf
- [Pub] gonsForBalance
- [Pub] balanceForGons
- [Pub] circulatingSupply
- [Pub] index
- [Pub] transfer #
- [Pub] allowance
- [Pub] transferFrom #
- [Pub] approve #
- [Int] _approve #
- [Pub] increaseAllowance #
- [Pub] decreaseAllowance #
TimeStaking Contract
($) = payable function
# = non-constant function
+ [Lib] SafeMath
- [Int] add
- [Int] add32
- [Int] sub
- [Int] sub
- [Int] mul
- [Int] div
- [Int] div
+ [Int] IERC20
- [Ext] decimals
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ [Lib] Address
- [Int] isContract
- [Int] sendValue #
- [Int] functionCall #
- [Int] functionCall #
- [Int] functionCallWithValue #
- [Int] functionCallWithValue #
- [Prv] _functionCallWithValue #
- [Int] functionStaticCall
- [Int] functionStaticCall
- [Int] functionDelegateCall #
- [Int] functionDelegateCall #
- [Prv] _verifyCallResult
- [Int] addressToString
+ [Lib] SafeERC20
- [Int] safeTransfer #
- [Int] safeTransferFrom #
- [Int] safeApprove #
- [Int] safeIncreaseAllowance #
- [Int] safeDecreaseAllowance #
- [Prv] _callOptionalReturn #
+ [Int] IOwnable
- [Ext] manager
- [Ext] renounceManagement #
- [Ext] pushManagement #
- [Ext] pullManagement #
+ Ownable (IOwnable)
- [Pub] #
- [Pub] manager
- [Pub] renounceManagement #
- modifiers: onlyManager
- [Pub] pushManagement #
- modifiers: onlyManager
- [Pub] pullManagement #
+ [Int] IMemo
- [Ext] rebase #
- [Ext] circulatingSupply
- [Ext] balanceOf
- [Ext] gonsForBalance
- [Ext] balanceForGons
- [Ext] index
+ [Int] IWarmup
- [Ext] retrieve #
+ [Int] IDistributor
- [Ext] distribute #
+ TimeStaking (Ownable)
- [Pub] #
- [Ext] stake #
- [Pub] claim #
- [Ext] forfeit #
- [Ext] toggleDepositLock #
- [Ext] unstake #
- [Pub] index
- [Pub] rebase #
- [Pub] contractBalance
- [Ext] giveLockBonus #
- [Ext] returnLockBonus #
- [Ext] setContract #
- modifiers: onlyManager
- [Ext] setWarmup #
- modifiers: onlyManager
Distributor Contract
($) = payable function
# = non-constant function
+ [Lib] SafeERC20
- [Int] safeTransfer #
- [Int] safeTransferFrom #
- [Int] safeApprove #
- [Int] safeIncreaseAllowance #
- [Int] safeDecreaseAllowance #
- [Prv] _callOptionalReturn #
+ [Lib] SafeMath
- [Int] add
- [Int] add32
- [Int] sub
- [Int] sub
- [Int] mul
- [Int] div
- [Int] div
- [Int] mod
- [Int] mod
- [Int] sqrrt
- [Int] percentageAmount
- [Int] substractPercentage
- [Int] percentageOfTotal
- [Int] average
- [Int] quadraticPricing
- [Int] bondingCurve
+ [Int] IERC20
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ [Lib] Address
- [Int] isContract
- [Int] sendValue #
- [Int] functionCall #
- [Int] functionCall #
- [Int] functionCallWithValue #
- [Int] functionCallWithValue #
- [Prv] _functionCallWithValue #
- [Int] functionStaticCall
- [Int] functionStaticCall
- [Int] functionDelegateCall #
- [Int] functionDelegateCall #
- [Prv] _verifyCallResult
- [Int] addressToString
+ [Int] IPolicy
- [Ext] policy
- [Ext] renouncePolicy #
- [Ext] pushPolicy #
- [Ext] pullPolicy #
+ Policy (IPolicy)
- [Pub] #
- [Pub] policy
- [Pub] renouncePolicy #
- modifiers: onlyPolicy
- [Pub] pushPolicy #
- modifiers: onlyPolicy
- [Pub] pullPolicy #
+ [Int] ITreasury
- [Ext] mintRewards #
+ Distributor (Policy)
- [Pub] #
- [Ext] distribute #
- [Int] adjust #
- [Pub] nextRewardAt
- [Pub] nextRewardFor
- [Ext] addRecipient #
- modifiers: onlyPolicy
- [Ext] removeRecipient #
- modifiers: onlyPolicy
- [Ext] setAdjustment #
- modifiers: onlyPolicy
StakingWarmup Contract
($) = payable function
# = non-constant function
+ [Int] IERC20
- [Ext] decimals
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ StakingWarmup
- [Pub] #
- [Ext] retrieve #
TimeTreasury Contract
($) = payable function
# = non-constant function
+ [Lib] SafeMath
- [Int] add
- [Int] add32
- [Int] sub
- [Int] sub
- [Int] mul
- [Int] mul32
- [Int] div
- [Int] div
+ [Lib] Address
- [Int] isContract
- [Int] functionCall #
- [Prv] _functionCallWithValue #
- [Prv] _verifyCallResult
+ [Int] IOwnable
- [Ext] manager
- [Ext] renounceManagement #
- [Ext] pushManagement #
- [Ext] pullManagement #
+ Ownable (IOwnable)
- [Pub] #
- [Pub] manager
- [Pub] renounceManagement #
- modifiers: onlyManager
- [Pub] pushManagement #
- modifiers: onlyManager
- [Pub] pullManagement #
+ [Int] IERC20
- [Ext] decimals
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] approve #
- [Ext] totalSupply
- [Ext] transferFrom #
+ [Lib] SafeERC20
- [Int] safeTransfer #
- [Int] safeTransferFrom #
- [Prv] _callOptionalReturn #
+ [Int] IERC20Mintable
- [Ext] mint #
- [Ext] mint #
+ [Int] IOHMERC20
- [Ext] burnFrom #
+ [Int] IBondCalculator
- [Ext] valuation
+ TimeTreasury (Ownable)
- [Pub] #
- [Ext] deposit #
- [Ext] withdraw #
- [Ext] incurDebt #
- [Ext] repayDebtWithReserve #
- [Ext] repayDebtWithOHM #
- [Ext] manage #
- [Ext] mintRewards #
- [Pub] excessReserves
- [Ext] auditReserves #
- modifiers: onlyManager
- [Pub] valueOf
- [Ext] queue #
- modifiers: onlyManager
- [Ext] toggle #
- modifiers: onlyManager
- [Int] requirements
- [Int] listContains
TimeBondingCalculator Contract
($) = payable function
# = non-constant function
+ [Lib] FullMath
- [Prv] fullMul
- [Prv] fullDiv
- [Int] mulDiv
+ [Lib] Babylonian
- [Int] sqrt
+ [Lib] BitMath
- [Int] mostSignificantBit
+ [Lib] FixedPoint
- [Int] decode
- [Int] decode112with18
- [Int] fraction
- [Int] sqrt
+ [Lib] SafeMath
- [Int] add
- [Int] sub
- [Int] sub
- [Int] mul
- [Int] div
- [Int] div
- [Int] sqrrt
+ [Int] IERC20
- [Ext] decimals
+ [Int] IUniswapV2ERC20
- [Ext] totalSupply
+ [Int] IUniswapV2Pair (IUniswapV2ERC20)
- [Ext] getReserves
- [Ext] token0
- [Ext] token1
+ [Int] IBondingCalculator
- [Ext] valuation
+ TimeBondingCalculator (IBondingCalculator)
- [Pub] #
- [Pub] getKValue
- [Pub] getTotalValue
- [Ext] valuation
- [Ext] markdown