Hyperfolio Info

Hyperfolio, an automated asset manager re-defining yield generation on blockchain.

Hyperfolio Logo

TrustNet Score

The TrustNet Score evaluates crypto projects based on audit results, security, KYC verification, and social media presence. This score offers a quick, transparent view of a project's credibility, helping users make informed decisions in the Web3 space.

23.04
Poor Excellent

Real-Time Threat Detection

Real-time threat detection, powered by Cyvers.io, is currently not activated for this project.

This advanced feature provides continuous monitoring and instant alerts to safeguard your assets from potential security threats. Real-time detection enhances your project's security by proactively identifying and mitigating risks. For more information, click here.

Security Assessments

"Static Analysis Dynamic Analysis Symbolic Execution SWC Check Manual Review"
Contract address
N/A
Network N/A
License N/A
Compiler N/A
Type N/A
Language Solidity
Onboard date 2026/08/21
Revision date 2026/08/21

Summary and Final Words

No crucial issues found

The contract does not contain issues of high or medium criticality. This means that no known vulnerabilities were found in the source code.

Contract owner cannot mint

It is not possible to mint new tokens.

Contract owner cannot blacklist addresses.

It is not possible to lock user funds by blacklisting addresses.

Contract owner cannot set high fees

The fees, if applicable, can be a maximum of 25% or lower. The contract can therefore not be locked. Please take a look in the comment section for more details.

Contract cannot be locked

Owner cannot lock any user funds.

Token cannot be burned

There is no burning within the contract without any allowances

Ownership is not renounced

The owner retains significant control, which could potentially be used to modify key contract parameters.

Contract is upgradeable

The contract uses a proxy pattern or similar mechanism, enabling future upgrades. This can introduce risks if the upgrade mechanism is not securely managed.

Scope of Work

This audit encompasses the evaluation of the files listed below, each verified with a SHA-1 Hash. The team referenced above has provided the necessary files for assessment.

The auditing process consists of the following systematic steps:

  1. Specification Review: Analyze the provided specifications, source code, and instructions to fully understand the smart contract's size, scope, and functionality.
  2. Manual Code Examination: Conduct a thorough line-by-line review of the source code to identify potential vulnerabilities and areas for improvement.
  3. Specification Alignment: Ensure that the code accurately implements the provided specifications and intended functionalities.
  4. Test Coverage Assessment: Evaluate the extent and effectiveness of test cases in covering the codebase, identifying any gaps in testing.
  5. Symbolic Execution: Analyze the smart contract to determine how various inputs affect execution paths, identifying potential edge cases and vulnerabilities.
  6. Best Practices Evaluation: Assess the smart contracts against established industry and academic best practices to enhance efficiency, maintainability, and security.
  7. Actionable Recommendations: Provide detailed, specific, and actionable steps to secure and optimize the smart contracts.

A file with a different Hash has been intentionally or otherwise modified after the security review. A different Hash may indicate a changed condition or potential vulnerability that was not within the scope of this review.

Final Words

The following provides a concise summary of the audit report, accompanied by insightful comments from the auditor. This overview captures the key findings and observations, offering valuable context and clarity.


Smart Contract Analysis Statement

Contract Analysis

The HyperfolioVault contract implements an upgradeable asset custody vault that accepts deposits of a single configured asset - either an ERC20 token or the chain's native currency - and forwards them to an interchangeable external strategy contract that is expected to generate yield. It is not a token: it has no supply, no transfers, no allowances and no mint or burn functions. Deposits and withdrawals are not open to the public. They can only be initiated by one designated gateway contract, referred to in the code as the main chef, which is responsible for identifying users and enforcing whatever rules the wider protocol applies. The vault keeps a simple internal ledger of how much each user has deposited and pays withdrawals against that ledger.

The design is small and readable, and several parts of it are done carefully - reentrancy protection is present on both value-moving paths, the upgradeable initialisation pattern is implemented correctly, and the contract deliberately avoids the categories of risk that plague most vault designs, having no price oracle, no swap path, no signature verification and no cross-chain messaging. The problems we found are concentrated in one place: the accounting that connects what the vault records to what the vault and its strategy actually hold. Under ordinary conditions those two figures can drift apart, and the contract has no mechanism to notice or correct that. We also found that the vault's ability to return funds to users depends entirely on the attached strategy behaving correctly, with no fallback if it does not.

