Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/module/AllocateModule.sol": {
"content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
import {IERC20, IERC4626} from "@openzeppelin-contracts/interfaces/IERC4626.sol";
import {IAllocateModule} from "../interface/IAllocateModule.sol";
import {IStrategyTemplate} from "../interface/IStrategyTemplate.sol";
import {IConcreteStandardVaultImpl} from "../interface/IConcreteStandardVaultImpl.sol";
import {ConcreteStandardVaultImplStorageLib} from "../lib/storage/ConcreteStandardVaultImplStorageLib.sol";
import {SafeCast} from "@openzeppelin-contracts/utils/math/SafeCast.sol";
import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol";
contract AllocateModule is IAllocateModule {
using SafeCast for uint256;
using SafeERC20 for IERC20;
/// @inheritdoc IAllocateModule
function allocateFunds(bytes calldata data) external {
AllocateParams[] memory params = abi.decode(data, (AllocateParams[]));
ConcreteStandardVaultImplStorageLib.ConcreteStandardVaultImplStorage storage $ =
ConcreteStandardVaultImplStorageLib.fetch();
for (uint256 i; i < params.length; ++i) {
// Only allocate to Active strategies
if ($.strategyData[params[i].strategy].status != IConcreteStandardVaultImpl.StrategyStatus.Active) {
continue;
}
uint256 amount;
if (params[i].isDeposit) {
IERC20(IERC4626(address(this)).asset()).forceApprove(params[i].strategy, type(uint256).max);
amount = IStrategyTemplate(params[i].strategy).allocateFunds(params[i].extraData);
IERC20(IERC4626(address(this)).asset()).forceApprove(params[i].strategy, 0);
$.strategyData[params[i].strategy].allocated += amount.toUint120();
} else {
amount = IStrategyTemplate(params[i].strategy).deallocateFunds(params[i].extraData);
$.strategyData[params[i].strategy].allocated -= amount.toUint120();
}
emit AllocatedFunds(params[i].strategy, params[i].isDeposit, amount, params[i].extraData);
}
}
}
"
},
"node_modules/@openzeppelin/contracts/interfaces/IERC4626.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC-4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}
"
},
"src/interface/IAllocateModule.sol": {
"content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/**
* @title IAllocateModule
* @dev Interface for the AllocateModule contract that handles fund allocation and deallocation across multiple strategies.
* @dev This module enables the vault to efficiently manage funds across different yield-generating strategies
* by batching multiple allocation/deallocation operations in a single transaction.
*
* @notice The AllocateModule serves as a coordinator for strategy operations, allowing the vault to:
* - Allocate funds to multiple strategies in a single call
* - Deallocate funds from multiple strategies in a single call
* - Maintain accurate accounting of allocated amounts per strategy
*
* @notice This module is typically used during rebalancing operations where the vault needs to
* adjust allocations across multiple strategies based on current market conditions,
* strategy performance, or allocation targets.
*/
interface IAllocateModule {
/**
* @dev Emitted when funds are allocated or deallocated from a strategy.
*
* @param strategy The address of the strategy contract.
* @param isDeposit True if this is an allocation (deposit) operation, false if it's a deallocation (withdrawal).
* @param amount The amount of funds allocated or deallocated.
* @param extraData Arbitrary calldata passed to the strategy's allocateFunds or deallocateFunds function.
*/
event AllocatedFunds(address indexed strategy, bool indexed isDeposit, uint256 amount, bytes extraData);
/**
* @dev Structure containing parameters for a single allocation or deallocation operation.
*
* @param isDeposit True if this is an allocation (deposit) operation, false if it's a deallocation (withdrawal).
* @param strategy The address of the strategy contract to interact with.
* @param extraData Arbitrary calldata to pass to the strategy's allocateFunds or deallocateFunds function.
* This allows for strategy-specific parameters like slippage tolerance, routing info, etc.
*/
struct AllocateParams {
bool isDeposit;
address strategy;
bytes extraData;
}
/**
* @dev Executes multiple allocation and deallocation operations across different strategies in a single transaction.
* @dev This function processes an array of allocation parameters, calling the appropriate strategy functions
* and updating the vault's internal accounting for each strategy.
*
* @param data ABI-encoded array of AllocateParams structures containing the operations to execute.
* Each AllocateParams specifies whether to allocate or deallocate funds, which strategy to use,
* and any additional data required by the strategy.
*
* @notice The function iterates through all provided parameters and:
* - For deposits (isDeposit = true): Calls strategy.allocateFunds() and increases allocated amount
* - For withdrawals (isDeposit = false): Calls strategy.deallocateFunds() and decreases allocated amount
*
* @notice All operations are executed atomically - if any single operation fails, the entire transaction reverts.
*
* @notice The function updates the vault's internal strategy accounting to track the total amount
* allocated to each strategy, which is used for yield calculation and strategy limits.
*/
function allocateFunds(bytes calldata data) external;
}
"
},
"src/interface/IStrategyTemplate.sol": {
"content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/**
* @title IStrategyTemplate
* @dev Interface that all strategy implementations must follow to be compatible with the vault system.
* @dev Each strategy is bound to a single vault and manages that vault's funds in different protocols or investment opportunities.
* @dev The Vault uses this interface to deploy, withdraw, and rebalance funds across multiple strategies.
*
* @notice This interface defines the core functionality required for strategy contracts:
* - Asset management (allocation and deallocation of funds)
* - Withdrawal capabilities for user redemptions
* - Limit reporting for rebalancing operations
* - Compatibility with the vault's underlying asset token
*
* @notice All strategies must implement proper access controls and ensure only authorized callers
* (typically the vault) can execute fund management operations.
*
* @notice For strategies that accrue rewards from underlying protocols:
* The vault has an arbitrary call execution function that can call any target with arbitrary data.
* This is primarily used to claim rewards from external reward systems. Strategies that earn rewards
* should provide dedicated functions that can be called by the vault through this mechanism to claim
* rewards and forward them to the rewards distributor system.
*/
/**
* @dev Enum representing different types of strategies
*/
enum StrategyType {
ATOMIC, // 0: Strategy that executes operations atomically, provides on-chain accurate accounting of yield
ASYNC, // 1: Strategy that requires asynchronous operations (multiple transactions), can provide stale (within defined latency) accounting of yield
CROSSCHAIN // 2: Strategy that operates across different blockchain networks, can provide stale (within defined latency) accounting of yield
}
interface IStrategyTemplate {
/**
* @dev Allocates funds from the vault to the underlying protocol.
* @dev This function will be called when the vault wants to deploy assets into the yield-generating protocol.
*
* @param data Arbitrary calldata that can be used to pass strategy-specific parameters for the allocation.
* This allows for flexible configuration of the allocation process (e.g., slippage tolerance,
* specific protocol parameters, routing information, etc.).
*
* - MUST emit the AllocateFunds event.
* - MUST revert if all of assets cannot be deposited (due to allocation limit being reached, slippage, the protocol
* not being able to accept more funds, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.
*/
function allocateFunds(bytes calldata data) external returns (uint256);
/**
* @dev Deallocates funds from the underlying protocol back to the vault.
* @dev This function will be called when the vault wants to withdraw assets from the yield-generating protocol.
*
* @param data Arbitrary calldata that can be used to pass strategy-specific parameters for the deallocation.
* This allows for flexible configuration of the withdrawal process (e.g., slippage tolerance,
* specific protocol parameters, withdrawal routing, etc.).
*
* - MUST emit the DeallocateFunds event.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the protocol
* not having enough liquidity, etc).
*/
function deallocateFunds(bytes calldata data) external returns (uint256);
/**
* @dev Sends assets of underlying tokens to sender.
* @dev This function will be called when the vault unwinds its position while depositor withdraws.
*
* - MUST emit the Withdraw event.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough assets, etc).
*/
function onWithdraw(uint256 assets) external returns (uint256);
/**
* @dev Rescue function to withdraw tokens that may have been accidentally sent to the strategy.
* @dev This function allows authorized users to rescue tokens that are not part of the strategy's normal operations.
*
* @param token The address of the token to rescue.
* @param amount The amount of tokens to rescue. Use 0 to rescue all available tokens.
*
* - MUST only allow rescue of tokens that are not the strategy's primary asset (asset()).
* - MUST emit appropriate events for the rescue operation.
* - MUST revert if the caller is not authorized to perform token rescue.
* - MUST revert if attempting to rescue the strategy's primary asset token.
*/
function rescueToken(address token, uint256 amount) external;
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address);
/**
* @dev Returns the address of the vault that this strategy is bound to.
*
* - MUST return the vault address that was set during strategy initialization.
* - MUST NOT revert.
*/
function getVault() external view returns (address);
/**
* @dev Returns the type of strategy implementation.
* @dev This function indicates the operational characteristics of the strategy.
*
* @return The strategy type as defined in the StrategyType enum.
*
* - MUST return one of the defined StrategyType values.
* - MUST NOT revert.
* - ATOMIC: Strategy executes operations atomically in the same transaction, yield MUST be always atomicly updated in strategy allocated amount.
* - ASYNC: Strategy requires asynchronous operations across multiple transactions, yield Can be updated asynchronously within documented latency.
* - CROSSCHAIN: Strategy operates across different blockchain networks, yield Can be updated asynchronously within documented latency.
*/
function strategyType() external view returns (StrategyType);
/**
* @dev Returns the total value of assets that the bound vault has allocated in the strategy.
* @dev This function is mainly used during yield accrual operations to account for strategy yield or losses.
*
* @return The total value of allocated assets denominated in the asset() token.
*
* - MUST return the total value of assets that the bound vault has allocated to this strategy.
* - MUST account for any losses or depreciation in the underlying protocol.
* - MUST NOT revert.
* - MUST return 0 if the vault has no funds allocated to this strategy.
*/
function totalAllocatedValue() external view returns (uint256);
/**
* @dev Returns the maximum amount of assets that can be allocated to the underlying protocol.
* @dev This function is primarily used by the Allocator to determine allocation limits when rebalancing funds.
*
* - MUST return the maximum amount of underlying assets that can be allocated in a single call to allocateFunds.
* - MUST NOT revert.
* - MAY return 0 if the protocol cannot accept any more funds.
* - MAY return type(uint256).max if there is no practical limit.
*/
function maxAllocation() external view returns (uint256);
/**
* @dev Returns the maximum amount of assets that can be withdrawn from the strategy by the vault.
* @dev This function is primarily used by the vault to determine withdrawal limits when covering user redemptions.
*
* - MUST return the maximum amount of underlying assets that can be withdrawn in a single call to onWithdraw.
* - MUST NOT revert.
* - MAY return 0 if no funds are available for withdrawal.
* - SHOULD reflect current liquidity constraints and strategy-specific withdrawal limits.
*/
function maxWithdraw() external view returns (uint256);
}
"
},
"src/interface/IConcreteStandardVaultImpl.sol": {
"content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
import {IUpgradeableVault} from "./IUpgradeableVault.sol";
import {Hooks} from "./IHook.sol";
import {IERC4626} from "@openzeppelin-contracts/interfaces/IERC4626.sol";
import {IAccessControlEnumerable} from "@openzeppelin-contracts/access/extensions/IAccessControlEnumerable.sol";
/**
* @title IConcreteStandardVaultImpl
* @dev Interface for the standard vault implementation that manages multiple investment strategies.
* @dev This interface extends the base tokenized vault functionality with strategy management capabilities.
* @dev Strategies are external contracts that implement the IStrategyTemplate interface and handle
* fund allocation to different yield-generating protocols or investment opportunities.
*/
interface IConcreteStandardVaultImpl is IUpgradeableVault, IERC4626, IAccessControlEnumerable {
/**
* @dev Thrown when attempting to withdraw to the zero address.
*/
error InvalidReceiver();
/**
* @dev Thrown when attempting to add a strategy that uses a different asset than the vault.
*/
error InvalidStrategyAsset();
/**
* @dev Thrown when attempting to add a strategy that has already been added to the vault.
*/
error StrategyAlreadyAdded();
/**
* @dev Thrown when attempting to operate on a strategy that doesn't exist in the vault.
*/
error StrategyDoesNotExist();
/**
* @dev Thrown when attempting to interact with a strategy that is halted.
*/
error StrategyIsHalted();
/**
* @dev Thrown when attempting to halt a strategy that is already halted.
*/
error StrategyAlreadyHalted();
/**
* @dev Thrown when attempting to toggle the status of an inactive strategy.
*/
error CannotToggleInactiveStrategy();
/**
* @dev Thrown when attempting to set a management fee without setting a recipient first.
*/
error FeeRecipientNotSet();
/**
* @dev Thrown when attempting to set a management fee that exceeds the maximum allowed.
*/
error ManagementFeeExceedsMaximum();
/**
* @dev Thrown when attempting to set a performance fee that exceeds the maximum allowed.
*/
error PerformanceFeeExceedsMaximum();
/**
* @dev Thrown when attempting to set an invalid fee recipient address (address(0)).
*/
error InvalidFeeRecipient();
/**
* @dev Thrown when the allocate module is invalid.
*/
error InvalidAllocateModule();
/**
* @dev Thrown when the asset is invalid.
*/
error InvalidAsset();
/**
* @dev Thrown when the initial vault manager is invalid.
*/
error InvalidInitialVaultManager();
/**
* @dev Thrown when the name is invalid.
*/
error InvalidName();
/**
* @dev Thrown when the symbol is invalid.
*/
error InvalidSymbol();
/**
* @dev Thrown when the deposit limits are invalid.
*/
error InvalidDepositLimits();
/**
* @dev Thrown when the withdraw limits are invalid.
*/
error InvalidWithdrawLimits();
/**
* @dev Thrown when the asset amount is out of bounds.
*/
error AssetAmountOutOfBounds(address sender, uint256 assets, uint256 minDepositAmount, uint256 maxDepositAmount);
/**
* @dev Thrown when attempting to remove a strategy that has allocation or is in the deallocation order.
*/
error StrategyHasAllocation();
/**
* @dev Thrown when the vault has insufficient balance to process the epoch.
*/
error InsufficientBalance();
/**
* @dev Thrown when calculated shares are zero.
*/
error InsufficientShares();
/**
* @dev Thrown when calculated assets are zero.
*/
error InsufficientAssets();
/**
* @dev Emitted when a new strategy is successfully added to the vault.
* @param strategy The address of the strategy contract that was added.
*/
event StrategyAdded(address strategy);
/**
* @dev Emitted when a strategy is successfully removed from the vault.
* @param strategy The address of the strategy contract that was removed.
*/
event StrategyRemoved(address strategy);
/**
* @dev Emitted when a strategy is set to Halted status.
* @param strategy The address of the strategy contract that was halted.
*/
event StrategyHalted(address strategy);
/**
* @dev Emitted when a strategy's status is toggled between Active and Halted.
* @param strategy The address of the strategy contract whose status was toggled.
*/
event StrategyStatusToggled(address indexed strategy);
/**
* @dev Emitted when the yield accrual operation is completed across all strategies.
*
* @param totalPositiveYield The total amount of positive yield generated across all strategies.
* @param totalNegativeYield The total amount of losses incurred across all strategies.
*/
event YieldAccrued(uint256 totalPositiveYield, uint256 totalNegativeYield);
/**
* @dev Emitted when management fee is accrued.
* @param recipient The address that received the management fee shares.
* @param shares The number of shares minted as management fee.
* @param feeAmount The asset value of the management fee.
*/
event ManagementFeeAccrued(address indexed recipient, uint256 shares, uint256 feeAmount);
/**
* @dev Emitted when performance fee is accrued.
* @param recipient The address that received the performance fee shares.
* @param shares The number of shares minted as performance fee.
* @param feeAmount The asset value of the performance fee.
*/
event PerformanceFeeAccrued(address indexed recipient, uint256 shares, uint256 feeAmount);
/**
* @dev Emitted when management fee is updated.
* @param managementFee The new management fee rate in basis points.
*/
event ManagementFeeUpdated(uint16 managementFee);
/**
* @dev Emitted when management fee recipient is updated.
* @param managementFeeRecipient The new management fee recipient address.
*/
event ManagementFeeRecipientUpdated(address managementFeeRecipient);
/**
* @dev Emitted when performance fee is updated.
* @param performanceFee The new performance fee rate in basis points.
*/
event PerformanceFeeUpdated(uint16 performanceFee);
/**
* @dev Emitted when performance fee recipient is updated.
* @param performanceFeeRecipient The new performance fee recipient address.
*/
event PerformanceFeeRecipientUpdated(address performanceFeeRecipient);
/**
* @dev Emitted when deposit limits are updated.
* @param maxDepositAmount The new maximum deposit amount.
* @param minDepositAmount The new minimum deposit amount.
*/
event DepositLimitsUpdated(uint256 maxDepositAmount, uint256 minDepositAmount);
/**
* @dev Emitted when withdraw limits are updated.
* @param maxWithdrawAmount The new maximum withdraw amount.
* @param minWithdrawAmount The new minimum withdraw amount.
*/
event WithdrawLimitsUpdated(uint256 maxWithdrawAmount, uint256 minWithdrawAmount);
/**
* @dev Emitted when the deallocation order is updated.
*/
event DeallocationOrderUpdated();
/**
* @dev Emitted when an individual strategy's yield is accrued.
*
* @param strategy The address of the strategy contract whose yield was accrued.
* @param currentTotalAllocatedValue The current total allocated value reported by the strategy.
* @param yield The amount of positive yield generated by this strategy since last accrual.
* @param loss The amount of loss incurred by this strategy since last accrual.
*/
event StrategyYieldAccrued(
address indexed strategy, uint256 currentTotalAllocatedValue, uint256 yield, uint256 loss
);
/**
* @dev Enumeration of possible strategy statuses within the vault.
* @dev Inactive: Strategy is inactive and cannot receive new allocations.
* @dev Active: Strategy is active and can receive allocations and process withdrawals normally.
* @dev Halted: Strategy is halted, typically due to detected issues or failures.
* In this state, the strategy can be removed even if it has allocated funds
*/
enum StrategyStatus {
Inactive,
Active,
Halted
}
/**
* @dev Structure containing metadata and state information for each strategy.
* @dev status: Current operational status of the strategy.
* @dev allocated: Total amount of vault assets currently allocated to this strategy, denominated in the vault's underlying asset token.
*/
struct StrategyData {
StrategyStatus status;
uint120 allocated;
}
/**
* @dev Adds a new strategy to the vault.
* @dev The strategy must implement the IStrategyTemplate interface and use the same underlying asset as the vault.
* @dev Only callable by accounts with the STRATEGY_MANAGER role.
*
* @param strategy The address of the strategy contract to add.
*
* Requirements:
* - The strategy's asset() must match the vault's asset()
* - The strategy must not already be added to the vault
* - Caller must have STRATEGY_MANAGER role
*
* Emits:
* - StrategyAdded event
*
* Reverts:
* - InvalidStrategyAsset if strategy uses different asset
* - StrategyAlreadyAdded if strategy is already in the vault
*/
function addStrategy(address strategy) external;
/**
* @dev Removes a strategy from the vault.
* @dev The strategy can only be removed if it has no allocated funds, unless it's in Halted status.
* @dev Only callable by accounts with the STRATEGY_MANAGER role.
*
* @param strategy The address of the strategy contract to remove.
*
* Requirements:
* - Strategy must exist in the vault
* - Strategy must have zero allocated funds OR be in Halted status
* - Caller must have STRATEGY_MANAGER role
*
* Emits:
* - StrategyRemoved event
*
* Reverts:
* - StrategyDoesNotExist if strategy is not in the vault
* - Custom revert if strategy has allocated funds and is not in Halted status
*/
function removeStrategy(address strategy) external;
/**
* @dev Toggles a strategy's status between Active and Halted.
* @dev This is a safety mechanism to isolate problematic strategies or reactivate previously halted ones.
* @dev Active strategies can receive allocations and participate in yield accrual and withdrawal operations.
* @dev Halted strategies are skipped during yield accrual and withdrawal operations.
* @dev Only callable by accounts with the STRATEGY_MANAGER role.
*
* @param strategy The address of the strategy contract to toggle.
*
* Requirements:
* - Strategy must exist in the vault
* - Strategy must be either Active or Halted (cannot toggle Inactive strategies)
* - Caller must have STRATEGY_MANAGER role
*
* Emits:
* - StrategyStatusToggled event
*
* Reverts:
* - StrategyDoesNotExist if strategy is not in the vault
*/
function toggleStrategyStatus(address strategy) external;
/**
* @notice Executes fund allocation and deallocation operations across multiple strategies.
* @dev This function performs a yield accrual operation first to update vault accounting,
* then executes the allocation operations specified in the data parameter.
* @dev All operations are performed via delegatecall to the respective modules to maintain
* proper storage context and access control.
* @param data ABI-encoded array of AllocateParams structures containing the allocation
* operations to execute. Each param specifies whether to allocate or deallocate
* funds, which strategy to use, and any additional data required by the strategy.
* @dev Only callable by accounts with the ALLOCATOR role.
* @dev The function automatically triggers yield accrual before allocation to ensure
* accurate vault accounting prior to fund movements.
*/
function allocate(bytes calldata data) external;
/**
* @notice Accrues yield and accounts for losses across all active strategies in the vault.
* @dev This function updates the vault's internal accounting by querying the current
* value of all strategy allocations and calculating net yield or losses.
* @dev This function can be called by anyone to update the vault's accounting.
* @dev The yield accrual operation does not trigger actual fund movements, it only
* updates the vault's internal state to reflect current strategy values.
*/
function accrueYield() external;
/**
* @notice Updates the management fee for the vault.
* @param managementFee The new management fee in basis points.
* @dev Only callable by accounts with VAULT_MANAGER role.
* @dev Fee must be <= MAX_MANAGEMENT_FEE.
* @dev If fee > 0, recipient must be set.
*/
function updateManagementFee(uint16 managementFee) external;
/**
* @notice Updates the management fee recipient for the vault.
* @param recipient The new management fee recipient address.
* @dev Only callable by accounts with VAULT_MANAGER role.
* @dev Recipient cannot be address(0).
*/
function updateManagementFeeRecipient(address recipient) external;
/**
* @notice Updates the performance fee for the vault.
* @param performanceFee The new performance fee in basis points.
* @dev Only callable by accounts with VAULT_MANAGER role.
* @dev Fee must be <= MAX_PERFORMANCE_FEE.
* @dev If fee > 0, recipient must be set.
*/
function updatePerformanceFee(uint16 performanceFee) external;
/**
* @notice Updates the performance fee recipient for the vault.
* @param recipient The new performance fee recipient address.
* @dev Only callable by accounts with VAULT_MANAGER.
* @dev Recipient cannot be address(0).
*/
function updatePerformanceFeeRecipient(address recipient) external;
/**
* @notice Returns the current fee configuration for the vault.
* @return currentManagementFee The current management fee in basis points.
* @return currentManagementFeeRecipient The current management fee recipient address.
* @return currentLastManagementFeeAccrual The timestamp of the last management fee accrual.
* @return currentPerformanceFee The current performance fee in basis points.
* @return currentPerformanceFeeRecipient The current performance fee recipient address.
*/
function getFeeConfig()
external
view
returns (
uint16 currentManagementFee,
address currentManagementFeeRecipient,
uint32 currentLastManagementFeeAccrual,
uint16 currentPerformanceFee,
address currentPerformanceFeeRecipient
);
/**
* @notice Sets the hooks for the vault.
* @dev This function sets the hooks for the vault.
* @dev Only callable by accounts with the HOOK_MANAGER role.
* @param hooks The hooks to set.
*/
function setHooks(Hooks memory hooks) external;
/**
* @notice Previews the total assets that would be available after accruing yield from all strategies.
* @dev This function simulates the yield accrual operation without actually executing it,
* providing a view of what the vault's total assets would be after accounting
* for yield and losses across all active strategies.
* @dev The calculation includes the current lastTotalAssets plus any positive
* yield minus any losses that would be realized during yield accrual.
* @dev This is a view function that does not modify state or trigger any actual
* fund movements or strategy interactions.
*
* @return The total amount of assets that would be available in the vault after yield accrual,
* denominated in the vault's underlying asset token.
* @return The total amount of shares that would be available in the vault after yield accrual,
* calculated as current totalSupply + management fee shares.
*/
function previewAccrueYield() external view returns (uint256, uint256);
/**
* @dev Retrieves the current data and status information for a specific strategy.
* @dev This function provides read-only access to strategy metadata including allocation amounts and status.
*
* @param strategy The address of the strategy contract to query.
* @return The StrategyData struct containing the strategy's current status and allocated amount.
*
* Note:
* - Returns default values (Inactive status, 0 allocated) for non-existent strategies
* - Does not revert for invalid strategy addresses
*/
function getStrategyData(address strategy) external view returns (StrategyData memory);
/**
* @dev Returns an array of all strategy addresses currently managed by the vault.
* @dev This function provides a way to enumerate all active strategies for external integrations and monitoring.
*
* @return An array containing the addresses of all strategies added to the vault.
*
* Note:
* - The returned array includes strategies in all statuses (Active, Inactive, Emergency)
* - The order of strategies in the array is not guaranteed
* - Returns an empty array if no strategies have been added
*/
function getStrategies() external view returns (address[] memory);
/**
* @dev Returns the address of the allocate module.
*
* @return The address of the allocate module.
*/
function allocateModule() external view returns (address);
/**
* @dev Returns the management fee configuration.
* @return managementFeeRecipient The address that receives management fees.
* @return managementFeeRate The management fee rate in basis points (where 10,000 = 100%).
* @return lastAccrualTime The timestamp of the last management fee accrual.
*/
function managementFee()
external
view
returns (address managementFeeRecipient, uint16 managementFeeRate, uint32 lastAccrualTime);
/**
* @dev Sets the deposit limits.
* @param maxDepositAmount The maximum deposit amount.
* @param minDepositAmount The minimum deposit amount.
* @dev Only callable by accounts with VAULT_MANAGER role.
*/
function setDepositLimits(uint256 maxDepositAmount, uint256 minDepositAmount) external;
/**
* @dev Sets the withdraw limits.
* @param maxWithdrawAmount The maximum withdraw amount.
* @param minWithdrawAmount The minimum withdraw amount.
* @dev Only callable by accounts with VAULT_MANAGER role.
*/
function setWithdrawLimits(uint256 maxWithdrawAmount, uint256 minWithdrawAmount) external;
/**
* @dev Returns the deposit limits.
* @return maxDepositAmount The maximum deposit amount.
* @return minDepositAmount The minimum deposit amount.
*/
function getDepositLimits() external view returns (uint256 maxDepositAmount, uint256 minDepositAmount);
/**
* @dev Returns the withdraw limits.
* @return maxWithdrawAmount The maximum withdraw amount.
* @return minWithdrawAmount The minimum withdraw amount.
*/
function getWithdrawLimits() external view returns (uint256 maxWithdrawAmount, uint256 minWithdrawAmount);
/**
* @dev Returns the performance fee configuration.
* @return performanceFeeRecipient The address that receives performance fees.
* @return performanceFeeRate The performance fee rate in basis points (where 10,000 = 100%).
*/
function performanceFee() external view returns (address performanceFeeRecipient, uint16 performanceFeeRate);
/**
* @dev Returns the total amount of assets allocated to all strategies.
*
* @return The total amount of assets allocated to all strategies.
*/
function getTotalAllocated() external view returns (uint256);
/**
* @dev Returns the cached value of total assets after the last call.
*
* @return The cached value of total assets after the last call.
*/
function cachedTotalAssets() external view returns (uint256);
/**
* @dev Returns the deallocation order from strategies.
*
* @return order An array of strategy addresses in the order they should be deallocated.
*/
function getDeallocationOrder() external view returns (address[] memory order);
/**
* @dev Sets the deallocation order for strategies.
* @dev Only callable by accounts with the ALLOCATOR role.
* @param order An array of strategy addresses in the order they should be deallocated.
*/
function setDeallocationOrder(address[] calldata order) external;
}
"
},
"src/lib/storage/ConcreteStandardVaultImplStorageLib.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/types/Time.sol)
pragma solidity ^0.8.24;
import {IConcreteStandardVaultImpl} from "../../interface/IConcreteStandardVaultImpl.sol";
import {EnumerableSet} from "@openzeppelin-contracts/utils/structs/EnumerableSet.sol";
import {Hooks} from "../Hooks.sol";
library ConcreteStandardVaultImplStorageLib {
/// @dev keccak256(abi.encode(uint256(keccak256("concrete.storage.ConcreteStandardVaultImplStorage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ConcreteStandardVaultImplStorageLocation =
0xe74d828616eceb28be4a8cf3f9eeee868e1f44ce928ee17a9d7ad296fa52be00;
/// @custom:storage-location erc7201:concrete.storage.ConcreteStandardVaultImplStorage
struct ConcreteStandardVaultImplStorage {
/// @dev max deposit amount
uint256 maxDepositAmount;
/// @dev max withdraw amount
uint256 maxWithdrawAmount;
/// @dev min deposit amount
uint256 minDepositAmount;
/// @dev min withdraw amount
uint256 minWithdrawAmount;
/// @dev allocate module's address
address allocateModule;
/// 1 slot: 160 + 16 + 32
/// @dev management fee recipient
address managementFeeRecipient;
/// @dev annual management fee rate in basis points
uint16 managementFee;
/// @dev timestamp of last management fee accrual
uint32 lastManagementFeeAccrual;
/// 1 slot: 160 + 16
/// @dev performance fee recipient
address performanceFeeRecipient;
/// @dev annual performance fee rate in basis points
uint16 performanceFee;
/// @dev high water mark
uint128 performanceFeeHighWaterMark;
/// Mapping between a strategy address and it's data
mapping(address => IConcreteStandardVaultImpl.StrategyData) strategyData;
/// An set of strategy addresses that ConcreteVault allocates to
EnumerableSet.AddressSet strategies;
/// Defines the order in which funds are retrieved from strategies to fulfill withdrawals
address[] deallocationOrder;
/// @dev hooks
Hooks hooks;
}
/**
*
*/
function fetch() internal pure returns (ConcreteStandardVaultImplStorage storage $) {
assembly {
$.slot := ConcreteStandardVaultImplStorageLocation
}
}
}
"
},
"node_modules/@openzeppelin/contracts/utils/math/SafeCast.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input m
Submitted on: 2025-10-17 20:49:10
Comments
Log in to comment.
No comments yet.