Hyperbolic Protocol
Smart Contract Audit Report
Audit Summary
Hyperbolic Protocol is a 100% on-chain collateralized lending protocol that is intended to leverage Uniswap V3 TWAPs, automated variable APRs and protocol fees to yield rewards to investors.
For this audit, we reviewed the following contracts on the Ethereum Mainnet:
- LoanToken contract at 0xE69e34B9f90bbd31FF72c3c4Fa006D7E21897177.
- LendingPool contract at 0x3B57D742f3D023FA97C622584db9C235650c1653.
- LendingPoolTokenCustodian contract at 0x1781077acAeA50B9e8fBD634a87b3E04E3c80264.
- HyperbolicProtocol contract at 0x85225ed797fd4128ac45a992c46ea4681a7a15da.
- LendingRewards contract at 0x300648a601c584E6379fa0D6a31CbBFCcA6177e4.
- RewardsLocker contract at 0x02FFdaCeb369b54255b6f20d640C5829F029061F.
- External LP LoanToken contract at 0xA223D06030056f0f85c1F9547ff2790311E9430a.
- LendingPoolExtLP contract at 0xf55D5E761B6FE3f43E55874cE2973CAC575d16c7.
- External LP Token LendingPoolTokenCustodian contract at 0x275B225C30E29fD62755A611D59fEA491EDa5998.
- HLP contract at 0x6118B4aE99146D3530B35F5708C5ab97Bd0E54FE.
- HLP LendingRewards contract at 0x12aD8cec0cECD91A1D5C71Ac0Bb0D54A5154f9c4.
- TwapUtils contract at 0xBf1858b24243Ecbcf7d940f458e36CB7401c2366.
We previously reviewed the project team's GudGuess platform here.
Audit Findings
All findings have been resolved, though some centralized aspects are present.
Date: April 20th, 2023.
Updated: May 16th, 2023 to reflect changes from commit e0152b02b4cf015a6861ec6b3ad9cb1679a65101 to commit e9a9a0eca522f7aef518398523efe570d69ef80b on the team's private GitHub repository. Additionally, the platform now intends to utilize the TwapUtils contract at address 0xdf9a6debb35be847d6addb7843e763539671b2c7 on the Arbitrum Mainnet.
Updated: June 8th, 2023 to reflect changes from commit e9a9a0eca522f7aef518398523efe570d69ef80b to commit 78720c7011ffb4cde058d2a9f0b093a9630d1f3e on the team's private GitHub repository.
Updated: June 23rd, 2023 to reflect changes from commit 78720c7011ffb4cde058d2a9f0b093a9630d1f3e to commit 120b5733b016e8126348640a099a979eb3618b13 on the team's private GitHub repository.
Updated: June 26th, 2023 to reflect changes from commit 120b5733b016e8126348640a099a979eb3618b13 to the mainnet addresses listed above.Finding #1 - LendingPool - High (Resolved)
Description: The _withdraw() function allows users to withdraw funds from their position if their resulting borrowed to collateral ratio exceeds the maximum loan percentage.
Risk/Impact: A user can drain value from the platform by withdrawing their collateral without repaying their debt.require( _currentLTVX96 == 0 || _currentLTVX96 >= (FixedPoint96.Q96 * maxLoanToValue) / DENOMENATOR, 'WITHDRAW: exceeds max LTV' );
Recommendation: The above require statement should be updated to the following:
Resolution: The team has implemented the above recommendation.require(_currentLTVX96 <= (FixedPoint96.Q96 * maxLoanToValue) / DENOMENATOR, 'WITHDRAW: exceeds max LTV' );
Finding #2 - LendingPool - High (Resolved)
Description: If a user withdraws a partial amount of their position's total deposited tokens and the position does not have an active loan, their LoanToken NFT and associated position is burned.
Risk/Impact: If a user withdraws less than the total collateral from an existing position without an active loan, they will lose the position's remaining collateral to the contract.(uint256 _currentLTVX96, , ) = getLTVX96(_tokenId); require( _currentLTVX96 == 0 || _currentLTVX96 >= (FixedPoint96.Q96 * maxLoanToValue) / DENOMENATOR, 'WITHDRAW: exceeds max LTV' ); if (_currentLTVX96 == 0) { _deleteLoan(_tokenId); }
Recommendation: A position should only be deleted if a position has no remaining collateral or debt.
Resolution: A position is now only deleted if the user has no remaining collateral.
Finding #3 - LendingPool - High (Resolved)
Description: Underflow can occur if a user repays more than the sum of their borrowed amount and interest fees.
Risk/Impact: A position's borrowed amount can underflow and result in a larger value than intended. The user will then not be able to pay their loan back and will be able to be liquidated._loan.amountETHBorrowed -= (_amount - _amountAPRFees);
Recommendation: The mentioned code should be updated to the following:
Resolution: The team has implemented the above recommendation.if ((_amount - _amountAPRFees) > _loan.amountETHBorrowed) { _loan.amountETHBorrowed = 0; } else { _loan.amountETHBorrowed -= (_amount - _amountAPRFees); }
Finding #4 - LendingPool - Medium (Resolved)
Description: Swaps in the _processLiquidatedTokens() function currently use the loan's total borrowed amount as the minimum amount to receive. If a pool's minimum collateral ratio is significantly larger than 100%, the amount received should be expected to be greater than the loan's borrowed amount.
Risk/Impact: A large disparity between the value of the tokens and the current specified minimum amount to receive can allow for frontrunning opportunities in which the contract would receive less funds than they should when a liquidation occurs.
Recommendation: The project team should use the referenced TWAP with desired slippage in order to calculate minimum expected amounts to receive.
Resolution: The team implemented the above recommendation.
Finding #5 - LendingPool - Medium (Resolved)
Description: Users will have to pay lifetime interest on the loan's existing debt each time they borrow or repay. For example, if a user repays half of their loan, they first pay interest on the total amount borrowed for the entire duration of the loan. If they then repay the remaining half, they are charged interest on the remaining half for the entire duration of the loan instead of from the time of the last repayment.
Risk/Impact: Users will pay more interest if executing multiple borrows or repayments within a single position than if they borrowed or repaid the total amount at once.
Recommendation: A Position's aprStart should be updated whenever its interest is paid.
Resolution: The team has implemented the above recommendation.
Contracts Overview
LoanToken Contract:
- The project team should exercise caution and disallow fee-on-transfer tokens from being used as collateral unless the proper exemptions are made.
HLP Contract:
- This contract defines Hyperbolic Protocol Loan NFTs.
- The associated Lending Pool address can mint or burn a NFT from any user at any time.
- This contract also implements the EIP-2981 NFT Royalty standard to support paying NFT creators a royalty on NFT Marketplaces.
- The owner may update the Royalty address and Royalty basis points at any time.
- The owner may update the base URI at any time.
- The owner can update the Lending pool address at any time.
LendingPool Contract:
- This contract is used to represent users' deposited liquidity into the LendingPoolExtHLP contract.
- The Lending Pool address can mint or burn tokens from any user at any time.
- An associated LendingRewards contract is created by this contract upon deployment.
- Users' Rewardshares are updated in the LendingRewards contract whenever participating in a transfer.
- This contract complies with the ERC-20 standard.
LendingPoolExtHLP Contract:
- This contract allows users to deposit various collateral tokens in order to borrow ETH.
- A user can deposit any supported collateral token by specifying its corresponding liquidity pool address.
- The collateral can be used for a new position, or can be added to an existing position.
- When creating a new position, the user is minted a LoanToken NFT to represent their loan data.
- If adding to an existing position, the user specifies a LoanToken ID that they own to signal the position to be deposited into.
- Deposited funds are transferred into the contract's associated LendingPoolTokenCustodian contract.
- Users can then borrow ETH up to a maximum loan percentage of the ETH value of the collateral token.
- If a user attempts to borrow more than they are permitted, their maximum permitted amount is borrowed instead.
- The maximum loan percentage is determined by the collateral's custom max LTV. If a max LTV is not set, the contract's default maximum LTV is used instead.
- The total amount borrowed from a pool at once cannot exceed the pool's maximum total borrow limit if one has been set for the pool.
- Token prices are calculated using the associated TwapUtils contract.
- A borrowing fee percentage is taken from any ETH borrowed by a user.
- When borrowing from an existing position, the borrowed amount is deducted by any accumulated interest owed.
- Interest is calculated based on the total lifespan of the LoanToken NFT, amount borrowed, and the LendingPool balance to target market cap ratio.
- A low LendingPool balance to target market cap ratio results in a higher APR, decreasing to the contract's minimum APR once the balance has reached the target.
- A user can repay borrowed ETH at any time.
- Each time a user repays, they are first charged interest on the position's current borrowed amount.
- Any remaining funds after interest are counted towards the repayment of borrowed funds.
- Any excess ETH provided is returned to the user.
- A user can withdraw their deposited funds if it does not result in their position's borrowed to collateral ratio exceeding the maximum loan percentage.
- All collected fees and interest are deposited into the LendingRewards contract.
- Any position can be liquidated by any address if its borrowed to collateral ratio exceeds the liquidation threshold.
- When a liquidation using non-HYPE tokens as collateral occurs, the loan's collateral is swapped for the blockchain's native token and stored in the contract for future borrowing as long as the "Liquidate Default Capital" flag is enabled.
- If a loan using HYPE as collateral is liquidated, the loan's collateral is transferred to the contract's owner.
- If the Liquidate Default Capital flag is disabled, any liquidated loan's collateral is transferred to the contract's owner.
- The owner can toggle the Liquidate Default Capital flag at any time.
- The owner can update the swap slippage used for liquidations at any time.
- The owner can update the borrowing fee to any value up to 30% at any time.
- The owner can update the minimum APR to up to 10% and the maximum APR to up to 100% at any time.
- The owner can set a maximum borrow limit for a pool at any time.
- The owner can update the contract's default maximum loan percentage, any custom token maximum loan percentages, and liquidation threshold values to up to 100% at any time.
- The owner can pause deposit and borrow functionality at any time.
- The owner can add or remove a supported liquidity pool from the whitelist at any time.
- A pool must support the UniswapV3Pool interface and contain WETH as one of its tokens in order to be whitelisted.
- The project team should ensure that the liquidation threshold is set to a lower threshold than a token's maximum loan percentage threshold to prevent immediate liquidations after borrowing.
- The project team should ensure that liquidation eligibility is monitored and the liquidation threshold is set to a value less than 100% to avoid losses and to ensure that swaps on liquidations do not fail.
HyperbolicProtocol Contract:
- This contract inherits all LendingPool functionality with updated reward distribution and liquidity functionality.
- Users can deposit the blockchain's native token at any time in exchange for minted HLP tokens.
- HLP tokens can also be redeemed at any time for an equal amount of the blockchain's native token. HLP tokens are burned from the user upon redemption.
- When rewards are deposited into this contract, they are split between a LendingRewards contract used for HYPE holder rewards and another LendingRewards contract used for HLP holder rewards.
- The owner can update the proportions of this split at any time.
LendingPoolTokenCustodian Contract:
- This contract defines the "Hyperbolic Protocol" ERC-20 token where each token additionally represents a share in the HolderRewards contract for addresses not excluded from rewards.
- Users' shares in the HolderRewards contract will be adjusted as tokens are sent and received.
- 100 million tokens are minted upon deployment, where 10% is minted to the RewardsLocker contract, and the remaining 90% is minted to the owner.
- Any user may burn their own tokens at any time to reduce the total supply.
- HYPE tokens may not be bought or sold until the owner has set the launch time.
- Any address that buys HYPE tokens within 10 seconds of the launch time will be marked as a bot.
- Addresses marked as bots will not be able to send or receive tokens at any time.
- Any address may not have more than 1% of the token's total supply within 30 minutes of the launch time.
- When taxes are enabled, the tax percentage will fall between the minimum and maximum tax percentage, determined by the LendingPool balance to target market cap ratio.
- All taxes collected will be stored within this contract until the "swap threshold" is reached.
- The contract will perform an automated swap and process when the following conditions are met:
- Swapping is enabled.
- The owner has initialized a Uniswap liquidity position.
- The contract's HYPE token balance has reached the swap threshold.
- An LP percentage of the accumulated HYPE fees are used for a liquidity add, where half of the tokens are swapped for ETH, paired with the remaining half, and added as liquidity.
- Any remaining tokens and ETH from the liquidity add are transferred to the owner.
- The remaining portion of the accumulated HYPE fees are swapped for ETH and deposited into the LendingPool contract.
- The owner may create a Uniswap liquidity pool at a specified fee amount at any time.
- The owner may create a liquidity position in one of the liquidity pools with a specified number of the contract's tokens at any time, along with supplied ETH.
- The owner can manually execute a swap and process at any time if the swap threshold has been reached.
- The owner may toggle any address as an Automated Market Maker (AMM) at any time. AMMs are used to identify buys and sells, and are excluded from rewards.
- The owner can update the swap threshold and toggle swap and process functionality at any time.
- The project team should ensure that the swap threshold is limited in order to prevent frontrunning attacks.
- The owner can update the pool to market cap target at any time.
- The owner can disable taxes on buys, sells, or transfers at any time.
- The owner can set the minimum and maximum tax percentages to up to 20% each at any time. The team should exercise caution and ensure that the minimum tax is always less than or equal to the maximum tax.
- The owner can update the LP percentage at any time.
- The owner can update the LendingPool address at any time.
- The owner can exclude any address from rewards at any time.
- The owner can remove an address from the bot list at any time.
RewardsLocker Contract:
- This contract is used to distribute rewards to HYPE token holders.
- The contract also holds tokens that are deposited into the LendingPool contract.
- Each HYPE token represents 1 share in this contract. Users' balances are updated by the HyperbolicProtocol contract as tokens are transferred.
- Users' shares are not impacted if their HYPE tokens are deposited into the LendingPool contract.
- Users will earn a reward in ETH per share.
- Users' rewards will be distributed each time their share balance is updated.
- Users may manually claim their rewards at any time.
- Any address may deposit rewards into the contract.
- Depositing rewards will add to the accumulated reward per share for all users.
- Any ETH transferred to this contract are deposited as rewards while the contract holds any HYPE tokens. If the contract does not hold any HYPE, received ETH is sent to the contract's owner, intended to be the LendingPool address.
TwapUtils Contract:
- This contract is used to claim rewards in the associated LendingRewards contract and transfer them to this contract's owner.
- Any address can initiate a reward withdrawal to the owner at any time.
- Ownership can be transferred at any time.
- This contract is used to determine the current value of a token in a UniswapV3 liquidity pool.
- The price is determined using a Time-Weighted Average Price Oracle (TWAP).
- The price is currently calculated using a 5-minute interval.
- The owner may set the TWAP interval to any value at any time.
- The team should adjust the TWAP interval as needed to maintain price accuracy.
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 |
Sybil Attack | N/A | PASS |
Unbounded Loops | N/A | PASS |
Unused Code | N/A | PASS |
Overall Contract Safety | PASS |
Contract Source Summary and Visualizations
Name |
Address/Source Code |
Visualized |
LoanToken |
||
LendingPoolExtLP, LendingPool, & HLP |
||
HyperbolicProtocol |
||
LendingRewards |
||
RewardsLocker |
||
TwapUtils |
About SourceHat
SourceHat (formerly Solidity Finance - founded in 2020) has quickly grown to have one of the most experienced and well-equipped smart contract auditing teams in the industry. Our team has conducted 1700+ 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!
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.