We reviewed the contract line by line, then as a whole, and confirmed each finding against the compiled contract rather than against the source alone. Forty targeted test cases were written to demonstrate the issues and to verify the cases that behave correctly, including a dedicated set that settles which of the suspected problems are genuine and which are not. Independent property testing reproduced the central accounting defect without being pointed at it, which is a strong indication that it is reachable in normal operation rather than only in contrived circumstances. Across the review we recorded five high severity issues, seven medium, ten low, thirteen informational observations and eight gas optimisations. We found no critical issues, in the sense that no unprivileged party can drain the contract; the most severe exposures require either a privileged key or an asset with particular transfer behaviour.

Ownership Privileges

The ownership of the contract has been not yet established, because the contract was not deployed at the time of review. Initialisation assigns ownership to whichever address performs it, so the owner will be determined by the deployment procedure. The owner retains full privileges including:

  • Replacing the yield strategy at any time, with immediate effect. This is by far the most consequential power in the contract: attaching a new strategy grants that strategy an unlimited allowance over the vault's asset and then pushes the vault's entire balance to it. An owner, or anyone who obtains the owner key, can direct every deposit to a contract of their choosing in a single transaction.
  • Changing the address of the gateway contract that is permitted to deposit and withdraw, which determines who can move funds in and out of the vault on behalf of users.
  • Changing the configured asset and the sentinel address that decides whether the vault operates in token mode or native mode. Both changes are permitted whenever the internal ledger reads zero, which is not the same as the vault being genuinely empty.
  • Transferring or renouncing ownership outright. Renouncing is materially dangerous here, because several of the recovery paths are owner-only, so a renounced vault holding funds behind a malfunctioning strategy would be permanently frozen.
  • The owner cannot alter any individual user's recorded balance, and cannot credit or delete a ledger entry directly. All ledger changes flow through the deposit and withdrawal paths.
  • The owner cannot block a specific user or address. There is no blacklist, allowlist or freeze capability anywhere in the contract, and no per-account restriction of any kind.
  • The owner cannot charge a fee. The contract has no fee parameter at all, so there is no deposit fee, withdrawal fee or performance fee, and consequently no fee ceiling that could be raised.
  • The owner cannot pause the contract or halt withdrawals, because no pause mechanism exists. This cuts both ways: users cannot be stopped from exiting by an administrative action, but there is also no way to contain an incident while it is being investigated.

Security Features

The contract implements several positive security features:

  • Both the deposit and the withdrawal path are protected against reentrancy, using the transient-storage variant of the guard. We verified that mixing this non-upgradeable guard into an upgradeable contract is safe here, because it writes only to transient storage and reserves no persistent slot that could collide with the proxy layout.
  • The upgradeable initialisation pattern is implemented correctly. The implementation disables its own initialisers in the constructor, so the implementation contract itself cannot be claimed by an outside party, and the initialiser cannot be called twice. A block of reserved storage slots is present for future versions, and we confirmed the current layout has no collisions.
  • Access to user funds is narrowed to a single gateway address rather than being open to the public, which removes a large class of direct attacks and keeps user-facing policy in one auditable place.
  • The attack surface that causes most vault losses is simply absent. There is no price oracle to manipulate, no swap or liquidity path to sandwich, no signature verification to replay, no unbounded loop to exhaust with gas, and no cross-chain messaging that could be spoofed. Arithmetic uses the compiler's checked operations throughout, with no unchecked blocks anywhere in the code.
  • Token transfers are handled through wrappers that tolerate the non-standard ERC20 implementations that return no value, and approvals to the strategy use a forced-approval routine that resets the allowance before setting it, which is the correct handling for tokens that reject a direct overwrite.
  • The documentation in the source is unusually thorough for a contract of this size, which made the review materially faster. Our one caution is that some of it asserts guarantees the code does not currently deliver, and those statements should be corrected rather than trusted.

Principal Risks for the Project Team and for Investors

