PlvGLP
Smart Contract Audit Report
Audit Summary
Plutus DAO is creating a new staking platform which includes two new tokens.
For this audit, we reviewed Plutus DAO's PlsGlpToken, PlvGlpToken, GlpDepositor, and GlpStaker contracts at commit 564ac32af9f2a867b70d3a1be68ad944f6c829ac on the team's private GitHub repository.
Audit Findings
No Findings were identified, though centralized aspects are present.
Date: September 26th, 2022.
Contracts Overview
PlvGlpToken Contract:
- As the contracts are implemented with Solidity v0.8.x, they are safe from any possible overflows/underflows.
PlsGlpToken Contract:
- This contract implements the ERC-4626 tokenized vault standard which allows users to deposit a specified token in exchange for minted shares.
- Shares represent a portion of the contract's specified token balance and can be redeemed while redemption functionality is enabled and the GlpDepositor contract is not paused.
- Only the Operator, intended to be the GlpDepositor contract, can deposit, redeem, mint, and withdraw tokens.
- As a result, users must use the GlpDepositor contract in order to interact with this contract.
- The total supply of shares cannot exceed the specified supply cap.
- The owner can update the supply cap at any time.
- The owner can disable deposits, redemptions, mints, or withdrawals at any time.
- The owner can update the Operator address at any time.
GlpDepositor Contract:
- The Operator can mint any number of tokens to any address at any time.
- The Operator can burn any number of tokens from any address at any time.
- If "private transfer mode" is enabled, only "Handlers" can transfer tokens.
- The owner can update the Operator address at any time.
- The owner can toggle private transfer mode at any time.
- The owner can add or remove any address from the Handler list at any time.
GlpStaker Contract:
- This contract can be used to deposit "sGLP" tokens into its associated staker address.
- Upon depositing, PlsGlp tokens are minted to this contract and deposited to the PlvGlpToken Vault on behalf of the depositor. The depositor is then minted PlvGlp tokens to represent their shares.
- PlvGlp tokens can be redeemed at any time for sGLP. This will first exchange the PlvGlp tokens for a portion of the vault's PlsGlp token balance.
- A "rebate" percentage of the resulting PlsGlp token amount is transferred back into the vault; the remainder is burned.
- sGLP tokens are then transferred from the staker contract at a 1:1 ratio to the PlsGlp redemption amount.
- A default exit fee percentage is taken from this amount. A rebate percentage of this fee is kept in the staker contract, and the remainder of the fee is transferred to the Exit Fee Collector address.
- The remaining sGLP tokens after the exit fee is transferred to the redeemer.
- If a redeemer is a "Partner", a custom exit fee and rebate percentage is used instead.
- Any address can donate sGLP to the staker contract through this contract at any time. This will also mint an equal amount of PlsGlp to the vault contract.
- Contracts cannot interact with this contract unless they have been added as a Partner or added to the Whitelist.
- As the sGLP and Whitelist contracts were not included in the scope of this audit, we are unable to provide an assessment with regards to security or functionality.
- The owner can update the default exit fee percentage and default vault rebate percentage to up to 100% each at any time.
- The owner can add or remove a Partner at any time.
- The owner can update a Partner's custom exit fee and rebate percentages to any amounts at any time.
- The owner can update the Fee Collector address at any time.
- The owner can update the associated Whitelist address at any time.
- The owner can pause the contract at any time, disabling deposit and redemption functionality.
- The owner can withdraw any tokens or the blockchain's native currency from this contract at any time.
- This contract is used to interact with external contracts in order to earn rewards on deposited funds.
- Any Operator can call the handleRewards() function at any time.
- This will collect any rewards earned from the associated RewardRouterV2 contract.
- A fee is taken from the resulting WETH balance of the contract. 80% of this fee is transferred to the Fee Collector address, and 20% is transferred to the caller in the form of ETH.
- The remaining WETH amount is transferred to the Compounder address. If compounding is enabled, additional functionality from the Compound address is executed.
- As the RewardRouterV2 and Compounder contracts were not included in the scope of this audit, we are unable to provide an assessment with regards to security or functionality.
- This contract can be upgraded by the owner at any time.
- The owner can update the fee to any amount less than 100% at any time.
- The owner can toggle compounding functionality at any time.
- The owner can update the Compounder, Depositor, and Fee Collector addresses at any time.
- The owner can add or remove any address from the Operator list at any time.
- The owner can withdraw any NFTs, ERC20 tokens, or the blockchain's native currency from this contract at any time.
Audit Results
Vulnerability Category | Notes | Result |
---|---|---|
Arbitrary Jump/Storage Write | N/A | PASS |
Centralization of Control |
|
WARNING |
Compiler Issues | N/A | PASS |
Delegate Call to Untrusted Contract | N/A | PASS |
Dependence on Predictable Variables | N/A | PASS |
Ether/Token Theft | N/A | PASS |
Flash Loans | N/A | PASS |
Front Running | N/A | PASS |
Improper Events | N/A | PASS |
Improper Authorization Scheme | N/A | PASS |
Integer Over/Underflow | N/A | PASS |
Logical Issues | N/A | PASS |
Oracle Issues | N/A | PASS |
Outdated Compiler Version | N/A | PASS |
Race Conditions | N/A | PASS |
Reentrancy | N/A | PASS |
Signature Issues | N/A | PASS |
Unbounded Loops | N/A | PASS |
Unused Code | N/A | PASS |
Overall Contract Safety | PASS |
PlvGlpToken Contract
($) = payable function
# = non-constant function
+ [Int] IERC20
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ [Int] IERC20Metadata (IERC20)
- [Ext] name
- [Ext] symbol
- [Ext] decimals
+ Context
- [Int] _msgSender
- [Int] _msgData
+ ERC20 (Context, IERC20, IERC20Metadata)
- [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] _spendAllowance #
- [Int] _beforeTokenTransfer #
- [Int] _afterTokenTransfer #
+ [Int] IERC20Permit
- [Ext] permit #
- [Ext] nonces
- [Ext] DOMAIN_SEPARATOR
+ [Lib] Address
- [Int] isContract
- [Int] sendValue #
- [Int] functionCall #
- [Int] functionCall #
- [Int] functionCallWithValue #
- [Int] functionCallWithValue #
- [Int] functionStaticCall
- [Int] functionStaticCall
- [Int] functionDelegateCall #
- [Int] functionDelegateCall #
- [Int] verifyCallResult
+ [Lib] SafeERC20
- [Int] safeTransfer #
- [Int] safeTransferFrom #
- [Int] safeApprove #
- [Int] safeIncreaseAllowance #
- [Int] safeDecreaseAllowance #
- [Int] safePermit #
- [Prv] _callOptionalReturn #
+ [Int] IERC4626 (IERC20, IERC20Metadata)
- [Ext] asset
- [Ext] totalAssets
- [Ext] convertToShares
- [Ext] convertToAssets
- [Ext] maxDeposit
- [Ext] previewDeposit
- [Ext] deposit #
- [Ext] maxMint
- [Ext] previewMint
- [Ext] mint #
- [Ext] maxWithdraw
- [Ext] previewWithdraw
- [Ext] withdraw #
- [Ext] maxRedeem
- [Ext] previewRedeem
- [Ext] redeem #
+ [Lib] Math
- [Int] max
- [Int] min
- [Int] average
- [Int] ceilDiv
- [Int] mulDiv
- [Int] mulDiv
- [Int] sqrt
- [Int] sqrt
+ ERC4626 (ERC20, IERC4626)
- [Pub] #
- [Pub] asset
- [Pub] totalAssets
- [Pub] convertToShares
- [Pub] convertToAssets
- [Pub] maxDeposit
- [Pub] maxMint
- [Pub] maxWithdraw
- [Pub] maxRedeem
- [Pub] previewDeposit
- [Pub] previewMint
- [Pub] previewWithdraw
- [Pub] previewRedeem
- [Pub] deposit #
- [Pub] mint #
- [Pub] withdraw #
- [Pub] redeem #
- [Int] _convertToShares
- [Int] _convertToAssets
- [Int] _deposit #
- [Int] _withdraw #
- [Prv] _isVaultCollateralized
+ Ownable (Context)
- [Pub] #
- [Pub] owner
- [Int] _checkOwner
- [Pub] renounceOwnership #
- modifiers: onlyOwner
- [Pub] transferOwnership #
- modifiers: onlyOwner
- [Int] _transferOwnership #
+ PlvGlpToken (ERC4626, Ownable)
- [Pub] #
- modifiers: ERC4626,ERC20
- [Pub] redeem #
- [Pub] deposit #
- [Pub] withdraw #
- [Pub] mint #
- [Ext] setParams #
- modifiers: onlyOwner
- [Ext] setSupplyCap #
- modifiers: onlyOwner
- [Ext] setOperator #
- modifiers: onlyOwner
PlsGlpToken Contract
($) = payable function
# = non-constant function
+ [Int] IERC20
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ [Int] IERC20Metadata (IERC20)
- [Ext] name
- [Ext] symbol
- [Ext] decimals
+ Context
- [Int] _msgSender
- [Int] _msgData
+ ERC20 (Context, IERC20, IERC20Metadata)
- [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] _spendAllowance #
- [Int] _beforeTokenTransfer #
- [Int] _afterTokenTransfer #
+ Ownable (Context)
- [Pub] #
- [Pub] owner
- [Int] _checkOwner
- [Pub] renounceOwnership #
- modifiers: onlyOwner
- [Pub] transferOwnership #
- modifiers: onlyOwner
- [Int] _transferOwnership #
+ PlsGlpToken (ERC20, Ownable)
- [Pub] #
- modifiers: ERC20
- [Ext] mint #
- [Ext] burn #
- [Int] _transfer #
- [Ext] setOperator #
- modifiers: onlyOwner
- [Ext] setInPrivateTransferMode #
- modifiers: onlyOwner
- [Ext] updateHandler #
- modifiers: onlyOwner
GlpDepositor Contract
($) = payable function
# = non-constant function
Int = Internal
Ext = External
Pub = Public
+ Context
- [Int] _msgSender
- [Int] _msgData
+ Pausable (Context)
- [Pub] #
- [Pub] paused
- [Int] _requireNotPaused
- [Int] _requirePaused
- [Int] _pause #
- modifiers: whenNotPaused
- [Int] _unpause #
- modifiers: whenPaused
+ [Int] IERC20
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ [Int] IERC20Metadata (IERC20)
- [Ext] name
- [Ext] symbol
- [Ext] decimals
+ [Int] IERC4626 (IERC20, IERC20Metadata)
- [Ext] asset
- [Ext] totalAssets
- [Ext] convertToShares
- [Ext] convertToAssets
- [Ext] maxDeposit
- [Ext] previewDeposit
- [Ext] deposit #
- [Ext] maxMint
- [Ext] previewMint
- [Ext] mint #
- [Ext] maxWithdraw
- [Ext] previewWithdraw
- [Ext] withdraw #
- [Ext] maxRedeem
- [Ext] previewRedeem
- [Ext] redeem #
+ [Int] IERC20Permit
- [Ext] permit #
- [Ext] nonces
- [Ext] DOMAIN_SEPARATOR
+ [Lib] Address
- [Int] isContract
- [Int] sendValue #
- [Int] functionCall #
- [Int] functionCall #
- [Int] functionCallWithValue #
- [Int] functionCallWithValue #
- [Int] functionStaticCall
- [Int] functionStaticCall
- [Int] functionDelegateCall #
- [Int] functionDelegateCall #
- [Int] verifyCallResult
+ [Lib] SafeERC20
- [Int] safeTransfer #
- [Int] safeTransferFrom #
- [Int] safeApprove #
- [Int] safeIncreaseAllowance #
- [Int] safeDecreaseAllowance #
- [Int] safePermit #
- [Prv] _callOptionalReturn #
+ Ownable (Context)
- [Pub] #
- [Pub] owner
- [Int] _checkOwner
- [Pub] renounceOwnership #
- modifiers: onlyOwner
- [Pub] transferOwnership #
- modifiers: onlyOwner
- [Int] _transferOwnership #
+ OwnableWithRetrieve (Ownable)
- [Ext] retrieve #
- modifiers: onlyOwner
+ [Int] ITokenMinter
- [Ext] mint #
- [Ext] burn #
+ [Int] IWhitelist
- [Ext] isWhitelisted
+ GlpDepositor (OwnableWithRetrieve, Pausable)
- [Pub] #
- [Pub] deposit #
- modifiers: whenNotPaused
- [Pub] redeem #
- modifiers: whenNotPaused
- [Ext] previewRedeem
- [Ext] getFeeBp
- [Ext] depositAll #
- [Ext] redeemAll #
- [Ext] donate #
- [Prv] _deposit #
- [Prv] _redeem #
- [Prv] _calculateFee
- [Prv] _isEligibleSender
- [Prv] _validateInvariants
- [Ext] setExitFee #
- modifiers: onlyOwner
- [Ext] updatePartner #
- modifiers: onlyOwner
- [Ext] setFeeCollector #
- modifiers: onlyOwner
- [Ext] setWhitelist #
- modifiers: onlyOwner
- [Ext] setPaused #
- modifiers: onlyOwner
GlpStaker Contract
($) = payable function
# = non-constant function
+ [Lib] AddressUpgradeable
- [Int] isContract
- [Int] sendValue #
- [Int] functionCall #
- [Int] functionCall #
- [Int] functionCallWithValue #
- [Int] functionCallWithValue #
- [Int] functionStaticCall
- [Int] functionStaticCall
- [Int] verifyCallResult
+ Initializable
- [Int] _disableInitializers #
+ [Int] IERC1822ProxiableUpgradeable
- [Ext] proxiableUUID
+ [Int] IBeaconUpgradeable
- [Ext] implementation
+ [Lib] StorageSlotUpgradeable
- [Int] getAddressSlot
- [Int] getBooleanSlot
- [Int] getBytes32Slot
- [Int] getUint256Slot
+ ERC1967UpgradeUpgradeable (Initializable)
- [Int] __ERC1967Upgrade_init #
- modifiers: onlyInitializing
- [Int] __ERC1967Upgrade_init_unchained #
- modifiers: onlyInitializing
- [Int] _getImplementation
- [Prv] _setImplementation #
- [Int] _upgradeTo #
- [Int] _upgradeToAndCall #
- [Int] _upgradeToAndCallUUPS #
- [Int] _getAdmin
- [Prv] _setAdmin #
- [Int] _changeAdmin #
- [Int] _getBeacon
- [Prv] _setBeacon #
- [Int] _upgradeBeaconToAndCall #
- [Prv] _functionDelegateCall #
+ UUPSUpgradeable (Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable)
- [Int] __UUPSUpgradeable_init #
- modifiers: onlyInitializing
- [Int] __UUPSUpgradeable_init_unchained #
- modifiers: onlyInitializing
- [Ext] proxiableUUID
- modifiers: notDelegated
- [Ext] upgradeTo #
- modifiers: onlyProxy
- [Ext] upgradeToAndCall ($)
- modifiers: onlyProxy
- [Int] _authorizeUpgrade #
+ ContextUpgradeable (Initializable)
- [Int] __Context_init #
- modifiers: onlyInitializing
- [Int] __Context_init_unchained #
- modifiers: onlyInitializing
- [Int] _msgSender
- [Int] _msgData
+ OwnableUpgradeable (Initializable, ContextUpgradeable)
- [Int] __Ownable_init #
- modifiers: onlyInitializing
- [Int] __Ownable_init_unchained #
- modifiers: onlyInitializing
- [Pub] owner
- [Int] _checkOwner
- [Pub] renounceOwnership #
- modifiers: onlyOwner
- [Pub] transferOwnership #
- modifiers: onlyOwner
- [Int] _transferOwnership #
+ [Int] IERC20
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ [Int] IERC165
- [Ext] supportsInterface
+ [Int] IERC721 (IERC165)
- [Ext] balanceOf
- [Ext] ownerOf
- [Ext] safeTransferFrom #
- [Ext] safeTransferFrom #
- [Ext] transferFrom #
- [Ext] approve #
- [Ext] setApprovalForAll #
- [Ext] getApproved
- [Ext] isApprovedForAll
+ [Int] IERC721Enumerable (IERC721)
- [Ext] totalSupply
- [Ext] tokenOfOwnerByIndex
- [Ext] tokenByIndex
+ [Int] IRewardRouterV2
- [Ext] handleRewards #
- [Ext] mintAndStakeGlp #
+ [Int] IWETH (IERC20)
- [Ext] withdrawTo #
+ GlpStaker (Initializable, OwnableUpgradeable, UUPSUpgradeable)
- [Pub] #
- [Pub] initialize #
- modifiers: initializer
- [Ext] handleRewards #
- [Prv] _calculateFee
- [Int] _authorizeUpgrade #
- modifiers: onlyOwner
- [Ext] retrieve #
- modifiers: onlyOwner
- [Ext] retrieveNFT #
- modifiers: onlyOwner
- [Ext] setFee #
- modifiers: onlyOwner
- [Ext] updateOperator #
- modifiers: onlyOwner
- [Ext] setDepositor #
- modifiers: onlyOwner
- [Ext] updateCompounder #
- modifiers: onlyOwner
- [Ext] setFeeCollector #
- modifiers: onlyOwner
About SourceHat
SourceHat has quickly grown to have one of the most experienced and well-equipped smart contract auditing teams in the industry. Our team has conducted 1300+ solidity smart contract audits covering all major project types and protocols, securing a total of over $50 billion U.S. dollars in on-chain value across 1500 projects!.
Our firm is well-reputed in the community and is trusted as a top smart contract auditing company for the review of solidity code, no matter how complex. Our team of experienced solidity smart contract auditors performs audits for tokens, NFTs, crowdsales, marketplaces, gambling games, financial protocols, and more!
Contact us today to get a free quote for a smart contract audit of your project!
What is a SourceHat Audit?
Typically, a smart contract audit is a comprehensive review process designed to discover logical errors, security vulnerabilities, and optimization opportunities within code. A SourceHat Audit takes this a step further by verifying economic logic to ensure the stability of smart contracts and highlighting privileged functionality to create a report that is easy to understand for developers and community members alike.
How Do I Interpret the Findings?
Each of our Findings will be labeled with a Severity level. We always recommend the team resolve High, Medium, and Low severity findings prior to deploying the code to the mainnet. Here is a breakdown on what each Severity level means for the project:
- High severity indicates that the issue puts a large number of users' funds at risk and has a high probability of exploitation, or the smart contract contains serious logical issues which can prevent the code from operating as intended.
- Medium severity issues are those which place at least some users' funds at risk and has a medium to high probability of exploitation.
- Low severity issues have a relatively minor risk association; these issues have a low probability of occurring or may have a minimal impact.
- Informational issues pose no immediate risk, but inform the project team of opportunities for gas optimizations and following smart contract security best practices.