Guardian's review of Genesis Vaults Updates for Nunchi, published November 2025. The report records 18 findings across 2 review rounds, including 2 high and 9 medium.
- Published
- Review window
- October 27 to November 5, 2025
- Rounds
- Main Review, Remediation Review
- Language
- Solidity
- Chains
- Hyperliquid
- Sector
- Yield and vaults, Perpetuals
- 0 Critical
- 2 High
- 9 Medium
- 5 Low
- 2 Informational
Scope
Findings 18
Main Review
16 findings · October 27 to 28, 2025-
H-01 High Invalid Redeem Handling Logical Error Resolved
Description
VaultModule.withdraw returns the pre-penalty 'assets' value but transfers only the net assets after applying the global withdrawal penalty. GenesisVaultSYToken._redeem uses the returned value as the amount to forward to the receiver, leading it to attempt transferring more tokens than it actually received. This will either revert due to insufficient balance or, if the SY contract holds any underlying balance, overpay the user and drain those funds.
Recommendation
Make the amounts consistent. Either (a) change VaultModule.withdraw to return the netAssets actually transferred to msg.sender, or (b) change GenesisVaultSYToken._redeem to derive the net amount by tracking the SY contract’s asset balance delta (before and after withdraw) and transfer only that net amount. Also base the slippage check on the net amount.
-
H-02 High LayerZero Read Messaging Channel DoS DoS Resolved
Description
The
getUserSharesForClaimfunction is intended to be invoked by LayerZero’s lzRead function to distribute the state to other chains. It includes several revert cases if thevaultIdis incorrect or the vault is not yet fully migrated.However lzRead target functions should never revert, otherwise they would prevent DVNs from verifying the result and halt the read messaging channel, thus stopping the migration until it is manually unblocked, at which point it can be halted again.
Recommendation
Ensure the
getUserSharesForClaimnever reverts and instead returns an empty/sentinel value which can be ignored for invalid cases. -
M-01 Medium burnForMigration Avoids Withdrawal Delay Gaming Acknowledged
Description
In the
burnForMigrationfunction there is no validation that the user has passed the withdrawal delay before burning their tokens for the migration.Therefore the migration may offer a pathway for the user to exit their position in the VaultSYToken before the delay is up.
Recommendation
Consider if the withdrawalDelay should be validated before a user is allowed to invoke the
burnForMigrationfunction. -
M-02 Medium Cooldown Withdrawal DoS DoS Resolved
Description
The
depositfunction allows the caller to provide an arbitrary receiver address and the receiver is the account which will have their withdrawal cooldown assigned, preventing them from withdrawing for thewithdrawalDelayperiod.Furthermore, there is no minimum deposit amount, which means that a malicious actor could prevent users from withdrawing their assets by continually depositing 1 wei of assets on behalf the user, specifying the victim user as the
receiverand resetting theirlastDepositTime.Recommendation
Consider requiring that the receiver is the account invoking the deposit function, or that the caller is in a whitelisted group for the receiver so that this griefing cannot occur.
-
M-03 Medium Cooldown Bypass Gaming Resolved
Description
The cooldown mechanism for withdrawals can be bypassed if a user specifies the
GenesisVaultSYTokencontract as the receiver and then invokes the redeem function withburnFromInternalBalanceastrue.This way the
lastDepositTimeentry is set for theGenesisVaultSYTokencontract but never read, since theredeemfunction relies on the entry for themsg.sender.This allows users to cause a deposit on behalf of the
GenesisVaultSYTokencontract and withdrawal to arbitrary receiver within a single transaction, while bypassing the withdrawal cooldown which may be unexpected for the system.Recommendation
Consider validating that the receiver is not
address(this)in thedepositfunction to prevent users from circumventing thewithdrawalDelaythis way. -
M-04 Medium AlreadyBurned Check Bypass Validation Acknowledged
Description
The
AlreadyBurnedcheck in theburnForMigrationfunction can be bypassed by transferring the tokens to another EOA.Recommendation
Consider to prevent sending and receiving token if the user already burned or consider if this validation is necessary in general. Another solution could be to prevent transfers after the migration.
-
M-05 Medium Cooldown Withdrawal DoS Via Transfer DoS Resolved
Description
The
_beforeTokenTransferfunction of theGenesisVaultSYTokenwill update the recipient'slastDepositTimeto the one of the sender if it's bigger than the current one.This enables a withdrawal griefing DoS:
- Malicious actor deposits the minimum amount into the system and by doing so the attacker's
lastDepositTimeis set to now - Another user tries to withdraw tokens
- The malicious actor front runs the call and transfers 1 wei to the user
- The victims
lastDepositTimeis updated and therefore the withdraw fails as the withdrawal delay has not passed yet.
Recommendation
Consider to create a whitelist mechanism to allow users to configure who can send them tokens. Or to add a minimum transfer amount to make this DoS attack too expensive to realistically take place.
- Malicious actor deposits the minimum amount into the system and by doing so the attacker's
-
M-06 Medium strategyInUse Not Reset During Migration Validation Resolved
Description
If the given vault used a strategy it will be unset in the
migrateVaultflow. However thestrategyInUsemapping is not set to false and therefore the strategy can never be used again and needs to be redeployed.Recommendation
Consider to set the
strategyInUsemapping to false in that case. -
M-07 Medium Cooldown Bypass Via Internal Burn Logical Error Resolved
Description
In GenesisVaultSYToken, the redeem function enforces withdrawal delay using
lastDepositTime[msg.sender]even when burning shares directly from the contract (burnFromInternalBalance=true). An attacker can transfer their shares to the Factory contract, and then immediately redeem from a fresh account to bypass the cooldown.Recommendation
When burning from internal balance, enforce cooldown based on the balance owner whose tokens are being burned or disallow
burnFromInternalBalancepath. -
L-01 Low Users Can Deposit After Burning Warning Acknowledged
Description
The
burnForMigrationfunction states thatUsers must burn their full balance to track for cross-chain claims, and the function does indeed burn the entire user balance of the user. However there is no validation that prevents the same user from depositing again through the deposit function.This user will not be able to invoke the
burnForMigrationfunction again, however it may be unexpected for the migration that the user now has a balance in excess of what was burned previously.Recommendation
Consider if this is expected for the migration and avoid this edge case in the migration logic. If it should be prevented, consider validating that the
burnedBalancesentry for the user is zero before allowing a deposit to occur. -
L-02 Low Incorrect getUserAccountSummary output Rewards Resolved
Description
The
getUserAccountSummaryfunction calculates and returns theearnedYieldof the user.The calculation compares the deposited and withdrawn amount of the user and sums it up with the current worth of the users shares.
The comparison of the withdrawn and deposited amount takes into account the paid fees while the worth of the user's shares does not.
Recommendation
Consider to apply the withdraw penalty.
-
L-03 Low Performance Fee Is Enforced Rewards Resolved
Description
The
collectPerformanceFeefunction handles the case that no performance fee is set:if (recipient == address(0) || rate == 0 || yield == 0) { return (0, yield);}However the
harvestAndCompoundfunction which calls it early returns if no performance fee is configured:if (vault.strategy == address(0) || !hasPerformanceFeeConfigured(vault)) { return (0, 0); }Recommendation
Consider to allow not configuring a performance and giving all yield to the users in that case.
-
L-04 Low Wrong Migration Delay Configuration Acknowledged
Description
The
MIN_MIGRATION_DELAYis set to one day, while the documentation states out it is 3 days.Recommendation
Consider to update the constant or the comment.
-
L-05 Low Minimum Withdraw Applies Before Penalty Logical Error Resolved
Description
In VaultModule, withdraw function enforces
minWithdrawon gross assets before applying the withdrawal penalty. IfgrossAssetsis greater than or equal tominWithdrawbut the penalty reducesnetAssetsbelowminWithdraw, the withdrawal still succeeds, allowing dust withdrawals contrary to intended behaviour.Recommendation
Consider enforcing
minWithdrawon the post penalty amount. -
I-01 Informational Redundant Receiver Parameter Superfluous Code Acknowledged
Description
The
deposittakes in areceiverparameter but reverts if it's not themsg.sender.Recommendation
Consider to use the
msg.senderinstead. -
I-02 Informational Unused Code Superfluous Code Resolved
Description
There is unused code in multiple places:
- The
VaultNotMigratederror inErrors.sol - The
IERC165import inConfigurationModule.sol
Recommendation
Consider to remove unused code.
- The
Remediation Review
2 findings · November 5, 2025-
M-01 Medium Withdraw DoS Bypass Validation Acknowledged
Description
The
lastDepositTimeof the SY token recipient is now only increased if the recipient currently does not own tokens.This allows to bypass the withdraw delay by transferring to another EOA if the user has multiple accounts holding the SY tokens.
Recommendation
Consider to acknowledge this behavior or to create a whitelist mechanism to allow users to configure who can send them tokens and to revert the recent changes.
-
M-02 Medium getUserSharesForClaim Could Still Revert DoS Resolved
Description
The
getUserSharesForClaimfunction is intended to be invoked by LayerZero’s lzRead function to distribute the state to other chains and reverts if thevaultIdis incorrect.However lzRead target functions should never revert, otherwise they would prevent DVNs from verifying the result and halt the read messaging channel, thus stopping the migration until it is manually unblocked, at which point it can be halted again.
Recommendation
Ensure the
getUserSharesForClaimnever reverts and instead returns an empty/sentinel value which can be ignored for invalid cases.
No findings match.
More from Nunchi
Put your code through the same review.
This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.