Three themes account for the significant findings and should drive the remediation plan.

  • Accounting can overstate what the vault holds. The vault measures a deposit by the change in its own balance, which correctly captures a fee charged on the transfer into the vault, but the funds are then pulled out again by the strategy and that second movement is never measured. With any asset that takes a cut on transfer, or that otherwise delivers less than was requested, the ledger records more than the vault and its strategy actually hold, and the gap widens with every deposit. The practical consequence is that early withdrawers are paid in full and later ones are left with balances they cannot redeem. The same measurement also folds in a figure the strategy reports about itself, which lets a depositor be credited with value they did not supply. We recommend moving to share-based accounting, where a deposit buys a proportional claim on the assets actually held, because that single change resolves this whole family of issues at once. If assets that tax transfers are not intended to be supported, they should be rejected explicitly rather than accepted and mis-recorded.
  • The ability to return funds depends entirely on the strategy. Withdrawals are always served from the strategy, never from assets sitting in the vault, so a strategy that returns less than asked, or caps how much can leave at once, blocks withdrawals that the vault could otherwise cover from its own balance. Worse, detaching a broken strategy first requires calling into it, so a strategy that reverts cannot be removed - it stays attached, and users stay locked in. There is no emergency path that bypasses it. A related gap is that the vault never checks whether the strategy actually paid the user: a strategy that quietly sends less than asked, or nothing at all, still causes the user's entire recorded balance to be cleared, with the value left sitting in the strategy and no error raised. We confirmed this with an ordinary token that charges no fee of any kind, so it is not a side effect of unusual asset behaviour. We recommend serving withdrawals from vault liquidity first and topping up from the strategy, adding a check that the money genuinely arrived, and adding a detach route that clears the pointer without calling into the strategy at all.
  • Administrative power is unconstrained. Every privileged action takes effect immediately. There is no timelock of any length, ownership transfer is single-step, ownership can be renounced, and the strategy that receives the vault's entire balance is attached with no validation that it is even a contract, let alone that it handles the right asset. None of this is a coding defect - it is a governance choice - but it means that at present users of the vault are trusting a single key without any structural protection. Before any funds are accepted we would expect to see ownership held by a multisig whose address, signers and threshold are published, every setter placed behind a timelock with a stated minimum delay, and the ability to renounce ownership removed.

On the pre-defined claims commonly checked by investors, our verdict is as follows. The contract cannot mint, cannot burn, cannot blacklist and cannot set fees, because none of those mechanisms exist in it. It is upgradeable, and the upgrade authority sits entirely outside the audited code with no delay attached, so the implementation should be assumed replaceable at any time by whoever controls the proxy administrator. On the question of whether funds can be locked, the honest answer is a qualified yes: there is no lock function, but a malfunctioning strategy freezes withdrawals with no way out, and because ownership can be renounced that state can be made permanent. That combination is the one we would most want addressed before deployment.

Note - This Audit report consists of a security analysis of the HyperfolioVault smart contract. This analysis did not include economic analysis of the contract's tokenomics. Moreover, we only audited the main contract for the HyperfolioVault team. Other contracts associated with the project were not audited by our team, and this matters more than usual here: the gateway contract that controls all access to the vault, and every strategy contract the vault will delegate funds to, are both fully trusted by the code we reviewed and both fall outside this scope. We recommend investors do their own research before investing.

Files and details

Findings and Audit result

high Issues | 5 findings

Pending

#1 high Issue
Fee-on-transfer accounting covers only the first transfer hop, leaving the vault insolvent
HyperfolioVault.sol
L305-325
Description

The deposit path reads the vault's reported balance before and after pulling tokens from the gateway and credits the depositor with the difference. That measurement captures the fee taken on the first transfer only. Immediately afterwards the vault instructs the strategy to pull the same amount out again, and because the strategy holds an unlimited allowance that second transfer is taxed a second time. The shortfall is never measured or recorded, so the per-user ledger and the recorded total both overstate what the vault and its strategy actually hold. The gap grows with every deposit, which means the earliest withdrawers are paid in full while later ones are left holding entries they cannot redeem. Any asset that delivers less than the requested amount is affected, including deflationary and rebasing designs. This was reproduced with a one percent fee token, where a deposit of 1,000 credits the user with 990 while only 980.1 reaches the strategy, and the attempt to withdraw the credited amount reverts.

Pending

#2 high Issue
Withdrawals ignore assets held by the vault, so a solvent vault can fail to pay
HyperfolioVault.sol
L363-375
Description

