VaultV2
The VaultV2 contract is an ERC-4626 compliant vault that implements advanced asset allocation strategies across multiple adapters, fee management, timelock-protected governance, and flexible access controls.
Overview
VaultV2 extends the ERC-4626 standard with:
- Multi-adapter allocation system with configurable caps
- Timelock-protected curator functions
- Role-based access control (owner, curator, allocators, sentinels)
- Performance and management fee accrual
- Gate-based transfer restrictions
- ERC-2612 permit functionality
Immutable variables
The address of the underlying ERC-20 asset managed by the vault
The number of decimals used for vault shares (assetDecimals + decimalOffset, where decimalOffset = max(0, 18 - assetDecimals))
Virtual shares used for inflation attack protection (equals 10^decimalOffset)
State variables
Role storage
The vault owner who can set the curator and sentinels
The curator who can submit timelocked configuration changes
Gate contract that controls who can receive vault shares (address(0) disables)
Gate contract that controls who can send vault shares (address(0) disables)
Gate contract that controls who can receive assets from the vault (address(0) disables)
Gate contract that controls who can send assets to the vault (address(0) disables)
Registry contract that validates adapters (address(0) allows any adapter)
Mapping of accounts that have sentinel privileges (can revoke timelocked operations and decrease caps)
Mapping of accounts that can allocate assets across adapters
Token storage
The name of the vault token
The symbol of the vault token
Total supply of vault shares (excludes unminted fee shares)
balanceOf
mapping(address => uint256)
Mapping of account balances
allowance
mapping(address => mapping(address => uint256))
Mapping of spending allowances
nonces
mapping(address => uint256)
Nonces for ERC-2612 permit functionality
Interest storage
Total assets after first interest accrual in the current transaction (transient storage)
Last recorded total assets (use totalAssets() for current value)
Timestamp of last interest accrual
Maximum rate at which share price can increase per second (in WAD)
Curation storage
Mapping of enabled adapters
Array of adapter addresses
forceDeallocatePenalty
mapping(address => uint256)
Penalty (in WAD) for force deallocating from each adapter
Liquidity adapter storage
Adapter used for deposits and withdrawals
Data passed to the liquidity adapter
Timelock storage
timelock
mapping(bytes4 => uint256)
Timelock duration for each function selector
Functions that have been permanently disabled
executableAt
mapping(bytes => uint256)
Timestamp when each timelocked operation can be executed
Fee storage
Performance fee in WAD (max 50%)
Recipient of performance fees
Management fee per second in WAD (max 5% APR)
Recipient of management fees
View functions
adaptersLength
function adaptersLength() external view returns (uint256)
Returns the number of adapters.
The length of the adapters array
totalAssets
function totalAssets() external view returns (uint256)
Returns the total assets managed by the vault after accruing interest.
The current total assets including accrued interest
DOMAIN_SEPARATOR
function DOMAIN_SEPARATOR() public view returns (bytes32)
Returns the EIP-712 domain separator for permit signatures.
The domain separator hash
absoluteCap
function absoluteCap(bytes32 id) external view returns (uint256)
Returns the absolute cap for a given allocation ID.
The allocation ID (keccak256 hash of idData)
The absolute cap in asset units
relativeCap
function relativeCap(bytes32 id) external view returns (uint256)
Returns the relative cap for a given allocation ID.
The relative cap in WAD (relative to firstTotalAssets)
allocation
function allocation(bytes32 id) external view returns (uint256)
Returns the current allocation for a given ID.
The current allocation amount
accrueInterestView
function accrueInterestView() public view returns (uint256, uint256, uint256)
Calculates accrued interest and fees without updating state.
The total assets after interest accrual
Shares to mint for performance fees
Shares to mint for management fees
previewDeposit
function previewDeposit(uint256 assets) public view returns (uint256)
Previews the number of shares that would be minted for a deposit.
The amount of assets to deposit
The number of shares that would be minted
previewMint
function previewMint(uint256 shares) public view returns (uint256)
Previews the amount of assets required to mint a given number of shares.
The number of shares to mint
The amount of assets required
previewWithdraw
function previewWithdraw(uint256 assets) public view returns (uint256)
Previews the number of shares that would be burned for a withdrawal.
The amount of assets to withdraw
The number of shares that would be burned
previewRedeem
function previewRedeem(uint256 shares) public view returns (uint256)
Previews the amount of assets that would be withdrawn for redeeming shares.
The number of shares to redeem
The amount of assets that would be withdrawn
convertToShares
function convertToShares(uint256 assets) external view returns (uint256)
Converts assets to shares (rounded down), accounting for fees.
The equivalent number of shares
convertToAssets
function convertToAssets(uint256 shares) external view returns (uint256)
Converts shares to assets (rounded down), accounting for fees.
The equivalent amount of assets
maxDeposit
function maxDeposit(address) external pure returns (uint256)
Returns the maximum deposit amount (always 0 due to gate uncertainty).
maxMint
function maxMint(address) external pure returns (uint256)
Returns the maximum mint amount (always 0 due to gate uncertainty).
maxWithdraw
function maxWithdraw(address) external pure returns (uint256)
Returns the maximum withdrawal amount (always 0 due to gate uncertainty).
maxRedeem
function maxRedeem(address) external pure returns (uint256)
Returns the maximum redeem amount (always 0 due to gate uncertainty).
canReceiveShares
function canReceiveShares(address account) public view returns (bool)
Checks if an account can receive vault shares.
True if the account can receive shares
canSendShares
function canSendShares(address account) public view returns (bool)
Checks if an account can send vault shares.
True if the account can send shares
canReceiveAssets
function canReceiveAssets(address account) public view returns (bool)
Checks if an account can receive assets from the vault.
True if the account can receive assets (vault itself is always allowed)
canSendAssets
function canSendAssets(address account) public view returns (bool)
Checks if an account can send assets to the vault.
True if the account can send assets
Constructor
constructor(address _owner, address _asset)
Initializes a new VaultV2 instance.
The initial owner of the vault
The underlying ERC-20 asset address
Public functions
multicall
function multicall(bytes[] calldata data) external
Executes multiple calls in a single transaction using delegatecall.
Array of encoded function calls
accrueInterest
function accrueInterest() public
Accrues interest and mints fee shares. Called automatically on first interaction per transaction.
Owner functions
These functions can only be called by the vault owner.
setOwner
function setOwner(address newOwner) external
Sets a new owner.
The address of the new owner
setCurator
function setCurator(address newCurator) external
Sets a new curator.
The address of the new curator
setIsSentinel
function setIsSentinel(address account, bool newIsSentinel) external
Grants or revokes sentinel role.
True to grant sentinel role, false to revoke
setName
function setName(string memory newName) external
Sets the vault token name.
setSymbol
function setSymbol(string memory newSymbol) external
Sets the vault token symbol.
Timelock functions
These functions manage the timelock system for curator functions.
submit
function submit(bytes calldata data) external
Submits a timelocked operation. Can only be called by the curator.
The encoded function call data
revoke
function revoke(bytes calldata data) external
Revokes a pending timelocked operation. Can be called by curator or sentinels.
The encoded function call data to revoke
Curator functions
These functions are timelocked and can only be executed by the curator after the timelock expires.
setIsAllocator
function setIsAllocator(address account, bool newIsAllocator) external
Grants or revokes allocator role (timelocked).
True to grant allocator role, false to revoke
setReceiveSharesGate
function setReceiveSharesGate(address newReceiveSharesGate) external
Sets the receive shares gate (timelocked).
The new gate address (address(0) to disable)
setSendSharesGate
function setSendSharesGate(address newSendSharesGate) external
Sets the send shares gate (timelocked).
The new gate address (address(0) to disable)
setReceiveAssetsGate
function setReceiveAssetsGate(address newReceiveAssetsGate) external
Sets the receive assets gate (timelocked).
The new gate address (address(0) to disable)
setSendAssetsGate
function setSendAssetsGate(address newSendAssetsGate) external
Sets the send assets gate (timelocked).
The new gate address (address(0) to disable)
setAdapterRegistry
function setAdapterRegistry(address newAdapterRegistry) external
Sets the adapter registry (timelocked). Validates existing adapters against the new registry.
The new adapter registry address (address(0) to disable)
addAdapter
function addAdapter(address account) external
Adds an adapter (timelocked). Validates against adapter registry if set.
The adapter address to add
removeAdapter
function removeAdapter(address account) external
Removes an adapter (timelocked).
The adapter address to remove
increaseTimelock
function increaseTimelock(bytes4 selector, uint256 newDuration) external
Increases the timelock duration for a function (timelocked).
The function selector (cannot be decreaseTimelock)
The new timelock duration in seconds
decreaseTimelock
function decreaseTimelock(bytes4 selector, uint256 newDuration) external
Decreases the timelock duration for a function (timelocked with the original function’s timelock).
The function selector (cannot be decreaseTimelock)
The new timelock duration in seconds
abdicate
function abdicate(bytes4 selector) external
Permanently disables a timelocked function (timelocked).
The function selector to abdicate
function setPerformanceFee(uint256 newPerformanceFee) external
Sets the performance fee (timelocked). Accrues interest before changing.
The new performance fee in WAD (max 0.5e18 = 50%)
setManagementFee
function setManagementFee(uint256 newManagementFee) external
Sets the management fee (timelocked). Accrues interest before changing.
The new management fee per second in WAD (max 5% APR)
function setPerformanceFeeRecipient(address newPerformanceFeeRecipient) external
Sets the performance fee recipient (timelocked). Accrues interest before changing.
newPerformanceFeeRecipient
The new recipient address
setManagementFeeRecipient
function setManagementFeeRecipient(address newManagementFeeRecipient) external
Sets the management fee recipient (timelocked). Accrues interest before changing.
newManagementFeeRecipient
The new recipient address
increaseAbsoluteCap
function increaseAbsoluteCap(bytes memory idData, uint256 newAbsoluteCap) external
Increases the absolute cap for an allocation ID (timelocked).
The allocation ID data (hashed to get the ID)
decreaseAbsoluteCap
function decreaseAbsoluteCap(bytes memory idData, uint256 newAbsoluteCap) external
Decreases the absolute cap for an allocation ID. Can be called by curator or sentinels (not timelocked for sentinels).
increaseRelativeCap
function increaseRelativeCap(bytes memory idData, uint256 newRelativeCap) external
Increases the relative cap for an allocation ID (timelocked).
The new relative cap in WAD (max 1e18 = 100%)
decreaseRelativeCap
function decreaseRelativeCap(bytes memory idData, uint256 newRelativeCap) external
Decreases the relative cap for an allocation ID. Can be called by curator or sentinels (not timelocked for sentinels).
The new relative cap in WAD
setForceDeallocatePenalty
function setForceDeallocatePenalty(address adapter, uint256 newForceDeallocatePenalty) external
Sets the penalty for force deallocating from an adapter (timelocked).
newForceDeallocatePenalty
The penalty in WAD (max 0.02e18 = 2%)
Allocator functions
These functions can be called by accounts with the allocator role.
allocate
function allocate(address adapter, bytes memory data, uint256 assets) external
Allocates assets to an adapter. Checks caps after allocation.
Data to pass to the adapter
Amount of assets to allocate
deallocate
function deallocate(address adapter, bytes memory data, uint256 assets) external
Deallocates assets from an adapter. Can also be called by sentinels.
Data to pass to the adapter
Amount of assets to deallocate
setLiquidityAdapterAndData
function setLiquidityAdapterAndData(address newLiquidityAdapter, bytes memory newLiquidityData) external
Sets the liquidity adapter and data used for deposits and withdrawals.
The new liquidity adapter address
The data to pass to the liquidity adapter
setMaxRate
function setMaxRate(uint256 newMaxRate) external
Sets the maximum rate at which the share price can increase. Accrues interest before changing.
The new max rate per second in WAD (max 200% APR)
User functions
deposit
function deposit(uint256 assets, address onBehalf) external returns (uint256)
Deposits assets and mints shares.
Amount of assets to deposit
Address to receive the shares
mint
function mint(uint256 shares, address onBehalf) external returns (uint256)
Mints exact shares by depositing assets.
Address to receive the shares
Amount of assets deposited
withdraw
function withdraw(uint256 assets, address receiver, address onBehalf) public returns (uint256)
Withdraws exact assets by burning shares.
Amount of assets to withdraw
Address to receive the assets
Address to burn shares from
redeem
function redeem(uint256 shares, address receiver, address onBehalf) external returns (uint256)
Redeems shares for assets.
Number of shares to redeem
Address to receive the assets
Address to burn shares from
Amount of assets withdrawn
forceDeallocate
function forceDeallocate(address adapter, bytes memory data, uint256 assets, address onBehalf) external returns (uint256)
Forces deallocation from an adapter and applies a penalty. Useful for exiting when liquidity is limited.
The adapter to deallocate from
Data to pass to the adapter
Amount of assets to deallocate
Address to apply the penalty to
Number of penalty shares withdrawn
ERC-20 functions
transfer
function transfer(address to, uint256 shares) external returns (bool)
Transfers shares to another address.
Number of shares to transfer
Always returns true (reverts on failure)
transferFrom
function transferFrom(address from, address to, uint256 shares) external returns (bool)
Transfers shares from one address to another.
Number of shares to transfer
Always returns true (reverts on failure)
approve
function approve(address spender, uint256 shares) external returns (bool)
Approves an address to spend shares.
Number of shares to approve
Always returns true (reverts on failure)
permit
function permit(address _owner, address spender, uint256 shares, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external
Approves spending via EIP-2612 signature.
Number of shares to approve
Events
Constructor
event Constructor(address indexed owner, address indexed asset)
Emitted when the vault is created.
SetOwner
event SetOwner(address indexed newOwner)
Emitted when the owner is changed.
SetCurator
event SetCurator(address indexed newCurator)
Emitted when the curator is changed.
SetIsSentinel
event SetIsSentinel(address indexed account, bool newIsSentinel)
Emitted when a sentinel role is granted or revoked.
SetName
event SetName(string newName)
Emitted when the token name is changed.
SetSymbol
event SetSymbol(string newSymbol)
Emitted when the token symbol is changed.
Submit
event Submit(bytes4 indexed selector, bytes data, uint256 executableAt)
Emitted when a timelocked operation is submitted.
Revoke
event Revoke(address indexed sender, bytes4 indexed selector, bytes data)
Emitted when a timelocked operation is revoked.
Accept
event Accept(bytes4 indexed selector, bytes data)
Emitted when a timelocked operation is executed.
SetIsAllocator
event SetIsAllocator(address indexed account, bool newIsAllocator)
Emitted when an allocator role is granted or revoked.
SetReceiveSharesGate
event SetReceiveSharesGate(address indexed newReceiveSharesGate)
Emitted when the receive shares gate is changed.
SetSendSharesGate
event SetSendSharesGate(address indexed newSendSharesGate)
Emitted when the send shares gate is changed.
SetReceiveAssetsGate
event SetReceiveAssetsGate(address indexed newReceiveAssetsGate)
Emitted when the receive assets gate is changed.
SetSendAssetsGate
event SetSendAssetsGate(address indexed newSendAssetsGate)
Emitted when the send assets gate is changed.
SetAdapterRegistry
event SetAdapterRegistry(address indexed newAdapterRegistry)
Emitted when the adapter registry is changed.
AddAdapter
event AddAdapter(address indexed account)
Emitted when an adapter is added.
RemoveAdapter
event RemoveAdapter(address indexed account)
Emitted when an adapter is removed.
IncreaseTimelock
event IncreaseTimelock(bytes4 indexed selector, uint256 newDuration)
Emitted when a function’s timelock duration is increased.
DecreaseTimelock
event DecreaseTimelock(bytes4 indexed selector, uint256 newDuration)
Emitted when a function’s timelock duration is decreased.
Abdicate
event Abdicate(bytes4 indexed selector)
Emitted when a function is abdicated.
event SetPerformanceFee(uint256 newPerformanceFee)
Emitted when the performance fee is changed.
event SetPerformanceFeeRecipient(address indexed newPerformanceFeeRecipient)
Emitted when the performance fee recipient is changed.
SetManagementFee
event SetManagementFee(uint256 newManagementFee)
Emitted when the management fee is changed.
SetManagementFeeRecipient
event SetManagementFeeRecipient(address indexed newManagementFeeRecipient)
Emitted when the management fee recipient is changed.
IncreaseAbsoluteCap
event IncreaseAbsoluteCap(bytes32 indexed id, bytes idData, uint256 newAbsoluteCap)
Emitted when an absolute cap is increased.
DecreaseAbsoluteCap
event DecreaseAbsoluteCap(address indexed sender, bytes32 indexed id, bytes idData, uint256 newAbsoluteCap)
Emitted when an absolute cap is decreased.
IncreaseRelativeCap
event IncreaseRelativeCap(bytes32 indexed id, bytes idData, uint256 newRelativeCap)
Emitted when a relative cap is increased.
DecreaseRelativeCap
event DecreaseRelativeCap(address indexed sender, bytes32 indexed id, bytes idData, uint256 newRelativeCap)
Emitted when a relative cap is decreased.
SetForceDeallocatePenalty
event SetForceDeallocatePenalty(address indexed adapter, uint256 forceDeallocatePenalty)
Emitted when a force deallocate penalty is set.
Allocate
event Allocate(address indexed sender, address indexed adapter, uint256 assets, bytes32[] ids, int256 change)
Emitted when assets are allocated to an adapter.
Deallocate
event Deallocate(address indexed sender, address indexed adapter, uint256 assets, bytes32[] ids, int256 change)
Emitted when assets are deallocated from an adapter.
ForceDeallocate
event ForceDeallocate(address indexed sender, address adapter, uint256 assets, address indexed onBehalf, bytes32[] ids, uint256 penaltyAssets)
Emitted when assets are force deallocated with a penalty.
SetLiquidityAdapterAndData
event SetLiquidityAdapterAndData(address indexed sender, address indexed newLiquidityAdapter, bytes indexed newLiquidityData)
Emitted when the liquidity adapter and data are changed.
SetMaxRate
event SetMaxRate(uint256 newMaxRate)
Emitted when the max rate is changed.
AccrueInterest
event AccrueInterest(uint256 previousTotalAssets, uint256 newTotalAssets, uint256 performanceFeeShares, uint256 managementFeeShares)
Emitted when interest is accrued.
Deposit
event Deposit(address indexed sender, address indexed onBehalf, uint256 assets, uint256 shares)
Emitted when assets are deposited.
Withdraw
event Withdraw(address indexed sender, address indexed receiver, address indexed onBehalf, uint256 assets, uint256 shares)
Emitted when assets are withdrawn.
Transfer
event Transfer(address indexed from, address indexed to, uint256 shares)
Emitted when shares are transferred.
Approval
event Approval(address indexed owner, address indexed spender, uint256 shares)
Emitted when an approval is made.
AllowanceUpdatedByTransferFrom
event AllowanceUpdatedByTransferFrom(address indexed owner, address indexed spender, uint256 shares)
Emitted when allowance is updated by transferFrom.
Permit
event Permit(address indexed owner, address indexed spender, uint256 shares, uint256 nonce, uint256 deadline)
Emitted when a permit is used.
Errors
The VaultV2 contract uses the following custom errors from ErrorsLib:
Abdicated() - Function has been abdicated
AbsoluteCapExceeded() - Allocation exceeds absolute cap
AbsoluteCapNotDecreasing() - New absolute cap is not decreasing
AbsoluteCapNotIncreasing() - New absolute cap is not increasing
AutomaticallyTimelocked() - Cannot modify timelock of decreaseTimelock
CannotReceiveShares() - Account cannot receive shares (gate restriction)
CannotReceiveAssets() - Account cannot receive assets (gate restriction)
CannotSendShares() - Account cannot send shares (gate restriction)
CannotSendAssets() - Account cannot send assets (gate restriction)
DataAlreadyPending() - Operation already submitted
DataNotTimelocked() - Operation not submitted for timelock
FeeInvariantBroken() - Fee recipient required when fee is non-zero
FeeTooHigh() - Fee exceeds maximum allowed
InvalidSigner() - Permit signature is invalid
MaxRateTooHigh() - Max rate exceeds allowed maximum
NotAdapter() - Address is not an approved adapter
NotInAdapterRegistry() - Adapter not in registry
PenaltyTooHigh() - Force deallocate penalty exceeds maximum
PermitDeadlineExpired() - Permit deadline has passed
RelativeCapAboveOne() - Relative cap exceeds 100%
RelativeCapExceeded() - Allocation exceeds relative cap
RelativeCapNotDecreasing() - New relative cap is not decreasing
RelativeCapNotIncreasing() - New relative cap is not increasing
TimelockNotDecreasing() - New timelock is not decreasing
TimelockNotExpired() - Timelock period has not expired
TimelockNotIncreasing() - New timelock is not increasing
Unauthorized() - Caller is not authorized
ZeroAbsoluteCap() - Cannot allocate to ID with zero absolute cap
ZeroAddress() - Address cannot be zero
ZeroAllocation() - Cannot deallocate from ID with zero allocation
Constants
WAD - 1e18 (used for fee and rate calculations)
MAX_MAX_RATE - 200% APR (maximum allowed maxRate)
MAX_PERFORMANCE_FEE - 0.5e18 (50%, maximum performance fee)
MAX_MANAGEMENT_FEE - 0.05e18 / 365 days (5% APR, maximum management fee)
MAX_FORCE_DEALLOCATE_PENALTY - 0.02e18 (2%, maximum force deallocate penalty)