[VPD-633] Venus Fixed Rate Vault × Ceffu #52
Open
Debugger022 wants to merge 32 commits intodevelopfrom
Open
Conversation
- VaultFactory: deploys and registers vaults via `deployVault()`, with deterministic addressing derived from ceffuRequestId salt - VaultFactoryStorage: storage layout with vault registry mappings (by address, index, and ceffuRequestId) and 44-slot upgrade gap - IVaultFactory: interface defining events, errors, and external API
- FixedRateVault: ERC-4626 tokenized vault with four-state lifecycle (Fundraising → Locked → Matured / Cancelled), per-user deposit limits, auto-close on maxCap, protocol reserve extraction, and emergency unlock - FixedRateVaultStorage: storage layout with packed slot optimization, config fields, runtime state, user deposit tracking, and 33-slot gap - IFixedRateVault: interface defining VaultState enum, VaultInitParams struct, lifecycle events, custom errors, and external API
…effu - FundRouter: five-step fund flow (receiveFundsFromVault → setCeffuAddress → transferToCeffu → recordRepayment → distributeRepaymentToVault) with boolean idempotency guards, asset whitelist, and token sweep recovery - FundRouterStorage: per-vault VaultAllocation tracking, approved assets whitelist, and 47-slot upgrade gap - IFundRouter: interface defining VaultAllocation struct, fund flow events, idempotency errors, and external API
- IFixedRateVault: insert PendingFill enum between Fundraising and Locked, add confirmOrderFill() function and OrderFillConfirmed event - FixedRateVault: fundraising close now transitions to PendingFill (not Locked), lockStartAt and lockPeriodEndTime set only on order fill confirmation, cancelVault() extended to accept PendingFill state - FixedRateVaultStorage: add lockStartAt field, adjust gap (33 → 32) - IFundRouter: add orderFillConfirmed bool to VaultAllocation struct, add confirmOrderFillForVault() function and event, recordRepayment prerequisite now requires orderFillConfirmed (not fundsSentToCeffu) - FundRouter: implement confirmOrderFillForVault() step between transferToCeffu and recordRepayment in the fund flow - FundRouterStorage: update NatSpec to reflect new fund flow
- Add deployFullSystemFixture wiring ACM, MockToken, VaultFactory, FundRouter, and FixedRateVault - Add defaultVaultParams helper for reusable vault init parameters - Test VaultFactory initialization and re-initialization guard - Test deployVault: clone creation, sequential IDs, event emission, ceffuRequestId validation, ACM access control - Test setVaultImplementation and setFundRouter admin setters with zero-address and unchanged-value reverts - Test isVault lookup and predictVaultAddress deterministic address computation - Import MockToken in ImportsV8.sol for artifact generation - Add ./tests to tsconfig.json include paths
- Test receiveRepayment via FundRouter: state transition, totalRepayment, protocolReserve calculation, event emission - Test interest edge cases: zero interest, partial loss, 1-wei rounding - Test withdrawReserves: token transfer, reservesWithdrawn flag, totalAssets invariant - Test revert conditions: OnlyFundRouter, InvalidState, ReservesAlreadyWithdrawn, NoReservesToWithdraw, ACM
- Test redeem() in Matured state: full/partial redemption, share burning, proportional multi-user distribution - Test redeem() in Cancelled state: 1:1 refund for single and multiple users - Test withdraw(): exact asset withdrawal, maxWithdraw full drain, cancelled 1:1 - Test revert conditions: blocked in Fundraising, PendingFill, and Locked states - Test redemption amount unchanged after withdrawReserves - Test ERC-4626 allowance: third-party redemption with approval, insufficient allowance revert - Test withdrawal succeeds when vault is paused
- Test initialization: ACM, vaultFactory, re-initialization guard - Test setAssetApproval: approve/revoke assets, zero-address revert, ACM access control - Test setCeffuAddressForVault: set/update ceffu wallet, non-vault revert, ACM check - Test transferToCeffu: token transfer to ceffu wallet, state transition to Locked, revert conditions - Test confirmOrderFillForVault: PendingFill → Locked transition, non-PendingFill revert - Test recordRepayment and distributeRepaymentToVault: repayment recording, distribution to vault, double-distribution revert - Test pause/unpause: blocked operations while paused, ACM access control
- remove unused variables and imports - replace non-null assertions - run prettier
- Replace non-strict inequalities (>=, <=) with negated strict form in FixedRateVault - Disable max-states-count rule for FixedRateVaultStorage (21 vars required) - Suppress gas-small-strings warnings for ACM signature strings in FundRouter - Index lockStartAt and lockPeriodEndTime params in OrderFillConfirmed event
- Prevent direct admin cancelVault() in PendingFill state to avoid zero-asset redemption bug where vault transitions to Cancelled while all funds remain stuck in FundRouter - Add FundRouter.returnFundsAndCancelVault() that atomically returns principal to the vault and then triggers cancellation, ensuring users always redeem shares for actual assets - Restrict PendingFill cancelVault() to FundRouter-only via OnlyFundRouter check; Fundraising cancel remains admin-callable - Block cancellation after transferToCeffu() with FundsAlreadySentToCeffu guard since funds are no longer on-chain recoverable - Clean up allocation state on cancel to prevent stale operations (e.g., transferToCeffu after cancel) - Update NatSpec and state machine diagram to document both cancel paths - Add comprehensive tests for returnFundsAndCancelVault happy path, revert conditions, and post-cancel redemption flow
- Add check that maxUserDeposit >= minUserDeposit when both are non-zero, preventing misconfigured vaults where no valid deposit amount exists within the allowed range - Add check that minUserDeposit <= maxCap, preventing vaults where the minimum deposit exceeds total capacity making fundraising impossible - Skip maxUserDeposit vs minUserDeposit check when either is zero to preserve the "no per-user cap" (maxUserDeposit=0) semantic - Add revert and boundary-value tests for both new validations
…und lockup - Allow anyone to call closeFundraising() after fundraisingEndTime, removing admin dependency that could leave user funds locked indefinitely if admin fails to act - Before deadline: retain admin-only access control and pause guard for early close scenarios - Cancel path (below minCap) after deadline bypasses pause check since it involves no external calls, ensuring users can always recover funds - Success path (above minCap) still requires unpaused state due to FundRouter interaction during fund transfer - Replace whenNotPaused modifier with explicit _requireNotPaused() calls to enable granular pause behavior per code path - Update NatSpec to document timing-based access control semantics - Add tests for permissionless close, paused cancel path, paused success path revert, and post-cancel 1:1 redemption flow
- Cap fixedAPY at MAX_BPS (10000 / 100%) to prevent absurd interest rates from misconfiguration or fat-finger errors - Reject fundraisingEndTime that is at or before current block.timestamp, preventing deployment of vaults with already-expired fundraising windows - Cap gracePeriod at 365 days to prevent unreasonably long grace periods that could delay user fund access indefinitely - Add revert tests for each new boundary and acceptance tests for edge values (fixedAPY=10000, gracePeriod=365 days)
…ising - Prevent closeFundraising() from being called before fundraisingStartTime, which could prematurely cancel a vault before users have any chance to deposit - Add test for revert when called before fundraisingStartTime - Fix existing tests to advance time to fundraisingStartTime before calling closeFundraising, aligning with the new guard
- Document why cancelVault() omits nonReentrant (no external calls) and whenNotPaused (emergency cancel must work during pause) - Document why confirmOrderFill() bypasses pause (blocking would trap funds in FundRouter with no path to maturity) - Document why receiveRepayment() bypasses pause (blocking would prevent users from reaching redeemable Matured state) - Note integer division truncation in calculateExpectedInterest() for dust amounts (acceptable for stablecoin use case)
…fund contamination - Introduce totalCommittedPerAsset mapping in FundRouter to track tokens reserved across all active vault allocations (principal + undistributed repayments) - Increment committed on receiveFundsFromVault and recordRepayment; decrement on transferToCeffu, distributeRepaymentToVault, and returnFundsAndCancelVault - Validate in recordRepayment that the recorded amount does not exceed free (uncommitted) balance, preventing admin error from over-allocating tokens belonging to other vaults - Add InsufficientFreeBalance error for the new guard - Update storage gap from 47 to 46 to account for the new mapping slot - Add multi-vault integration tests covering full lifecycle tracking, cross-vault over-commit prevention, and cancel decrement correctness
…add minor guards - Guard sweepToken() against sweeping committed vault funds by checking totalCommittedPerAsset, reusing InsufficientFreeBalance error - Prevent no-op setCeffuAddressForVault() calls that set the same address, adding CeffuAddressUnchanged error for clarity - Add nonReentrant modifier to confirmOrderFillForVault() since it makes an external call to vault.confirmOrderFill() - Add tests for sweepToken free vs committed balance enforcement and setCeffuAddressUnchanged revert
…for improved asset validation
- Block setCeffuAddressForVault after funds already sent to Ceffu - Prevent underflow in sweepToken when balance < committed - Fully clean up allocation on cancel (zero supplyAsset/ceffuAddress) - Validate maxUserDeposit <= maxCap during initialization - Fix misleading error state in cancelVault revert
… tests Track real token amounts received via balance-before/after pattern in FixedRateVault._deposit() and FundRouter.receiveFundsFromVault() instead of trusting the input amount. Add tests for sweepToken committed balance guard, post-transfer setCeffuAddress revert, and maxUserDeposit > maxCap validation.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduces the Venus × Ceffu Fixed Rate Vault system — a set of three smart contracts that allow Venus to deploy tokenized fixed-rate lending vaults whose underlying funds are routed to Ceffu for off-chain yield generation.
Contracts
FixedRateVault— An ERC-4626 tokenized vault deployed as an EIP-1167 minimal proxy clone. Implements a four-state lifecycle (Fundraising → PendingFill → Locked → Matured) with an additionalCancelledterminal state. Users deposit during the fundraising window and redeem shares for principal + interest after maturity. Key features include per-user deposit limits, auto-close on max cap, pause-exempt withdrawals, admin-triggered emergency unlock (after grace period), and protocol reserve collection.FundRouter— A singleton upgradeable proxy that manages the six-step fund flow between vaults and Ceffu with strict sequential ordering and idempotency guards:receiveFundsFromVault → setCeffuAddressForVault → transferToCeffu → confirmOrderFillForVault → recordRepayment → distributeRepaymentToVault. Includes asset whitelisting, sweep functionality, and selective pause controls.VaultFactory— Deploys vault clones viaClones.cloneDeterministic()usingkeccak256(ceffuRequestId)as salt for deterministic addressing. Tracks all deployed vaults by address, index, and Ceffu request ID.Interfaces
IFixedRateVault,IFundRouter,IVaultFactory— Full NatSpec-documented interfaces for all three contracts.Architecture Highlights
AccessControlledV8(Venus ACM) for permissioned operations_disableInitializers(), only deployable via factorywithdraw()/redeem()are NOT paused — users can always exit in terminal statescancelVault()is NOT paused — admin can always cancel as a safety mechanismTest plan
npx hardhat test tests/hardhat/venus-ceffu/**/*.ts)FixedRateVault
FundRouter
VaultFactory
Cross-cutting coverage