When a strategy is attached, a withdrawal always requests the full amount from the strategy and pays the user out of whatever the strategy sends. Assets sitting in the vault itself are never used, even though the public balance accessor counts them towards the amount a user is permitted to request. A strategy that returns less than asked, or that caps how much can leave in one call, therefore causes the entire withdrawal to fail while the vault holds more than enough to cover it. The same mismatch means a partially funded strategy blocks users who could otherwise be paid immediately, and the deposit and withdrawal paths disagree about what counts as available.

Pending

#3 high Issue
Strategy migration pushes funds without registering them, stranding the transferred amount
HyperfolioVault.sol
L166-175
L384-397
Description

Attaching a new strategy transfers the vault's entire holdings to that strategy with a plain token or native transfer. The strategy is never told that a deposit took place, so a strategy that tracks its principal internally records nothing and reports a zero balance while physically holding the funds. Withdrawals then fail because the strategy believes it holds nothing to return, and the vault has already emptied itself. The transfer is also unverified, so if it moves nothing the vault carries on as though migration had succeeded. Nothing in the flow requires the receiving strategy to acknowledge the transfer, which makes the stranding silent. The worst case is theft rather than stranding. Because the funds sit in the strategy as an unregistered raw balance, they are exposed to whatever recovers stray tokens on that contract. Where a strategy exposes a rescue function that anyone can call, the whole migrated balance can be taken by an unprivileged address while the vault's ledger still shows the full liability. That pattern is normally restricted to the strategy owner, in which case the funds stay stranded but are not stolen, so the exposure depends on a component outside the scope of this review.

Pending

#4 high Issue
A halted strategy freezes every withdrawal and cannot be detached
HyperfolioVault.sol
L149-162
L351-375
Description

Detaching or replacing a strategy begins by calling that strategy to withdraw everything. If the call reverts for any reason, whether a paused strategy, an exhausted external protocol or a dependency that no longer exists, the configuration change reverts with it and the broken strategy stays attached. Because withdrawals are also routed exclusively through the strategy, users cannot exit either. There is no escape hatch: no pause, no forced detach and no path that pays users from the vault's own holdings. Every deposit stays trapped for as long as the strategy remains unhealthy, and because ownership can be renounced the freeze can become permanent.

Pending

#5 high Issue
The owner can seize every deposit in a single transaction
HyperfolioVault.sol
L144-178
Description

Setting a new strategy is unrestricted, takes effect in the same transaction and grants the target an unlimited allowance over the vault's asset before pushing the entire balance to it. An owner, or anyone who obtains the owner key, can point the vault at a contract they control and take all user funds at once. There is no delay, no confirmation step, no validation that the target behaves like a strategy and no cap on the amount at risk. Ownership is a single address that can also be renounced, and the gateway contract that fronts the vault is trusted without any conditions attached. This is the single largest risk in the contract and it exists by design rather than by mistake, so it needs to be addressed through governance controls rather than a code fix alone.

medium Issues | 7 findings

Pending

#1 medium Issue
Changing the asset or the native sentinel leaves stale unlimited approvals
HyperfolioVault.sol
L190-204
Description

The asset and the native currency sentinel can each be changed while a strategy is attached. Neither setter revokes the unlimited allowance granted under the previous configuration, and neither grants an allowance for the new one. The outcome is a strategy that still holds an unlimited approval over a token the vault no longer uses, together with no approval at all over the token it now does use, so deposits fail until a strategy is attached again. Changing the sentinel can also flip the vault between token mode and native mode without touching the strategy, leaving the two out of step in a way neither can detect. The guard on both setters checks the recorded total rather than the real balance, so a vault holding stray funds still passes it.

Pending

#2 medium Issue
Deposit size is derived from a balance that includes the strategy's self-reported figure
HyperfolioVault.sol
L309-314
Description

The deposit path sizes the credit from the difference between two readings of a combined figure that adds the vault's own holdings to whatever the strategy reports. Any movement in the strategy's reported balance during the token transfer is therefore attributed to the depositor. An asset with a transfer hook, or a strategy whose reported balance moves for an unrelated reason, lets a depositor capture value they never supplied, and a figure that moves downwards makes the subtraction revert and blocks deposits entirely. The strategy's report is accepted without any bound or sanity check even though it is a single external source that the vault does not control. The severity of this depends on the asset. A periodic or oracle-driven rebase cannot be captured this way, because it does not occur during the transfer, and neither can yield already sitting in the pool or a harvest performed in the pre-deposit hook, which is snapshotted beforehand. A reflection-on-transfer asset is capturable but the amount is bounded by the reflection on that single transfer. An asset that hands control to third-party code during the transfer is capturable without any bound at all, and was measured crediting 5,001 for a single token deposited. The rating reflects the fact that choosing such an asset is an owner decision rather than something an attacker selects, and it should be treated as high if any hooked, reflection or transfer-rebasing asset enters the intended asset set.

