ViperSwap - Smart Contract Audit Report
Summary
ViperSwap is a DEX and DeFi platform for yield farming on the Harmony mainnet.
For this audit we reviewed the project team's GovernanceToken, MasterBreeder, and Timelock contracts at addresses 0xea589e93ff18b1a1f1e9bac7ef3e86ab62addc79, 0x7abc67c8d4b248a38b0dc5756300630108cb48b4, and 0x1f4bcb672d059a562336fe2d98e43cb28ab1bcc7, respectively, on the Harmony mainnet.
Notes on the Contracts:
GovernanceToken Contract:MasterBreeder Contract:
- The GovernanceToken contract contains features to enable governance/voting.
- At the time of writing this report, Authorized users no longer have the ability to manually mint tokens.
- The owner has the ability to lock a specified amount of any user's GovernanceTokens. Upon locking, tokens are transferred from the holder to the GovernanceToken address until an owner-specified unlock block, where a user can subsequently unlock their funds and have their tokens transferred back to them.
- Authorized users change the block at which funds are unlocked, however this will only update already locked funds.
- The owner of this contract is currently set to the MasterBreeder contract.
- The owner of the MasterBreeder contract is currently set to the Timelock contract, which delays transactions by at least 2 days.
- Ownership of this contract can be transferred.
- The owner can mint an unlimited amount of tokens.
- The owner can grant or remove authorized access from any address.
General Notes Across Contracts:
- Users can stake various LP tokens into the MasterBreeder contract in order to earn GovernanceTokens.
- The contract owner can add new token pools for users to stake at any time.
- There is a percentage based deposit fee which can be changed by the owner to any amount at any time. This deposit fee is global accross all pools.
- When withdrawing LP tokens from the contract, users are intended to be charged decreasing dev fees based on the time between their most recent withdrawal and their current one. These fee percentages can be changed by authorized users to any amount at any time.
- The MasterChef staking contract should not be used with ERC-777 tokens or fee-on-transfer tokens. If a fee-on-transfer token is added as a staking asset, then the contract must be exempt from transfer fees.
- As previously mentioned, the owner of this contract is currently set to the Timelock contract, which delays transactions by at least 2 days.
- Ownership of this contract can be transferred.
- A dev fee, liquidity pool fee, community fund fee, and a founder's fee are all taken out of generated rewards. These rewards are percentage based and can be updated by the owner to any amount.
- A pool's share of rewards generated can be changed by the owner.
- Authorized users can update any fee address.
- Authorized users can transfer ownership of the GovernanceToken contract.
Audit Findings Summary:
- SafeMath is used to prevent overflows.
- Some gas optimizations could be achieved through marking functions external and variables constant, but as these contracts are already deployed, this is merely informational.
- No security issues from outside attackers were identified.
- Ensure trust in the project team as they have substantial control in the ecosystem.
- Users with large amounts invested may want to set up an Etherscan alert to monitor the Timelock contract's activity.
- Date: December 8th, 2021.
External Threat Results
Vulnerability Category | Notes | Result |
---|---|---|
Arbitrary Storage Write | N/A | PASS |
Arbitrary Jump | N/A | PASS |
Centralization of Control | The owner has the permissions listed above. | WARNING |
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 |
Unbounded Loop | N/A | PASS |
Unchecked Retval | N/A | PASS |
User Supplied Assertion | N/A | PASS |
Critical Solidity Compiler | N/A | PASS |
Overall Contract Safety | PASS |
Details: GovernanceToken Contract
($) = payable function
# = non-constant function
+ [Int] IERC20
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ Context
- [Int] _msgSender
- [Int] _msgData
+ Ownable (Context)
- [Int] #
- [Pub] owner
- [Pub] renounceOwnership #
- modifiers: onlyOwner
- [Pub] transferOwnership #
- modifiers: onlyOwner
+ ERC20 (Context, 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] _setupDecimals #
- [Int] _beforeTokenTransfer #
+ [Lib] Address
- [Int] isContract
- [Int] sendValue #
- [Int] functionCall #
- [Int] functionCall #
- [Int] functionCallWithValue #
- [Int] functionCallWithValue #
- [Int] functionStaticCall
- [Int] functionStaticCall
- [Int] functionDelegateCall #
- [Int] functionDelegateCall #
- [Prv] _verifyCallResult
+ Authorizable (Ownable)
- [Pub] addAuthorized #
- modifiers: onlyOwner
- [Pub] removeAuthorized #
- modifiers: onlyOwner
+ GovernanceToken (ERC20, Ownable, Authorizable)
- [Pub] #
- modifiers: ERC20
- [Pub] cap
- [Pub] capUpdate #
- modifiers: onlyAuthorized
- [Pub] lockFromUpdate #
- modifiers: onlyAuthorized
- [Pub] lockToUpdate #
- modifiers: onlyAuthorized
- [Pub] unlockedSupply
- [Pub] lockedSupply
- [Pub] circulatingSupply
- [Pub] totalLock
- [Int] _beforeTokenTransfer #
- [Int] _transfer #
- [Pub] mint #
- modifiers: onlyOwner
- [Pub] manualMint #
- modifiers: onlyAuthorized
- [Pub] totalBalanceOf
- [Pub] lockOf
- [Pub] lastUnlockBlock
- [Pub] lock #
- modifiers: onlyOwner
- [Pub] canUnlockAmount
- [Pub] unlock #
- [Pub] transferAll #
- [Ext] delegates
- [Ext] delegate #
- [Ext] delegateBySig #
- [Ext] getCurrentVotes
- [Ext] getPriorVotes
- [Int] _delegate #
- [Int] _moveDelegates #
- [Int] _writeCheckpoint #
- [Int] safe32
- [Int] getChainId
+ ReentrancyGuard
- [Int] #
+ [Lib] SafeMath
- [Int] tryAdd
- [Int] trySub
- [Int] tryMul
- [Int] tryDiv
- [Int] tryMod
- [Int] add
- [Int] sub
- [Int] mul
- [Int] div
- [Int] mod
- [Int] sub
- [Int] div
- [Int] mod
+ [Lib] EnumerableSet
- [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] SafeERC20
- [Int] safeTransfer #
- [Int] safeTransferFrom #
- [Int] safeApprove #
- [Int] safeIncreaseAllowance #
- [Int] safeDecreaseAllowance #
- [Prv] _callOptionalReturn #
+ MasterBreeder (Ownable, Authorizable, ReentrancyGuard)
- [Pub] #
- [Ext] poolLength
- [Pub] add #
- modifiers: onlyOwner,nonDuplicated
- [Pub] set #
- modifiers: onlyOwner
- [Pub] massUpdatePools #
- [Pub] updatePool #
- [Pub] getMultiplier
- [Pub] getPoolReward
- [Ext] pendingReward
- [Pub] claimRewards #
- [Pub] claimReward #
- [Int] _harvest #
- [Pub] getGlobalAmount
- [Pub] getGlobalRefAmount
- [Pub] getTotalRefs
- [Pub] getRefValueOf
- [Pub] deposit #
- modifiers: nonReentrant
- [Pub] withdraw #
- modifiers: nonReentrant
- [Pub] emergencyWithdraw #
- modifiers: nonReentrant
- [Int] safeGovTokenTransfer #
- [Pub] dev #
- modifiers: onlyAuthorized
- [Pub] bonusFinishUpdate #
- modifiers: onlyAuthorized
- [Pub] halvingUpdate #
- modifiers: onlyAuthorized
- [Pub] lpUpdate #
- modifiers: onlyAuthorized
- [Pub] comUpdate #
- modifiers: onlyAuthorized
- [Pub] founderUpdate #
- modifiers: onlyAuthorized
- [Pub] rewardUpdate #
- modifiers: onlyAuthorized
- [Pub] rewardMulUpdate #
- modifiers: onlyAuthorized
- [Pub] lockUpdate #
- modifiers: onlyAuthorized
- [Pub] lockdevUpdate #
- modifiers: onlyAuthorized
- [Pub] locklpUpdate #
- modifiers: onlyAuthorized
- [Pub] lockcomUpdate #
- modifiers: onlyAuthorized
- [Pub] lockfounderUpdate #
- modifiers: onlyAuthorized
- [Pub] starblockUpdate #
- modifiers: onlyAuthorized
- [Pub] getNewRewardPerBlock
- [Pub] userDelta
- [Pub] reviseWithdraw #
- modifiers: onlyAuthorized
- [Pub] reviseDeposit #
- modifiers: onlyAuthorized
- [Pub] setStageStarts #
- modifiers: onlyAuthorized
- [Pub] setStageEnds #
- modifiers: onlyAuthorized
- [Pub] setUserFeeStage #
- modifiers: onlyAuthorized
- [Pub] setDevFeeStage #
- modifiers: onlyAuthorized
- [Pub] setDevDepFee #
- modifiers: onlyAuthorized
- [Pub] setUserDepFee #
- modifiers: onlyAuthorized
- [Pub] reclaimTokenOwnership #
- modifiers: onlyAuthorized
Details: MasterBreeder Contract
($) = payable function
# = non-constant function
+ [Int] IERC20
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ Context
- [Int] _msgSender
- [Int] _msgData
+ Ownable (Context)
- [Int] #
- [Pub] owner
- [Pub] renounceOwnership #
- modifiers: onlyOwner
- [Pub] transferOwnership #
- modifiers: onlyOwner
+ ERC20 (Context, 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] _setupDecimals #
- [Int] _beforeTokenTransfer #
+ [Lib] Address
- [Int] isContract
- [Int] sendValue #
- [Int] functionCall #
- [Int] functionCall #
- [Int] functionCallWithValue #
- [Int] functionCallWithValue #
- [Int] functionStaticCall
- [Int] functionStaticCall
- [Int] functionDelegateCall #
- [Int] functionDelegateCall #
- [Prv] _verifyCallResult
+ Authorizable (Ownable)
- [Pub] addAuthorized #
- modifiers: onlyOwner
- [Pub] removeAuthorized #
- modifiers: onlyOwner
+ GovernanceToken (ERC20, Ownable, Authorizable)
- [Pub] #
- modifiers: ERC20
- [Pub] cap
- [Pub] capUpdate #
- modifiers: onlyAuthorized
- [Pub] lockFromUpdate #
- modifiers: onlyAuthorized
- [Pub] lockToUpdate #
- modifiers: onlyAuthorized
- [Pub] unlockedSupply
- [Pub] lockedSupply
- [Pub] circulatingSupply
- [Pub] totalLock
- [Int] _beforeTokenTransfer #
- [Int] _transfer #
- [Pub] mint #
- modifiers: onlyOwner
- [Pub] manualMint #
- modifiers: onlyAuthorized
- [Pub] totalBalanceOf
- [Pub] lockOf
- [Pub] lastUnlockBlock
- [Pub] lock #
- modifiers: onlyOwner
- [Pub] canUnlockAmount
- [Pub] unlock #
- [Pub] transferAll #
- [Ext] delegates
- [Ext] delegate #
- [Ext] delegateBySig #
- [Ext] getCurrentVotes
- [Ext] getPriorVotes
- [Int] _delegate #
- [Int] _moveDelegates #
- [Int] _writeCheckpoint #
- [Int] safe32
- [Int] getChainId
+ ReentrancyGuard
- [Int] #
+ [Lib] SafeMath
- [Int] tryAdd
- [Int] trySub
- [Int] tryMul
- [Int] tryDiv
- [Int] tryMod
- [Int] add
- [Int] sub
- [Int] mul
- [Int] div
- [Int] mod
- [Int] sub
- [Int] div
- [Int] mod
+ [Lib] EnumerableSet
- [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] SafeERC20
- [Int] safeTransfer #
- [Int] safeTransferFrom #
- [Int] safeApprove #
- [Int] safeIncreaseAllowance #
- [Int] safeDecreaseAllowance #
- [Prv] _callOptionalReturn #
+ MasterBreeder (Ownable, Authorizable, ReentrancyGuard)
- [Pub] #
- [Ext] poolLength
- [Pub] add #
- modifiers: onlyOwner,nonDuplicated
- [Pub] set #
- modifiers: onlyOwner
- [Pub] massUpdatePools #
- [Pub] updatePool #
- [Pub] getMultiplier
- [Pub] getPoolReward
- [Ext] pendingReward
- [Pub] claimRewards #
- [Pub] claimReward #
- [Int] _harvest #
- [Pub] getGlobalAmount
- [Pub] getGlobalRefAmount
- [Pub] getTotalRefs
- [Pub] getRefValueOf
- [Pub] deposit #
- modifiers: nonReentrant
- [Pub] withdraw #
- modifiers: nonReentrant
- [Pub] emergencyWithdraw #
- modifiers: nonReentrant
- [Int] safeGovTokenTransfer #
- [Pub] dev #
- modifiers: onlyAuthorized
- [Pub] bonusFinishUpdate #
- modifiers: onlyAuthorized
- [Pub] halvingUpdate #
- modifiers: onlyAuthorized
- [Pub] lpUpdate #
- modifiers: onlyAuthorized
- [Pub] comUpdate #
- modifiers: onlyAuthorized
- [Pub] founderUpdate #
- modifiers: onlyAuthorized
- [Pub] rewardUpdate #
- modifiers: onlyAuthorized
- [Pub] rewardMulUpdate #
- modifiers: onlyAuthorized
- [Pub] lockUpdate #
- modifiers: onlyAuthorized
- [Pub] lockdevUpdate #
- modifiers: onlyAuthorized
- [Pub] locklpUpdate #
- modifiers: onlyAuthorized
- [Pub] lockcomUpdate #
- modifiers: onlyAuthorized
- [Pub] lockfounderUpdate #
- modifiers: onlyAuthorized
- [Pub] starblockUpdate #
- modifiers: onlyAuthorized
- [Pub] getNewRewardPerBlock
- [Pub] userDelta
- [Pub] reviseWithdraw #
- modifiers: onlyAuthorized
- [Pub] reviseDeposit #
- modifiers: onlyAuthorized
- [Pub] setStageStarts #
- modifiers: onlyAuthorized
- [Pub] setStageEnds #
- modifiers: onlyAuthorized
- [Pub] setUserFeeStage #
- modifiers: onlyAuthorized
- [Pub] setDevFeeStage #
- modifiers: onlyAuthorized
- [Pub] setDevDepFee #
- modifiers: onlyAuthorized
- [Pub] setUserDepFee #
- modifiers: onlyAuthorized
- [Pub] reclaimTokenOwnership #
- modifiers: onlyAuthorized
Details: Timelock Contract
($) = payable function
# = non-constant function
+ [Lib] SafeMath
- [Int] tryAdd
- [Int] trySub
- [Int] tryMul
- [Int] tryDiv
- [Int] tryMod
- [Int] add
- [Int] sub
- [Int] mul
- [Int] div
- [Int] mod
- [Int] sub
- [Int] div
- [Int] mod
+ Timelock
- [Pub] #
- [Ext] ($)
- [Pub] setDelay #
- [Pub] acceptAdmin #
- [Pub] setPendingAdmin #
- [Pub] queueTransaction #
- [Pub] cancelTransaction #
- [Pub] executeTransaction ($)
- [Int] getBlockTimestamp