Pending

#3 medium Issue
Native currency sent to a token-mode vault is permanently locked
HyperfolioVault.sol
L256
L401
Description

The deposit entry point is payable and the contract exposes an open receive function, but neither checks the vault's operating mode and neither reconciles the value sent against the amount requested. Native currency arriving while the vault is configured for a token is recorded nowhere and cannot be withdrawn, because the withdrawal path only ever moves the configured asset. There is no rescue function, so the funds are lost outright. The open receive function also accepts value from any sender rather than only from the strategy returning funds, which widens the surface for accidental loss.

Pending

#4 medium Issue
The strategy's asset is never validated against the vault's asset
HyperfolioVault.sol
L144-178
Description

A strategy is attached with no check that it is even a contract and no check that the asset it declares matches the asset the vault holds. The strategy interface exposes an asset accessor for precisely this purpose and it is never called anywhere in the vault. Attaching a mismatched or codeless strategy still succeeds, still grants an unlimited allowance and still pushes the vault's entire balance out. In the codeless case the push reports success while the funds go somewhere they cannot be retrieved from, so a single mistyped address is enough to lose everything the vault holds.

Pending

#5 medium Issue
Withdrawals never verify that the strategy actually paid the recipient
HyperfolioVault.sol
L340-376
Description

The withdrawal path reduces the user's recorded balance and the recorded total by the requested amount, hands the payment off to the strategy, and returns the requested figure to the caller. It never establishes any post-condition on that hand-off. A strategy that transfers less than asked, or nothing at all, satisfies the call as long as it does not revert, and the user's entire claim is cleared against it with no error and no signal to the gateway. This was reproduced with an ordinary token that charges no fee whatsoever: a strategy retaining five percent left the user with 950 while the vault reported 1,000 withdrawn, and a strategy whose withdrawal is a no-op erased the claim entirely while reporting success. The value stays inside the strategy. The same gap exists on the native path. Note that where the asset itself charges a transfer fee, the shortfall the recipient sees is properly borne by the withdrawing user and is not a defect - the vault did release the full requested amount.

Pending

#6 medium Issue
Strategy yield is never accounted for and cannot reach users
HyperfolioVault.sol
L227-241
L340-376
Description

The vault records deposits as principal and pays withdrawals against that principal. Any profit the strategy earns raises the balance the vault reports but never raises any user's entitlement, so it accumulates in a pool that nobody can claim. The strategy interface declares functions for harvesting and claiming rewards and the vault calls neither. Users receive exactly what they put in, which contradicts the stated purpose of delegating funds to a strategy for yield, and the unassigned surplus becomes a standing incentive for whoever is able to reconfigure the vault.

Pending

#7 medium Issue
No pause, no emergency withdrawal and no circuit breaker
HyperfolioVault.sol
Lcontract-wide
Description

The vault holds all deposited value, routes everything through a single external strategy, and offers no way to stop accepting deposits while an incident is being investigated. There is no guardian role, no emergency path that bypasses the strategy and no rate limiting on any privileged action. When something goes wrong the only available response is to change configuration, and the functions that do so themselves depend on the strategy being healthy, which is exactly the condition that will not hold during an incident.

low Issues | 10 findings

Pending

#1 low Issue
The transfer helper treats calls into addresses with no code as successful transfers
TransferTokenHelper.sol
L23-52
Description

The helper performs a low level call and accepts the outcome whenever the call succeeded and either returned nothing or returned a truthy value. A call into an address with no code always succeeds and returns nothing, so a transfer to a non existent token is reported as a success. The vault reaches this path when it is configured with an asset that is not a contract, or when a mode change points it at an address that never held code, and it will then update its ledger against a transfer that never happened. The helper is generic, so any future caller inherits the same blind spot.

Pending

#2 low Issue
Ownership can be renounced and ownership transfer is single-step
HyperfolioVault.sol
L36
Description

The contract inherits an ownership module that lets the owner renounce ownership outright and transfer it to any address in one step. Renouncing is unusually damaging here because several recovery paths, including detaching a failed strategy, are owner only. A renounced vault with a broken strategy is permanently frozen with user funds inside it and nobody able to act. A single step transfer also allows ownership to be handed to a mistyped or uncontrolled address with no way to reverse the mistake.

Pending

#3 low Issue
Amount parameters are unvalidated on both the deposit and the withdrawal path
HyperfolioVault.sol
L256-277
Description

In native mode the credited amount is taken from the value attached to the call while the amount parameter is ignored entirely, so a caller can pass one figure and send another without anything objecting. Neither entry point rejects a zero amount either. A zero-amount withdrawal is particularly odd: the balance check passes trivially for any address, so the call succeeds for someone who has never deposited, emits a withdrawal event and reaches into the strategy with a zero amount. On the handful of tokens that reject zero-value transfers the call reverts instead, though only that call - the ledger is untouched and real withdrawals continue to work, so this is an input-validation gap rather than a denial of service. The more notable consequence is that a zero-amount deposit is a free trigger for the strategy's pre-deposit hook, which can be fired repeatedly without moving any value.

Pending

#4 low Issue
Missing zero-address validation on configuration setters
HyperfolioVault.sol
L122-132
L182-195
Description

The gateway address and the asset address can both be set to the zero address, and the initialiser performs no validation on either. A zero gateway makes every deposit and withdrawal permanently unreachable, because the access check can never pass again. A zero asset makes the vault interact with an address that has no code, where the transfer helper reports success without moving anything, so the ledger drifts away from reality with no error surfaced.

Pending

#5 low Issue
The strategy setter writes state after its external calls and has no reentrancy guard
HyperfolioVault.sol
L144-178
Description

Attaching a strategy calls into the outgoing strategy to unwind it, then writes the new strategy to storage, then approves and funds the new strategy. External calls therefore occur both before and after the state write, and the function carries no reentrancy protection even though the deposit and withdrawal paths do. A cooperating outgoing strategy can re-enter while the stored pointer still refers to it. The exposure is bounded because only the owner can start the sequence, which is why the rating stays low, but the ordering is the wrong way round for a function that moves the entire balance.

Pending

#6 low Issue
Initialisation is unprotected against front-running and emits no event
HyperfolioVault.sol
L122-132
Description

The initialiser is a plain public function guarded only by the one time initialiser modifier. If the proxy is deployed without being initialised in the same transaction, anyone can call it first and become the owner of a vault whose address has already been published. The implementation does disable its own initialisers in the constructor, which correctly prevents the implementation itself from being claimed, so the exposure is limited to the deployment procedure rather than to the code. No event is emitted, so the resulting configuration cannot be verified from logs afterwards.

Pending

#7 low Issue
Upgrade authorisation is entirely off-contract and has no delay
HyperfolioVault.sol
L32-36
Description

The contract is written for a proxy - it uses the upgradeable base contracts, disables its own initialisers and reserves a block of storage slots - but it inherits no upgrade module, so there is no upgrade entry point and no authorisation hook anywhere in the audited code. Whoever controls the external proxy administrator can replace the implementation at will, with no delay, no event at this layer and no record visible from the vault itself. The documentation does not state which proxy pattern is intended, so the real upgrade authority could not be assessed as part of this review.

Pending

#8 low Issue
Configuration guards check the recorded total rather than the actual balance
HyperfolioVault.sol
L191
L200
Description

The asset setter and the sentinel setter both permit a change only while the recorded total is zero. That figure is the vault's own bookkeeping, not its real holdings. A vault can hold stray tokens, residual dust from a fee charging asset, or funds a strategy returned outside a withdrawal, and still report a zero total. The guard therefore allows a configuration change that abandons real value, and the shortfall described in the fee-on-transfer finding makes the two figures diverge during ordinary operation rather than only in unusual cases.

Pending

#9 low Issue
The pre-deposit hook observes a native balance that already includes the incoming deposit
HyperfolioVault.sol
L261-268
Description

On the native path the vault calls the strategy's pre-deposit hook from inside a payable function, so the value attached to the call is already part of the vault's balance when the hook runs. A hook that reads the vault's balance to decide how much to harvest, or to price anything, sees a figure inflated by the deposit currently being processed. The token path does not behave this way, because there the transfer happens after the hook. The practical impact depends entirely on what a given strategy does inside the hook, but the inconsistency between the two paths is not something a strategy author would expect.

Pending

#10 low Issue
Inconsistent and floating compiler pragmas across the codebase
IStrategy.sol
L2
Description

One interface accepts any compiler from the 0.8 series while the other three files require at least 0.8.24. A floating pragma means the same source can be compiled by different compiler versions with different code generation and different known issues, which undermines reproducible builds and makes verification against deployed bytecode harder than it needs to be. The contract also relies on transient storage and therefore needs a chain that supports it, and nothing in the source enforces that beyond the pragma range.

optimization Issues | 8 findings

Pending

#1 optimization Issue
Repeated storage reads of the asset, strategy and sentinel within a single call
HyperfolioVault.sol
L227-241
L305-325
L351-375
Description

The asset, strategy and native sentinel variables are each read from storage several times inside the same function. The balance accessor reads the asset and the strategy up to four times between them, and the deposit and withdrawal paths repeat the same reads. Each repeat is a full storage load that the compiler cannot eliminate because external calls sit in between.

Pending

#2 optimization Issue
The combined balance accessor is invoked twice to size a single deposit
HyperfolioVault.sol
L309-313
Description

Sizing a single deposit calls the combined balance accessor twice, and each of those calls performs a token balance query plus a call into the strategy. Four external calls are made to establish a number that could be obtained from the vault's own balance with two.

Pending

#3 optimization Issue
Long revert strings instead of custom errors
TransferTokenHelper.sol
L25
L37
L51
L62
Description

Requirement checks throughout the vault and the transfer helper use string messages, several of which exceed thirty two bytes and therefore occupy multiple words of both deployment code and revert data. There are fourteen such checks across the codebase, eight of them with strings long enough to spill into a second word.

Pending

#4 optimization Issue
Public functions that are never called internally
HyperfolioVault.sol
L122
L256
L340
Description

The initialiser and both entry points are declared public but are never called from inside the contract. A public function has to copy its arguments into memory to support internal invocation that never happens here.

Pending

#5 optimization Issue
Single-member struct forces a struct load on every balance access
HyperfolioVault.sol
L45-47
L75
Description

Per-user balances are held in a struct with one member, so every read and write goes through a struct load rather than reading the slot directly. The wrapper provides no packing benefit because the single member already occupies a full slot.

Pending

#6 optimization Issue
Long-form assignment instead of compound assignment on accumulators
HyperfolioVault.sol
L287-288
L316-317
L348-349
Description

Ledger updates are written in long form, reading the variable, adding or subtracting, then writing it back, rather than using the compound assignment operators. On the withdrawal path the two subtractions are also guarded by a preceding bound check, so their overflow checks are redundant.

Pending

#7 optimization Issue
Internal transfer helpers with a single call site each
HyperfolioVault.sol
L384-397
Description

The two internal helpers that push funds to the strategy are each called from exactly one place, and each re-reads the strategy from storage even though the caller has just read it. The indirection costs a jump and a redundant storage load without improving readability.

Pending

#8 optimization Issue
Redundant type casts on variables that already hold that type
HyperfolioVault.sol
L155
L170
L230
L236
L292
L321
L355
L367
Description

The asset and strategy variables are repeatedly wrapped in casts to the interface types they already hold. There are eight such casts across the contract.

informational Issues | 13 findings

Pending

#1 informational Issue
Unused approval helper that lacks the reset non-standard tokens require
TransferTokenHelper.sol
L23-26
Description

The approval helper in the shared transfer library is never called by any contract in scope, because the vault uses the forced approval routine from its dependency instead. It is also the one helper that most needs care, since it writes a new allowance without first resetting it to zero, which several widely used tokens require. Dead code that is weaker than the live path is a hazard rather than a neutral leftover.

Pending

#2 informational Issue
Storage gap size is unconventional and undocumented
HyperfolioVault.sol
L78
Description

The reserved storage gap is fifty slots sitting on top of six declared slots, giving a fifty six slot footprint. The usual convention sizes the gap so the total reaches a round number, which would be forty four here. Either choice works, but the value chosen should be written down, because the only thing preventing a future upgrade from corrupting user balances is that whoever adds state remembers to shrink the gap by the same amount.

Pending

#3 informational Issue
Documentation asserts security properties the code does not provide
HyperfolioVault.sol
L13-35
Description

The contract header claims that fee-on-transfer tokens are handled by measuring actual received amounts, which is only half true because the second transfer hop is never measured, and it claims that fund stranding is prevented, which does not hold when the strategy is unhealthy. The comments also carry finding identifiers from a previous review that mean nothing to a reader of this codebase. Both patterns encourage a reviewer or integrator to trust a guarantee that is not there.

Pending

#4 informational Issue
Public parameters use the internal naming convention
HyperfolioVault.sol
L123-125
Description

Parameters on public and external functions are prefixed with an underscore, which by widespread convention marks internal or private identifiers. There are twelve such cases across the contract. The effect is purely cosmetic but it makes the externally facing interface read like internal plumbing, which slows down anyone integrating against it.

Pending

#5 informational Issue
Configuration events omit the previous value
HyperfolioVault.sol
L87-104
Description

Every configuration change emits an event carrying only the value that was set. Off-chain monitoring therefore has to reconstruct the previous value from earlier logs, which is fragile and impossible if any log was missed. For a contract where a single configuration change can move every asset it holds, the audit trail should be self contained.

Pending

#6 informational Issue
Single-member struct adds indirection without purpose
HyperfolioVault.sol
L45-47
Description

The per-user record is a struct containing a single amount. That shape suggests further fields were planned - a deposit timestamp, a share count, a reward debt - and never added. In its current form it adds a layer of indirection to every read and write without providing anything in return.

Pending

#7 informational Issue
Borrows tokenised-vault vocabulary without implementing the standard
HyperfolioVault.sol
Lcontract-wide
Description

The vault uses the vocabulary of the tokenised vault standard - assets, total assets, balance - without implementing that standard or any token interface at all. An integrator familiar with the standard will reasonably assume that the total assets figure reflects the value backing user claims, which here it does not, because yield is never attributed to anyone. Borrowing the names without the semantics is how integration bugs start.

Pending

#8 informational Issue
Deployment depends on chain features that are not enforced anywhere
HyperfolioVault.sol
L2
Description

The reentrancy protection uses transient storage, so the contract requires a chain that supports the Cancun rules, and the compiler settings also require at least the Shanghai rules for the zero push instruction. Neither requirement is enforced outside the compiler pragma. Deploying to a chain that lags behind on either would produce a contract whose critical paths revert, and the documentation names a chain without stating the constraint.

Pending

#9 informational Issue
Interface declares functions that no consumer ever calls
IStrategy.sol
L61-67
Description

The strategy interface declares a harvest function, a reward claim function and an asset accessor, and the vault calls none of them. The asset accessor is the one that would have prevented a mismatched strategy from being attached, and the harvest and claim functions are the ones that would have brought yield back to depositors. Unused interface surface leaves strategy authors guessing at what the vault will actually invoke.

Pending

#10 informational Issue
Asset variable is typed as a token but can hold a non-token sentinel
HyperfolioVault.sol
L59
L72
Description

The asset is declared with a token type, but in native mode it holds a sentinel address that is not a token at all. Every code path that touches it therefore has to remember to check the operating mode first, and any path that forgets will revert when it calls a token method on a non-token. The type is telling the reader something that is not true half the time.

Pending

#11 informational Issue
Public balance accessors can return mid-transaction state
HyperfolioVault.sol
L214-241
Description

The balance accessors are documented as integrator facing, but they combine the vault's own holdings with a figure the strategy reports, so a call made while a strategy interaction is in progress returns a partially updated view. An integrator that treats either accessor as a price or valuation source inside a callback will read an inconsistent state. Nothing in the contract prevents that, and nothing in the documentation warns against it.

Pending

#12 informational Issue
License declared as unlicensed across all files
HyperfolioVault.sol
L1
Description

All four files in scope declare themselves as unlicensed. That is consistent and may well be deliberate, but it is worth a conscious decision for a contract that users are being asked to place funds in, since it affects whether third parties can legitimately fork, review or build tooling against the code.

Pending

#13 informational Issue
No build configuration or dependency lockfile in the repository
HyperfolioVault.sol
Lrepository root
Description

The repository contains the contract sources but no build configuration and no dependency lockfile, even though the header comments reference a build config file that is not present. Dependency versions therefore could not be taken from the project and had to be pinned during this review at the current major release of the dependency library. Any difference between that choice and the version used for deployment would change the compiled output.