Tokens
| This document is better viewed at https://docs.openzeppelin.com/community-contracts/token |
Set of extensions and utilities for tokens (e.g ERC-20, ERC-721, ERC-1155) and derivated ERCs (e.g. ERC-4626, ERC-1363).
-
OnTokenTransferAdapter: Adapter of the ERC-1363 receiver interface to comply with Chainlink’s 667 interface. -
ERC20Allowlist: Extension of ERC20 with transfers and approvals that require users to be registered into an allowlist. -
ERC20Blocklist: Extension of ERC20 with transfers and approvals that can be disabled by adding users into a blocklist. -
ERC20Collateral: Oracle-agnostic extension of ERC20 that limits the total supply based on a collateral amount. -
ERC20Custodian: Extension of ERC20 that implements an access-control agnostic approach to define a custodian that can freeze user’s transfers and approvals. -
ERC20Freezable: Extension of ERC20 that allows an authorized account to freeze a portion of an account’s balance, preventing it from being transferred until unfrozen. -
ERC20Restricted: Extension of ERC20 that allows implementing user account transfer restrictions (blocklist or allowlist) inspired by EIP-7943. -
ERC20uRWA: Extension of ERC20 according to EIP-7943, combining standard ERC-20 with RWA-specific features like account restrictions, asset freezing, and forced transfers. -
ERC4626Fees: ERC4626 vault with fees on entry (deposit/mint) or exit (withdraw/redeem). -
ERC7540: Implementation of ERC-7540 "Asynchronous ERC-4626 Tokenized Vaults", providing a base for vaults with asynchronous deposit and/or redemption flows. -
ERC7540AdminDeposit: Admin-controlled (operator-triggered) fulfillment strategy for asynchronous deposits in ERC-7540 vaults. -
ERC7540AdminRedeem: Admin-controlled (operator-triggered) fulfillment strategy for asynchronous redemptions in ERC-7540 vaults. -
ERC7540DelayDeposit: Time-delay fulfillment strategy for asynchronous deposits, becoming permissionlessly claimable after a configurable waiting period. -
ERC7540DelayRedeem: Time-delay fulfillment strategy for asynchronous redemptions, becoming permissionlessly claimable after a configurable waiting period. -
ERC7540SyncDeposit: Module for enabling synchronous (ERC-4626) deposit flow in an ERC-7540 vault. -
ERC7540SyncRedeem: Module for enabling synchronous (ERC-4626) redeem flow in an ERC-7540 vault.
General
OnTokenTransferAdapter
import "@openzeppelin/community-contracts/token/OnTokenTransferAdapter.sol";
This contract exposes the 667 onTokenTransfer hook on top of {IERC1363Receiver-onTransferReceived}.
Inheriting from this adapter makes your ERC1363Receiver contract automatically compatible with tokens, such as
Chainlink’s Link, that implement the 667 interface for transferAndCall.
-
onTokenTransfer(from, amount, data)
-
onTransferReceived(operator, from, value, data)
ERC20
ERC20Allowlist
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Allowlist.sol";
Extension of {ERC20} that allows to implement an allowlist
mechanism that can be managed by an authorized account with the
_disallowUser and _allowUser functions.
The allowlist provides the guarantee to the contract owner
(e.g. a DAO or a well-configured multisig) that any account won’t be
able to execute transfers or approvals to other entities to operate
on its behalf if _allowUser was not called with such account as an
argument. Similarly, the account will be disallowed again if
_disallowUser is called.
Deprecated. Use ERC20Restricted instead.
|
-
allowed(account) -
_allowUser(user) -
_disallowUser(user) -
_update(from, to, value) -
_approve(owner, spender, value, emitEvent)
-
name() -
symbol() -
decimals() -
totalSupply() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_spendAllowance(owner, spender, value)
-
UserAllowed(user) -
UserDisallowed(user)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
ERC20Disallowed(user)
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
_allowUser(address user) → bool internal
Allows a user to receive and transfer tokens, including minting and burning.
_disallowUser(address user) → bool internal
Disallows a user from receiving and transferring tokens, including minting and burning.
ERC20Blocklist
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Blocklist.sol";
Extension of {ERC20} that allows to implement a blocklist
mechanism that can be managed by an authorized account with the
_blockUser and _unblockUser functions.
The blocklist provides the guarantee to the contract owner
(e.g. a DAO or a well-configured multisig) that any account won’t be
able to execute transfers or approvals to other entities to operate
on its behalf if _blockUser was not called with such account as an
argument. Similarly, the account will be unblocked again if
_unblockUser is called.
Deprecated. Use ERC20Restricted instead.
|
-
blocked(account) -
_blockUser(user) -
_unblockUser(user) -
_update(from, to, value) -
_approve(owner, spender, value, emitEvent)
-
name() -
symbol() -
decimals() -
totalSupply() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_spendAllowance(owner, spender, value)
-
UserBlocked(user) -
UserUnblocked(user)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
ERC20Blocked(user)
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
_blockUser(address user) → bool internal
Blocks a user from receiving and transferring tokens, including minting and burning.
_unblockUser(address user) → bool internal
Unblocks a user from receiving and transferring tokens, including minting and burning.
ERC20Collateral
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Collateral.sol";
Extension of {ERC20} that limits the supply of tokens based on a collateral amount and time-based expiration.
The collateral function must be implemented to return the collateral
data. This function can call external oracles or use any local storage.
-
constructor(liveness_) -
liveness() -
clock() -
CLOCK_MODE() -
collateral() -
_update(from, to, value)
-
name() -
symbol() -
decimals() -
totalSupply() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
ERC20ExceededSupply(increasedSupply, cap) -
ERC20ExpiredCollateral(timestamp, expiration)
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
constructor(uint48 liveness_) internal
Sets the value of the _liveness. This value is immutable, it can only be
set once during construction.
ERC20Custodian
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Custodian.sol";
Extension of {ERC20} that allows to implement a custodian
mechanism that can be managed by an authorized account with the
freeze function.
This mechanism allows a custodian (e.g. a DAO or a well-configured multisig) to freeze and unfreeze the balance of a user.
The frozen balance is not available for transfers or approvals
to other entities to operate on its behalf if. The frozen balance
can be reduced by calling freeze again with a lower amount.
Deprecated. Use ERC20Freezable instead.
|
-
onlyCustodian()
-
frozen(user) -
freeze(user, amount) -
availableBalance(account) -
_isCustodian(user) -
_update(from, to, value)
-
name() -
symbol() -
decimals() -
totalSupply() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
TokensFrozen(user, amount) -
TokensUnfrozen(user, amount)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
ERC20InsufficientUnfrozenBalance(user) -
ERC20InsufficientFrozenBalance(user) -
ERC20NotCustodian()
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
availableBalance(address account) → uint256 available public
Returns the available (unfrozen) balance of an account.
_update(address from, address to, uint256 value) internal
Transfers a value amount of tokens from from to to, or alternatively mints (or burns) if from
(or to) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
this function.
Emits a {Transfer} event.
TokensUnfrozen(address indexed user, uint256 amount) event
Emitted when tokens are unfrozen for a user.
ERC20InsufficientUnfrozenBalance(address user) error
The operation failed because the user has insufficient unfrozen balance.
ERC20Freezable
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Freezable.sol";
Extension of {ERC20} that allows to implement a freezing
mechanism that can be managed by an authorized account with the
_setFrozen function.
The freezing mechanism provides the guarantee to the contract owner
(e.g. a DAO or a well-configured multisig) that a specific amount
of tokens held by an account won’t be transferable until the frozen amount
is reduced using _setFrozen.
-
frozen(account) -
available(account) -
_setFrozen(account, amount) -
_update(from, to, value)
-
name() -
symbol() -
decimals() -
totalSupply() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
ERC20InsufficientUnfrozenBalance(account, needed, available)
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
available(address account) → uint256 public
Returns the available (unfrozen) balance of an account. Up to {balanceOf}.
_setFrozen(address account, uint256 amount) internal
Internal function to set the frozen token amount for a account.
ERC20Restricted
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Restricted.sol";
Extension of {ERC20} that allows to implement user account transfer restrictions
through the canTransact function. Inspired by EIP-7943.
By default, each account has no explicit restriction. The canTransact function acts as
a blocklist. Developers can override canTransact to check that restriction == ALLOWED
to implement an allowlist.
-
getRestriction(account) -
canTransact(account) -
_update(from, to, value) -
_setRestriction(account, restriction) -
_blockUser(account) -
_allowUser(account) -
_resetUser(account) -
_checkRestriction(account)
-
name() -
symbol() -
decimals() -
totalSupply() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
UserRestrictionsUpdated(account, restriction)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
ERC20UserRestricted(account)
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
getRestriction(address account) → enum ERC20Restricted.Restriction public
Returns the restriction of a user account.
canTransact(address account) → bool public
Returns whether a user account is allowed to interact with the token.
Default implementation only disallows explicitly BLOCKED accounts (i.e. a blocklist).
To convert into an allowlist, override as:
function canTransact(address account) public view virtual override returns (bool) {
return getRestriction(account) == Restriction.ALLOWED;
}
_update(address from, address to, uint256 value) internal
See {ERC20-_update}. Enforces restriction transfers (excluding minting and burning).
Requirements:
-
frommust be allowed to transfer tokens (seecanTransact). -
tomust be allowed to receive tokens (seecanTransact).
_setRestriction(address account, enum ERC20Restricted.Restriction restriction) internal
Updates the restriction of a user account.
_resetUser(address account) internal
Convenience function to reset a user account to default restriction.
_checkRestriction(address account) internal
Checks if a user account is restricted. Reverts with ERC20Restricted if so.
ERC20uRWA
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20uRWA.sol";
Extension of {ERC20} according to EIP-7943.
Combines standard ERC-20 functionality with RWA-specific features like account restrictions, asset freezing, and forced asset transfers. This contract doesn’t expose minting or burning capabilities; if implemented in derived contracts as needed, they must include 7943-specific logic.
-
canTransact(account) -
supportsInterface(interfaceId) -
canTransfer(from, to, amount) -
getFrozenTokens(account) -
setFrozenTokens(account, amount) -
forcedTransfer(from, to, amount) -
_update(from, to, amount) -
_checkEnforcer(from, to, amount) -
_checkFreezer(account, amount)
-
getRestriction(account) -
_setRestriction(account, restriction) -
_blockUser(account) -
_allowUser(account) -
_resetUser(account) -
_checkRestriction(account)
-
frozen(account) -
available(account) -
_setFrozen(account, amount)
-
name() -
symbol() -
decimals() -
totalSupply() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
ForcedTransfer(from, to, amount) -
Frozen(account, amount)
-
UserRestrictionsUpdated(account, restriction)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
ERC7943CannotTransact(account) -
ERC7943CannotTransfer(from, to, amount) -
ERC7943InsufficientUnfrozenBalance(account, amount, unfrozen)
-
ERC20UserRestricted(account)
-
ERC20InsufficientUnfrozenBalance(account, needed, available)
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
canTransact(address account) → bool public
Returns whether a user account is allowed to interact with the token.
Default implementation only disallows explicitly BLOCKED accounts (i.e. a blocklist).
To convert into an allowlist, override as:
function canTransact(address account) public view virtual override returns (bool) {
return getRestriction(account) == Restriction.ALLOWED;
}
supportsInterface(bytes4 interfaceId) → bool public
Returns true if this contract implements the interface defined by
interfaceId. See the corresponding
ERC section
to learn more about how these ids are created.
This function call must use less than 30 000 gas.
getFrozenTokens(address account) → uint256 amount public
It could return an amount higher than the account’s balance.
setFrozenTokens(address account, uint256 amount) → bool result public
See IERC7943Fungible.setFrozenTokens. Always returns true if successful. Reverts otherwise.
The amount is capped to the balance of the account to ensure the IERC7943Fungible.Frozen event
emits values that consistently reflect the actual amount of tokens that are frozen.
|
forcedTransfer(address from, address to, uint256 amount) → bool result public
See IERC7943Fungible.forcedTransfer. Always returns true if successful. Reverts otherwise.
Bypasses the ERC20Restricted restrictions for the from address and adjusts the frozen balance
to the new balance after the transfer.
This function uses _update to perform the transfer, ensuring all standard ERC20
side effects (such as balance updates and events) are preserved. If you override _update
to add additional restrictions or logic, those changes will also apply here.
Consider overriding this function to bypass newer restrictions if needed.
|
_update(address from, address to, uint256 amount) internal
Transfers a value amount of tokens from from to to, or alternatively mints (or burns) if from
(or to) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
this function.
Emits a {Transfer} event.
_checkEnforcer(address from, address to, uint256 amount) internal
Internal function to check if the enforcer is allowed to forcibly transfer the amount of tokens.
Example usage with {AccessControl-onlyRole}:
function _checkEnforcer(address from, address to, uint256 amount) internal view override onlyRole(ENFORCER_ROLE) {}
ERC4626Fees
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC4626Fees.sol";
ERC-4626 vault with entry/exit fees expressed in basis point (bp).
-
previewDeposit(assets) -
previewMint(shares) -
previewWithdraw(assets) -
previewRedeem(shares) -
_deposit(caller, receiver, assets, shares) -
_withdraw(caller, receiver, owner, assets, shares) -
_entryFeeBasisPoints() -
_exitFeeBasisPoints() -
_entryFeeRecipient() -
_exitFeeRecipient()
-
decimals() -
asset() -
totalAssets() -
convertToShares(assets) -
convertToAssets(shares) -
maxDeposit() -
maxMint() -
maxWithdraw(owner) -
maxRedeem(owner) -
deposit(assets, receiver) -
mint(shares, receiver) -
withdraw(assets, receiver, owner) -
redeem(shares, receiver, owner) -
_convertToShares(assets, rounding) -
_convertToAssets(shares, rounding) -
_transferIn(from, assets) -
_transferOut(to, assets) -
_decimalsOffset()
-
name() -
symbol() -
totalSupply() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_update(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
Deposit(sender, owner, assets, shares) -
Withdraw(sender, receiver, owner, assets, shares)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
ERC4626ExceededMaxDeposit(receiver, assets, max) -
ERC4626ExceededMaxMint(receiver, shares, max) -
ERC4626ExceededMaxWithdraw(owner, assets, max) -
ERC4626ExceededMaxRedeem(owner, shares, max)
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
previewDeposit(uint256 assets) → uint256 public
Preview taking an entry fee on deposit. See {IERC4626-previewDeposit}.
previewMint(uint256 shares) → uint256 public
Preview adding an entry fee on mint. See {IERC4626-previewMint}.
previewWithdraw(uint256 assets) → uint256 public
Preview adding an exit fee on withdraw. See {IERC4626-previewWithdraw}.
previewRedeem(uint256 shares) → uint256 public
Preview taking an exit fee on redeem. See {IERC4626-previewRedeem}.
_deposit(address caller, address receiver, uint256 assets, uint256 shares) internal
Send entry fee to _entryFeeRecipient. See {IERC4626-_deposit}.
_withdraw(address caller, address receiver, address owner, uint256 assets, uint256 shares) internal
Send exit fee to _exitFeeRecipient. See {IERC4626-_deposit}.
ERC7540
ERC7540
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC7540.sol";
Implementation of the ERC-7540 "Asynchronous ERC-4626 Tokenized Vaults" as defined in ERC-7540.
This abstract contract provides a single base for building vaults with asynchronous deposit and/or redemption
flows on top of ERC-4626. It integrates operator management (IERC7540Operator), the full ERC-4626 vault
interface, and routing logic that delegates to either synchronous (standard ERC-4626) or asynchronous paths
depending on the return value of _isDepositAsync and _isRedeemAsync.
Subcontracts choose their async behavior by overriding two internal pure boolean selectors:
-
_isDepositAsync: whentrue, the deposit side uses the Request lifecycle (Pending → Claimable → Claimed). -
_isRedeemAsync: whentrue, the redeem side uses the Request lifecycle.
Each async path requires a fulfillment strategy that implements the virtual hooks declared in this contract
(e.g. _consumeClaimableDeposit, _pendingDepositRequest, _asyncMaxDeposit, etc.).
Deposit and redeem strategies are independent: a vault can combine any deposit strategy with any redeem strategy (e.g. delay-based deposits with admin-based redeems).
Share custody during the async lifecycle is configurable via _depositShareOrigin and
_redeemShareDestination. When these return address(0) (the default), shares are minted/burned
at claim time. When they return a non-zero address, shares are pre-minted to (or transferred to)
that address at fulfillment time and then transferred to the receiver on claim.
|
When implementing a custom fulfillment strategy, the following virtual hooks MUST be overridden for each async side enabled: |
|
ERC-7540 introduces operator permissions that allow operators to manage requests on behalf of controllers. An operator approved by a controller can request deposits using the controller’s assets, request redemptions using the controller’s shares, and claim assets or shares on behalf of the controller. Users should only approve operators they fully trust with both their assets and shares. |
|
This contract assumes the underlying |
-
onlyOperatorOrController(async, controller, operator)
-
constructor(asset_) -
supportsInterface(interfaceId) -
isOperator(controller, operator) -
setOperator(operator, approved) -
_setOperator(controller, operator, approved) -
_checkOperatorOrController(async, controller, operator) -
decimals() -
asset() -
share() -
vault(asset_) -
totalAssets() -
totalSupply() -
pendingDepositRequest(requestId, controller) -
claimableDepositRequest(requestId, controller) -
pendingRedeemRequest(requestId, controller) -
claimableRedeemRequest(requestId, controller) -
totalPendingDepositAssets() -
totalPendingRedeemShares() -
convertToShares(assets) -
convertToAssets(shares) -
maxDeposit(owner) -
maxMint(owner) -
maxWithdraw(owner) -
maxRedeem(owner) -
previewDeposit(assets) -
previewMint(shares) -
previewWithdraw(assets) -
previewRedeem(shares) -
requestDeposit(assets, controller, owner) -
deposit(assets, receiver) -
deposit(assets, receiver, controller) -
mint(shares, receiver) -
mint(shares, receiver, controller) -
requestRedeem(shares, controller, owner) -
withdraw(assets, receiver, ownerOrController) -
redeem(shares, receiver, ownerOrController) -
_convertToShares(assets, rounding) -
_convertToAssets(shares, rounding) -
_requestDeposit(assets, controller, owner, requestId) -
_mintSharesOnDepositFulfill(assets, shares) -
_deposit(callerOrController, receiver, assets, shares) -
_requestRedeem(shares, controller, owner, requestId) -
_burnSharesOnRedeemFulfill(, shares) -
_withdraw(caller, receiver, owner, assets, shares) -
_transferIn(from, assets) -
_transferOut(to, assets) -
_decimalsOffset() -
_depositShareOrigin() -
_redeemShareDestination() -
_isDepositAsync() -
_isRedeemAsync() -
_pendingDepositRequest(, ) -
_claimableDepositRequest(, ) -
_pendingRedeemRequest(, ) -
_claimableRedeemRequest(, ) -
_consumeClaimableDeposit(, ) -
_consumeClaimableMint(, ) -
_consumeClaimableWithdraw(, ) -
_consumeClaimableRedeem(, ) -
_asyncMaxDeposit() -
_asyncMaxMint() -
_asyncMaxWithdraw() -
_asyncMaxRedeem()
-
name() -
symbol() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_update(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
Deposit(sender, owner, assets, shares) -
Withdraw(sender, receiver, owner, assets, shares)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
RedeemRequest(controller, owner, requestId, sender, shares)
-
DepositRequest(controller, owner, requestId, sender, assets)
-
OperatorSet(controller, operator, approved)
-
ERC4626ExceededMaxDeposit(receiver, assets, max) -
ERC4626ExceededMaxMint(receiver, shares, max) -
ERC4626ExceededMaxWithdraw(owner, assets, max) -
ERC4626ExceededMaxRedeem(owner, shares, max) -
ERC7540InvalidOperator(controller, operator) -
ERC7540SyncDeposit() -
ERC7540AsyncDeposit() -
ERC7540SyncRedeem() -
ERC7540AsyncRedeem() -
ERC7540MissingAsync() -
ERC7540UnauthorizedMintSharesOnDepositFulfill() -
ERC7540UnauthorizedBurnSharesOnRedeemFulfill()
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
onlyOperatorOrController(bool async, address controller, address operator) modifier
Modifier that enforces operator-or-controller authorization.
When async is false the check is skipped, which allows the standard ERC-4626 flow where
msg.sender is the caller and no controller/operator distinction exists.
constructor(contract IERC20 asset_) internal
Sets the underlying asset contract. This must be an ERC-20-compatible contract.
Caches the asset’s decimals() value at construction time. If the call fails (e.g. the asset has not
been created yet), a default of 18 is used.
Requirements:
-
At least one of
_isDepositAsyncor_isRedeemAsyncmust returntrue.
Either _isDepositAsync or _isRedeemAsync must return true. Use {ERC4626} otherwise.
|
supportsInterface(bytes4 interfaceId) → bool public
See {IERC165-supportsInterface}.
Reports support for IERC7540Operator unconditionally. Support for IERC7540Deposit and
IERC7540Redeem is conditional on the corresponding async selector returning true.
isOperator(address controller, address operator) → bool status public
Returns true if the operator is approved as an operator for a controller.
setOperator(address operator, bool approved) → bool public
Grants or revokes permissions for operator to manage requests on behalf of the caller.
-
MUST set the operator status to the
approvedvalue. -
MUST emit the {OperatorSet} event when the operator status is set.
-
MUST return true.
_setOperator(address controller, address operator, bool approved) internal
Sets the operator approval status for controller to approved.
Emits an IERC7540Operator.OperatorSet event.
_checkOperatorOrController(bool async, address controller, address operator) internal
Reverts with ERC7540InvalidOperator if operator is not the controller and is not
approved as an operator for controller. When async is false the check is a no-op,
preserving standard ERC-4626 authorization semantics.
decimals() → uint8 public
Decimals are computed by adding the decimal offset on top of the underlying asset’s decimals. This "original" value is cached during construction of the vault contract. If this read operation fails (e.g., the asset has not been created yet), a default of 18 is used to represent the underlying asset’s decimals.
See {IERC20Metadata-decimals}.
asset() → address public
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.
totalAssets() → uint256 public
See {IERC4626-totalAssets}.
Pending deposit assets are subtracted from the vault’s token balance, since they have not yet been converted into shares and must not be treated as yield for outstanding shareholders.
Internal flows preserve the invariant balanceOf(asset, vault) >= totalPendingDepositAssets() for
any well-behaved ERC-20. Assets with transfer fees, negative rebases, or externally-mutable balances can
violate it and cause this function to revert with an underflow. Strategies that read totalAssets on the
claim path become uncallable in that state. Strategies that lock the rate at fulfillment time
are unaffected.
|
totalSupply() → uint256 public
See {IERC20-totalSupply}.
Adds totalPendingRedeemShares to the ERC-20 supply. When shares are burned at request time
(i.e. _redeemShareDestination returns address(0)), pending redeem shares are removed from
the on-chain supply but still logically outstanding until claimed; this override compensates.
As a consequence, two standard ERC-20 assumptions do not hold: (a) totalSupply() may
exceed the sum of all balanceOf() (pending shares are virtual and unowned); (b) totalSupply()
can change without a matching Transfer event when totalPendingRedeemShares changes. Integrators
that snapshot supply for governance or reward weighting, or reconstruct supply from event logs
(indexers, bridges), must account for this.
|
pendingDepositRequest(uint256 requestId, address controller) → uint256 public
Requirements:
-
_isDepositAsyncmust returntrue.
claimableDepositRequest(uint256 requestId, address controller) → uint256 public
Requirements:
-
_isDepositAsyncmust returntrue.
pendingRedeemRequest(uint256 requestId, address controller) → uint256 public
Requirements:
-
_isRedeemAsyncmust returntrue.
claimableRedeemRequest(uint256 requestId, address controller) → uint256 public
Requirements:
-
_isRedeemAsyncmust returntrue.
totalPendingDepositAssets() → uint256 public
Returns the total amount of underlying assets currently pending in deposit Requests.
totalPendingRedeemShares() → uint256 public
Returns the total amount of vault shares currently pending in redeem Requests.
convertToShares(uint256 assets) → uint256 public
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.
| 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. |
convertToAssets(uint256 shares) → uint256 public
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.
| 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. |
maxDeposit(address owner) → uint256 public
See {IERC4626-maxDeposit}.
When the deposit flow is synchronous, returns type(uint256).max (no vault-imposed limit).
When async, delegates to _asyncMaxDeposit which must be provided by the fulfillment strategy.
maxMint(address owner) → uint256 public
See {IERC4626-maxMint}.
When the deposit flow is synchronous, returns type(uint256).max.
When async, delegates to _asyncMaxMint.
maxWithdraw(address owner) → uint256 public
See {IERC4626-maxWithdraw}.
When the redeem flow is synchronous, returns the asset-equivalent of the owner’s share balance.
When async, delegates to _asyncMaxWithdraw.
maxRedeem(address owner) → uint256 public
See {IERC4626-maxRedeem}.
When the redeem flow is synchronous, returns the owner’s share balance.
When async, delegates to _asyncMaxRedeem.
previewDeposit(uint256 assets) → uint256 public
See {IERC4626-previewDeposit}.
MUST revert when _isDepositAsync returns true, per the ERC-7540 specification which
mandates that preview functions revert for async flows.
previewMint(uint256 shares) → uint256 public
See {IERC4626-previewMint}.
MUST revert when _isDepositAsync returns true.
previewWithdraw(uint256 assets) → uint256 public
See {IERC4626-previewWithdraw}.
MUST revert when _isRedeemAsync returns true.
previewRedeem(uint256 shares) → uint256 public
See {IERC4626-previewRedeem}.
MUST revert when _isRedeemAsync returns true.
requestDeposit(uint256 assets, address controller, address owner) → uint256 public
Transfers assets from owner into the vault and submits a deposit Request for controller.
The Request enters Pending state. Uses requestId = 0 by default; override _requestDeposit
to use non-zero request IDs.
Requirements:
-
_isDepositAsyncmust returntrue. -
ownermust bemsg.senderormsg.sendermust be an approved operator ofowner. -
ownermust have approved the vault for at leastassetsof the underlying token.
The controller is the only address authorized to claim the resulting Request. Passing an address
with no claim authority (e.g. address(0), 0x…dead) or any contract that cannot itself call
deposit/mint or designate an operator via setOperator will permanently lock the committed
assets, since claims are gated by onlyOperatorOrController on controller and there is no
cancellation path. Callers are responsible for supplying a controller capable of authorizing claims.
|
deposit(uint256 assets, address receiver) → uint256 public
See {IERC4626-deposit}. Calls the three-argument overload with msg.sender as controller.
deposit(uint256 assets, address receiver, address controller) → uint256 public
When async, claims assets worth of shares from a Claimable deposit Request controlled by controller,
and transfers the resulting shares to receiver. When sync, behaves as standard ERC-4626 deposit.
When _isDepositAsync is false, the controller parameter is ignored and receiver is used
for limit checks, matching standard ERC-4626 semantics.
|
Requirements:
-
assetsmust not exceedmaxDepositfor the relevant account. -
When async,
msg.sendermust becontrolleror an approved operator ofcontroller.
mint(uint256 shares, address receiver) → uint256 assets public
See {IERC4626-mint}. Calls the three-argument overload with msg.sender as controller.
mint(uint256 shares, address receiver, address controller) → uint256 public
See IERC7540Deposit.mint.
When async, claims exactly shares from a Claimable deposit Request controlled by controller,
and transfers them to receiver. When sync, behaves as standard ERC-4626 mint.
When _isDepositAsync is false, the controller parameter is ignored.
|
Requirements:
-
sharesmust not exceedmaxMintfor the relevant account. -
When async,
msg.sendermust becontrolleror an approved operator ofcontroller.
requestRedeem(uint256 shares, address controller, address owner) → uint256 public
Assumes control of shares from owner and submits a redeem Request for controller.
The Request enters Pending state. Uses requestId = 0 by default.
Authorization for a msg.sender not equal to owner may come from either ERC-20 approval
over the shares of owner or from operator approval (see IERC7540Operator). This is
consistent with the approach described in ERC-6909.
Requirements:
-
_isRedeemAsyncmust returntrue.
The controller is the only address authorized to claim the resulting Request. Passing an address
with no claim authority (e.g. address(0), 0x…dead) or any contract that cannot itself call
withdraw/redeem or designate an operator via setOperator will permanently lock the committed
shares, since claims are gated by onlyOperatorOrController on controller and there is no
cancellation path. Callers are responsible for supplying a controller capable of authorizing claims.
|
withdraw(uint256 assets, address receiver, address ownerOrController) → uint256 public
See {IERC4626-withdraw}.
When async, claims assets from a Claimable redeem Request controlled by ownerOrController,
and transfers the underlying assets to receiver. When sync, behaves as standard ERC-4626 withdraw.
Per ERC-7540, when async the ownerOrController parameter acts as the controller
(replacing the traditional ERC-4626 owner role).
|
Requirements:
-
assetsmust not exceedmaxWithdrawforownerOrController. -
When async,
msg.sendermust beownerOrControlleror an approved operator. -
When sync,
msg.sendermust beownerOrControlleror have sufficient ERC-20 allowance.
redeem(uint256 shares, address receiver, address ownerOrController) → uint256 public
See {IERC4626-redeem}.
When async, claims shares from a Claimable redeem Request controlled by ownerOrController,
and transfers the corresponding underlying assets to receiver. When sync, behaves as standard
ERC-4626 redeem.
Per ERC-7540, when async the ownerOrController parameter acts as the controller.
|
Requirements:
-
sharesmust not exceedmaxRedeemforownerOrController. -
When async,
msg.sendermust beownerOrControlleror an approved operator. -
When sync,
msg.sendermust beownerOrControlleror have sufficient ERC-20 allowance.
_convertToShares(uint256 assets, enum Math.Rounding rounding) → uint256 internal
Internal conversion function (from assets to shares) with support for rounding direction.
Uses virtual shares and virtual assets to mitigate the inflation attack vector described in
ERC-4626 security considerations.
The offset is configurable via _decimalsOffset.
_convertToAssets(uint256 shares, enum Math.Rounding rounding) → uint256 internal
Internal conversion function (from shares to assets) with support for rounding direction.
_requestDeposit(uint256 assets, address controller, address owner, uint256 requestId) → uint256 internal
Internal handler for deposit Requests. Increments totalPendingDepositAssets, transfers
assets from owner into the vault, and emits IERC7540Deposit.DepositRequest.
Strategy extensions (e.g. ERC7540AdminDeposit) should override this to record per-controller
pending state before calling super._requestDeposit(…).
Pending accounting is updated before _transferIn to follow Checks-Effects-Interactions.
Assets with transfer hooks (e.g. ERC-777) may observe totalAssets temporarily understated
during the transfer, since _totalPendingDepositAssets is already incremented while the
token balance has not yet increased.
|
Requirements:
-
_isDepositAsyncmust returntrue, otherwise reverts withERC7540SyncDeposit.
_mintSharesOnDepositFulfill(uint256 assets, uint256 shares) internal
Mints shares to _depositShareOrigin as part of deposit fulfillment when using the
pre-mint share custody model. Decrements totalPendingDepositAssets by assets.
This function requires _depositShareOrigin to return a non-zero address.
When _depositShareOrigin returns address(0), shares are minted directly at claim time
inside _deposit and this function must not be called.
|
_deposit(address callerOrController, address receiver, uint256 assets, uint256 shares) internal
Common workflow for deposit and mint claim operations.
Handles three cases depending on the vault configuration:
-
Synchronous (
_isDepositAsyncreturnsfalse): transfers assets fromcallerOrControllerinto the vault and mints new shares toreceiver. Standard ERC-4626 behavior. -
Async, mint-on-claim (
_depositShareOriginreturnsaddress(0)): decrements_totalPendingDepositAssetsand mints new shares toreceiver. No asset transfer occurs since assets were already transferred duringrequestDeposit. -
Async, pre-minted (
_depositShareOriginreturns non-zero): transfers pre-minted shares from the share origin address toreceiver.
Emits {IERC4626-Deposit}. Per ERC-7540, the first event parameter is the controller in async
mode and msg.sender in sync mode.
_requestRedeem(uint256 shares, address controller, address owner, uint256 requestId) → uint256 internal
Internal handler for redeem Requests. Assumes control of shares from owner and
emits IERC7540Redeem.RedeemRequest.
Share custody depends on _redeemShareDestination:
-
address(0)(default): shares are burned immediately and_totalPendingRedeemSharesis incremented to keeptotalSupplyaccurate. -
Non-zero address: shares are transferred to that address and held until fulfillment.
Authorization for a msg.sender not equal to owner is checked via operator status first;
if that fails, ERC-20 allowance is spent via {ERC20-_spendAllowance}. This dual-authorization
approach is consistent with ERC-6909 semantics.
Requirements:
-
_isRedeemAsyncmust returntrue, otherwise reverts withERC7540SyncRedeem.
_burnSharesOnRedeemFulfill(uint256, uint256 shares) internal
Burns shares from _redeemShareDestination as part of redeem fulfillment when using
the escrow share custody model. Increments totalPendingRedeemShares by shares.
This function requires _redeemShareDestination to return a non-zero address.
When _redeemShareDestination returns address(0), shares were already burned at request
time inside _requestRedeem and this function must not be called.
|
_withdraw(address caller, address receiver, address owner, uint256 assets, uint256 shares) internal
Common workflow for withdraw and redeem claim operations.
Handles two cases depending on the vault configuration:
-
Synchronous (
_isRedeemAsyncreturnsfalse): spends ERC-20 allowance ifcalleris notowner, burns shares fromowner, and transfers underlying assets toreceiver. -
Async: decrements
_totalPendingRedeemShares(shares were already burned/escrowed during the Request or fulfillment phase) and transfers underlying assets toreceiver.
Emits {IERC4626-Withdraw}.
_transferIn(address from, uint256 assets) internal
Performs a transfer-in of underlying assets from from to the vault.
The default implementation uses {SafeERC20-safeTransferFrom}. Used by _deposit (sync) and
_requestDeposit (async).
_transferOut(address to, uint256 assets) internal
Performs a transfer-out of underlying assets from the vault to to.
The default implementation uses {SafeERC20-safeTransfer}. Used by _withdraw.
_decimalsOffset() → uint8 internal
Returns the decimal offset used for virtual shares/assets in _convertToShares and
_convertToAssets. Defaults to 0. Increase to strengthen inflation-attack protection
at the cost of share-price granularity.
_depositShareOrigin() → address internal
Returns the address from which shares are transferred to the receiver on deposit claim.
-
address(0)(default): shares are minted directly to the receiver at claim time. Pending deposit assets are tracked viatotalPendingDepositAssetsand decremented in_deposit. -
Non-zero address: shares are pre-minted to this address during fulfillment (via
_mintSharesOnDepositFulfill) and transferred to the receiver on claim.
If overridden to return a non-zero address, that address must not be able to transfer
shares (otherwise pre-minted shares could be moved before they are claimed). Use an unowned
address such as address(0xdead). Avoid addresses in the precompile reserved range
(address(1) through address(0x1ff), see EIP-7587).
|
_redeemShareDestination() → address internal
Returns the address to which shares are transferred (escrowed) on redeem request.
-
address(0)(default): shares are burned immediately at request time. Pending redeem shares are tracked viatotalPendingRedeemSharesso thattotalSupplyremains accurate. -
Non-zero address: shares are transferred to this address on request and burned during fulfillment (via
_burnSharesOnRedeemFulfill).
If overridden to return a non-zero address, that address must not be able to transfer
shares (otherwise escrowed shares could be moved before they are burned). Use an unowned
address such as address(0xdead). Avoid addresses in the precompile reserved range
(address(1) through address(0x1ff), see EIP-7587).
|
_isDepositAsync() → bool internal
Returns true if the deposit flow is asynchronous (Request-based). When false, deposit and
mint behave as standard synchronous ERC-4626 operations.
Override to return true in extensions that provide an async deposit fulfillment strategy.
_isRedeemAsync() → bool internal
Returns true if the redeem flow is asynchronous (Request-based). When false, withdraw and
redeem behave as standard synchronous ERC-4626 operations.
Override to return true in extensions that provide an async redeem fulfillment strategy.
_pendingDepositRequest(uint256, address) → uint256 internal
Returns the amount of assets in Pending state for controller with the given requestId.
_claimableDepositRequest(uint256, address) → uint256 internal
Returns the amount of assets in Claimable state for controller with the given requestId.
_pendingRedeemRequest(uint256, address) → uint256 internal
Returns the amount of shares in Pending state for controller with the given requestId.
_claimableRedeemRequest(uint256, address) → uint256 internal
Returns the amount of shares in Claimable state for controller with the given requestId.
_consumeClaimableDeposit(uint256, address) → uint256 internal
Consumes assets worth of a Claimable deposit for controller and returns the corresponding
number of shares. Called by deposit (three-argument overload) in async mode.
In async mode, this function may be susceptible to the inflation attack vector described in
ERC-4626 security considerations
if the shares are freed automatically (e.g. after a certain time period). Consider using _decimalsOffset
to mitigate this risk.
|
_consumeClaimableMint(uint256, address) → uint256 internal
Consumes shares worth of a Claimable deposit for controller and returns the corresponding
number of assets. Called by mint (three-argument overload) in async mode.
_consumeClaimableWithdraw(uint256, address) → uint256 internal
Consumes assets worth of a Claimable redeem for controller and returns the corresponding
number of shares. Called by withdraw in async mode.
_consumeClaimableRedeem(uint256, address) → uint256 internal
Consumes shares worth of a Claimable redeem for controller and returns the corresponding
number of assets. Called by redeem in async mode.
_asyncMaxDeposit(address) → uint256 internal
Returns the maximum assets that can be claimed via deposit for an async owner.
_asyncMaxMint(address) → uint256 internal
Returns the maximum shares that can be claimed via mint for an async owner.
_asyncMaxWithdraw(address) → uint256 internal
Returns the maximum assets that can be claimed via withdraw for an async owner.
_asyncMaxRedeem(address) → uint256 internal
Returns the maximum shares that can be claimed via redeem for an async owner.
ERC4626ExceededMaxDeposit(address receiver, uint256 assets, uint256 max) error
Attempted to deposit more assets than the max amount for receiver.
ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max) error
Attempted to mint more shares than the max amount for receiver.
ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max) error
Attempted to withdraw more assets than the max amount for owner.
ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max) error
Attempted to redeem more shares than the max amount for owner.
ERC7540InvalidOperator(address controller, address operator) error
The operator is not the caller or an approved operator of the controller.
ERC7540SyncDeposit() error
A deposit Request was attempted but _isDepositAsync returns false.
ERC7540AsyncDeposit() error
A synchronous deposit preview was attempted but _isDepositAsync returns true.
ERC7540SyncRedeem() error
A redeem Request was attempted but _isRedeemAsync returns false.
ERC7540AsyncRedeem() error
A synchronous redeem preview was attempted but _isRedeemAsync returns true.
ERC7540MissingAsync() error
Neither _isDepositAsync nor _isRedeemAsync returns true.
ERC7540AdminDeposit
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC7540AdminDeposit.sol";
Admin-controlled (operator-triggered) fulfillment strategy for asynchronous deposits.
Extends ERC7540 with a deposit flow where a privileged caller explicitly transitions requests
from Pending to Claimable by calling _fulfillDeposit. The caller provides both the assets
amount and the corresponding shares, giving the fulfiller explicit control over the exchange rate.
This is the most flexible fulfillment model. Epoch-based batch settlement, FIFO queues, and cross-chain oracle-gated settlement can all be composed on top.
Production equivalents include USDai, Nest (Plume), MetaVault, and Centrifuge.
All requests share requestId = 0 (per-controller accounting only).
-
_isDepositAsync() -
_requestDeposit(assets, controller, owner, requestId) -
_fulfillDeposit(assets, shares, controller) -
_consumeClaimableDeposit(assets, controller) -
_consumeClaimableMint(shares, controller) -
_pendingDepositRequest(, controller) -
_claimableDepositRequest(, controller) -
_asyncMaxDeposit(owner) -
_asyncMaxMint(owner)
-
supportsInterface(interfaceId) -
isOperator(controller, operator) -
setOperator(operator, approved) -
_setOperator(controller, operator, approved) -
_checkOperatorOrController(async, controller, operator) -
decimals() -
asset() -
share() -
vault(asset_) -
totalAssets() -
totalSupply() -
pendingDepositRequest(requestId, controller) -
claimableDepositRequest(requestId, controller) -
pendingRedeemRequest(requestId, controller) -
claimableRedeemRequest(requestId, controller) -
totalPendingDepositAssets() -
totalPendingRedeemShares() -
convertToShares(assets) -
convertToAssets(shares) -
maxDeposit(owner) -
maxMint(owner) -
maxWithdraw(owner) -
maxRedeem(owner) -
previewDeposit(assets) -
previewMint(shares) -
previewWithdraw(assets) -
previewRedeem(shares) -
requestDeposit(assets, controller, owner) -
deposit(assets, receiver) -
deposit(assets, receiver, controller) -
mint(shares, receiver) -
mint(shares, receiver, controller) -
requestRedeem(shares, controller, owner) -
withdraw(assets, receiver, ownerOrController) -
redeem(shares, receiver, ownerOrController) -
_convertToShares(assets, rounding) -
_convertToAssets(shares, rounding) -
_mintSharesOnDepositFulfill(assets, shares) -
_deposit(callerOrController, receiver, assets, shares) -
_requestRedeem(shares, controller, owner, requestId) -
_burnSharesOnRedeemFulfill(, shares) -
_withdraw(caller, receiver, owner, assets, shares) -
_transferIn(from, assets) -
_transferOut(to, assets) -
_decimalsOffset() -
_depositShareOrigin() -
_redeemShareDestination() -
_isRedeemAsync() -
_pendingRedeemRequest(, ) -
_claimableRedeemRequest(, ) -
_consumeClaimableWithdraw(, ) -
_consumeClaimableRedeem(, ) -
_asyncMaxWithdraw() -
_asyncMaxRedeem()
-
name() -
symbol() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_update(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
DepositClaimable(controller, requestId, assets, shares)
-
Deposit(sender, owner, assets, shares) -
Withdraw(sender, receiver, owner, assets, shares)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
RedeemRequest(controller, owner, requestId, sender, shares)
-
DepositRequest(controller, owner, requestId, sender, assets)
-
OperatorSet(controller, operator, approved)
-
ERC7540DepositInsufficientPendingAssets(assets, pendingAssets)
-
ERC4626ExceededMaxDeposit(receiver, assets, max) -
ERC4626ExceededMaxMint(receiver, shares, max) -
ERC4626ExceededMaxWithdraw(owner, assets, max) -
ERC4626ExceededMaxRedeem(owner, shares, max) -
ERC7540InvalidOperator(controller, operator) -
ERC7540SyncDeposit() -
ERC7540AsyncDeposit() -
ERC7540SyncRedeem() -
ERC7540AsyncRedeem() -
ERC7540MissingAsync() -
ERC7540UnauthorizedMintSharesOnDepositFulfill() -
ERC7540UnauthorizedBurnSharesOnRedeemFulfill()
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
_isDepositAsync() → bool internal
Returns true if the deposit flow is asynchronous (Request-based). When false, deposit and
mint behave as standard synchronous ERC-4626 operations.
Override to return true in extensions that provide an async deposit fulfillment strategy.
_requestDeposit(uint256 assets, address controller, address owner, uint256 requestId) → uint256 internal
Records per-controller pending state before delegating to ERC7540._requestDeposit.
_fulfillDeposit(uint256 assets, uint256 shares, address controller) internal
Fulfills a pending deposit request by transitioning it from Pending to Claimable state.
The caller provides both assets and shares, locking the exchange rate at fulfillment time.
The fulfiller should ensure the vault’s totalAssets() already reflects the deposited assets
(e.g. after deploying them to a yield source) to avoid diluting existing holders.
Emits a DepositClaimable event.
Requirements:
-
assetsmust not exceed the pending deposit amount for thecontroller.
Multiple fulfillments with different exchange rates will blend into a weighted average.
For example, fulfilling 50 assets → 100 shares (2:1) then 50 assets → 25 shares (0.5:1) produces
claimableAssets=100 and claimableShares=125. A partial claim of 50 assets yields
mulDiv(50, 125, 100) = 62 shares: the weighted average rate, not either original rate.
Integrators expecting per-fulfillment rate isolation should use a different strategy (e.g. epochs).
|
_consumeClaimableDeposit(uint256 assets, address controller) → uint256 internal
Consumes assets from the claimable deposit and returns the proportional shares (rounded down).
_consumeClaimableMint(uint256 shares, address controller) → uint256 internal
Consumes shares from the claimable deposit and returns the proportional assets (rounded up).
_pendingDepositRequest(uint256, address controller) → uint256 internal
Returns the amount of assets in Pending state for controller with the given requestId.
_claimableDepositRequest(uint256, address controller) → uint256 internal
Returns the amount of assets in Claimable state for controller with the given requestId.
_asyncMaxDeposit(address owner) → uint256 internal
Returns the maximum assets that can be claimed via deposit for an async owner.
_asyncMaxMint(address owner) → uint256 internal
Returns the maximum shares that can be claimed via mint for an async owner.
ERC7540AdminRedeem
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC7540AdminRedeem.sol";
Admin-controlled (operator-triggered) fulfillment strategy for asynchronous redemptions.
Extends ERC7540 with a redeem flow where a privileged caller explicitly transitions requests
from Pending to Claimable by calling _fulfillRedeem. The caller provides both the shares
amount and the corresponding assets, giving the fulfiller explicit control over the exchange rate.
The fulfiller must ensure the vault holds enough underlying assets before calling _fulfillRedeem.
Asset sourcing (unwinding positions, bridging cross-chain, etc.) is application-specific and is
not part of this contract.
Production equivalents include USDai, Nest (Plume), MetaVault, and Centrifuge.
All requests share requestId = 0 (per-controller accounting only).
-
_isRedeemAsync() -
_requestRedeem(shares, controller, owner, requestId) -
_fulfillRedeem(shares, assets, controller) -
_consumeClaimableWithdraw(assets, controller) -
_consumeClaimableRedeem(shares, controller) -
_pendingRedeemRequest(, controller) -
_claimableRedeemRequest(, controller) -
_asyncMaxWithdraw(owner) -
_asyncMaxRedeem(owner)
-
supportsInterface(interfaceId) -
isOperator(controller, operator) -
setOperator(operator, approved) -
_setOperator(controller, operator, approved) -
_checkOperatorOrController(async, controller, operator) -
decimals() -
asset() -
share() -
vault(asset_) -
totalAssets() -
totalSupply() -
pendingDepositRequest(requestId, controller) -
claimableDepositRequest(requestId, controller) -
pendingRedeemRequest(requestId, controller) -
claimableRedeemRequest(requestId, controller) -
totalPendingDepositAssets() -
totalPendingRedeemShares() -
convertToShares(assets) -
convertToAssets(shares) -
maxDeposit(owner) -
maxMint(owner) -
maxWithdraw(owner) -
maxRedeem(owner) -
previewDeposit(assets) -
previewMint(shares) -
previewWithdraw(assets) -
previewRedeem(shares) -
requestDeposit(assets, controller, owner) -
deposit(assets, receiver) -
deposit(assets, receiver, controller) -
mint(shares, receiver) -
mint(shares, receiver, controller) -
requestRedeem(shares, controller, owner) -
withdraw(assets, receiver, ownerOrController) -
redeem(shares, receiver, ownerOrController) -
_convertToShares(assets, rounding) -
_convertToAssets(shares, rounding) -
_requestDeposit(assets, controller, owner, requestId) -
_mintSharesOnDepositFulfill(assets, shares) -
_deposit(callerOrController, receiver, assets, shares) -
_burnSharesOnRedeemFulfill(, shares) -
_withdraw(caller, receiver, owner, assets, shares) -
_transferIn(from, assets) -
_transferOut(to, assets) -
_decimalsOffset() -
_depositShareOrigin() -
_redeemShareDestination() -
_isDepositAsync() -
_pendingDepositRequest(, ) -
_claimableDepositRequest(, ) -
_consumeClaimableDeposit(, ) -
_consumeClaimableMint(, ) -
_asyncMaxDeposit() -
_asyncMaxMint()
-
name() -
symbol() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_update(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
RedeemClaimable(controller, requestId, assets, shares)
-
Deposit(sender, owner, assets, shares) -
Withdraw(sender, receiver, owner, assets, shares)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
RedeemRequest(controller, owner, requestId, sender, shares)
-
DepositRequest(controller, owner, requestId, sender, assets)
-
OperatorSet(controller, operator, approved)
-
ERC7540RedeemInsufficientPendingShares(shares, pendingShares)
-
ERC4626ExceededMaxDeposit(receiver, assets, max) -
ERC4626ExceededMaxMint(receiver, shares, max) -
ERC4626ExceededMaxWithdraw(owner, assets, max) -
ERC4626ExceededMaxRedeem(owner, shares, max) -
ERC7540InvalidOperator(controller, operator) -
ERC7540SyncDeposit() -
ERC7540AsyncDeposit() -
ERC7540SyncRedeem() -
ERC7540AsyncRedeem() -
ERC7540MissingAsync() -
ERC7540UnauthorizedMintSharesOnDepositFulfill() -
ERC7540UnauthorizedBurnSharesOnRedeemFulfill()
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
_isRedeemAsync() → bool internal
Returns true if the redeem flow is asynchronous (Request-based). When false, withdraw and
redeem behave as standard synchronous ERC-4626 operations.
Override to return true in extensions that provide an async redeem fulfillment strategy.
_requestRedeem(uint256 shares, address controller, address owner, uint256 requestId) → uint256 internal
Records per-controller pending state before delegating to ERC7540._requestRedeem.
_fulfillRedeem(uint256 shares, uint256 assets, address controller) internal
Fulfills a pending redeem request by transitioning it from Pending to Claimable state.
The caller provides both shares and assets, locking the exchange rate at fulfillment time.
The fulfiller must ensure the vault holds enough underlying assets to cover the assets amount
before calling this function.
Emits a RedeemClaimable event.
Requirements:
-
sharesmust not exceed the pending redeem amount for thecontroller.
_consumeClaimableWithdraw(uint256 assets, address controller) → uint256 internal
Consumes assets from the claimable redeem and returns the proportional shares (rounded up).
_consumeClaimableRedeem(uint256 shares, address controller) → uint256 internal
Consumes shares from the claimable redeem and returns the proportional assets (rounded down).
_pendingRedeemRequest(uint256, address controller) → uint256 internal
Returns the amount of shares in Pending state for controller with the given requestId.
_claimableRedeemRequest(uint256, address controller) → uint256 internal
Returns the amount of shares in Claimable state for controller with the given requestId.
_asyncMaxWithdraw(address owner) → uint256 internal
Returns the maximum assets that can be claimed via withdraw for an async owner.
_asyncMaxRedeem(address owner) → uint256 internal
Returns the maximum shares that can be claimed via redeem for an async owner.
ERC7540DelayDeposit
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC7540DelayDeposit.sol";
Time-delay fulfillment strategy for asynchronous deposits.
Extends ERC7540 with a deposit flow where requests become permissionlessly claimable after a
configurable waiting period. No privileged fulfiller is needed — once the delay elapses, the
controller (or any keeper) can claim. The exchange rate is computed at claim time using the vault’s
live convertToShares.
Production equivalents (redeem side): BeefySonic, MagmaV2, Tangle.
Requests are tracked using {Checkpoints-Trace208}, storing cumulative deposit amounts keyed by
their maturity timepoint. The requestId returned by requestDeposit equals the absolute
timestamp at which the request becomes claimable (clock() + depositDelay(controller)).
Override depositDelay to customize the waiting period (default: 1 hour) and clock to
change the time source (default: block.timestamp).
This module does not support temporary share custody through _depositShareOrigin. The constructor
tries to enforce that property, but the check may be insufficient if _depositShareOrigin reads from
storage that is not yet initialized when the parent’s constructor runs
|
-
constructor() -
clock() -
CLOCK_MODE() -
depositDelay() -
_isDepositAsync() -
_requestDeposit(assets, controller, owner, ) -
_consumeClaimableDeposit(assets, controller) -
_consumeClaimableMint(shares, controller) -
_pendingDepositRequest(requestId, controller) -
_claimableDepositRequest(requestId, controller) -
_asyncMaxDeposit(owner) -
_asyncMaxMint(owner) -
_readyDepositAt(owner, timepoint)
-
supportsInterface(interfaceId) -
isOperator(controller, operator) -
setOperator(operator, approved) -
_setOperator(controller, operator, approved) -
_checkOperatorOrController(async, controller, operator) -
decimals() -
asset() -
share() -
vault(asset_) -
totalAssets() -
totalSupply() -
pendingDepositRequest(requestId, controller) -
claimableDepositRequest(requestId, controller) -
pendingRedeemRequest(requestId, controller) -
claimableRedeemRequest(requestId, controller) -
totalPendingDepositAssets() -
totalPendingRedeemShares() -
convertToShares(assets) -
convertToAssets(shares) -
maxDeposit(owner) -
maxMint(owner) -
maxWithdraw(owner) -
maxRedeem(owner) -
previewDeposit(assets) -
previewMint(shares) -
previewWithdraw(assets) -
previewRedeem(shares) -
requestDeposit(assets, controller, owner) -
deposit(assets, receiver) -
deposit(assets, receiver, controller) -
mint(shares, receiver) -
mint(shares, receiver, controller) -
requestRedeem(shares, controller, owner) -
withdraw(assets, receiver, ownerOrController) -
redeem(shares, receiver, ownerOrController) -
_convertToShares(assets, rounding) -
_convertToAssets(shares, rounding) -
_mintSharesOnDepositFulfill(assets, shares) -
_deposit(callerOrController, receiver, assets, shares) -
_requestRedeem(shares, controller, owner, requestId) -
_burnSharesOnRedeemFulfill(, shares) -
_withdraw(caller, receiver, owner, assets, shares) -
_transferIn(from, assets) -
_transferOut(to, assets) -
_decimalsOffset() -
_depositShareOrigin() -
_redeemShareDestination() -
_isRedeemAsync() -
_pendingRedeemRequest(, ) -
_claimableRedeemRequest(, ) -
_consumeClaimableWithdraw(, ) -
_consumeClaimableRedeem(, ) -
_asyncMaxWithdraw() -
_asyncMaxRedeem()
-
name() -
symbol() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_update(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
Deposit(sender, owner, assets, shares) -
Withdraw(sender, receiver, owner, assets, shares)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
RedeemRequest(controller, owner, requestId, sender, shares)
-
DepositRequest(controller, owner, requestId, sender, assets)
-
OperatorSet(controller, operator, approved)
-
ERC7540DelayInvalidDepositShareOrigin()
-
ERC4626ExceededMaxDeposit(receiver, assets, max) -
ERC4626ExceededMaxMint(receiver, shares, max) -
ERC4626ExceededMaxWithdraw(owner, assets, max) -
ERC4626ExceededMaxRedeem(owner, shares, max) -
ERC7540InvalidOperator(controller, operator) -
ERC7540SyncDeposit() -
ERC7540AsyncDeposit() -
ERC7540SyncRedeem() -
ERC7540AsyncRedeem() -
ERC7540MissingAsync() -
ERC7540UnauthorizedMintSharesOnDepositFulfill() -
ERC7540UnauthorizedBurnSharesOnRedeemFulfill()
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
clock() → uint48 public
Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting).
depositDelay(address) → uint48 public
Returns the delay duration before a deposit request becomes claimable. Defaults to 1 hour.
For any given controller, the maturity timepoint clock() + depositDelay(controller) MUST
be non-decreasing across successive requestDeposit calls. Overrides that shrink the delay faster
than clock() advances will cause new requests to revert until the previous maturity is reached.
|
_isDepositAsync() → bool internal
Returns true if the deposit flow is asynchronous (Request-based). When false, deposit and
mint behave as standard synchronous ERC-4626 operations.
Override to return true in extensions that provide an async deposit fulfillment strategy.
_requestDeposit(uint256 assets, address controller, address owner, uint256) → uint256 internal
Pushes a new cumulative checkpoint at the maturity timepoint and delegates to
ERC7540._requestDeposit with the timepoint as requestId.
_consumeClaimableDeposit(uint256 assets, address controller) → uint256 internal
Consumes assets from claimable deposits, returns proportional shares (rounded down).
Requirements:
-
maxMintmust not be 0 forcontroller. Panics with division by zero otherwise.
_consumeClaimableMint(uint256 shares, address controller) → uint256 internal
Consumes shares from claimable deposits, returns proportional assets (rounded up).
_pendingDepositRequest(uint256 requestId, address controller) → uint256 internal
Returns the assets in Pending state for a specific requestId (timepoint).
A request is pending only if its timepoint is strictly in the future.
_claimableDepositRequest(uint256 requestId, address controller) → uint256 internal
Returns the assets in Claimable state for a specific requestId (timepoint).
A request is claimable once its timepoint has elapsed and the assets haven’t been claimed yet.
_asyncMaxDeposit(address owner) → uint256 internal
Returns the total claimable assets across all matured timepoints for owner.
_asyncMaxMint(address owner) → uint256 internal
Returns the share-equivalent of _asyncMaxDeposit (rounded down).
_readyDepositAt(address owner, uint48 timepoint) → uint256 internal
Internal helper: fetch the amount that is expected to be claimable at a given timepoint, if any. Any amount that has already been claimed is taken into consideration.
ERC7540DelayInvalidDepositShareOrigin() error
Triggered if _depositShareOrigin is not address(0), as this is not supported by this module.
ERC7540DelayRedeem
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC7540DelayRedeem.sol";
Time-delay fulfillment strategy for asynchronous redemptions.
Extends ERC7540 with a redeem flow where requests become permissionlessly claimable after a
configurable waiting period. No privileged fulfiller is needed — once the delay elapses, the
controller (or any keeper) can claim. The exchange rate is computed at claim time using the vault’s
live convertToAssets.
Production equivalents: BeefySonic (protocol-dictated SFC unbonding), MagmaV2 (admin-configurable delay), Tangle (protocol-dictated).
Requests are tracked using {Checkpoints-Trace208}, storing cumulative redeem amounts keyed by
their maturity timepoint. The requestId returned by requestRedeem equals the absolute
timestamp at which the request becomes claimable (clock() + redeemDelay(controller)).
Override redeemDelay to customize the waiting period (default: 1 hour) and clock to
change the time source (default: block.timestamp).
This module does not support temporary share custody through _redeemShareDestination. The constructor
tries to enforce that property, but the check may be insufficient if _redeemShareDestination reads from
storage that is not yet initialized when the parent’s constructor runs.
|
-
constructor() -
clock() -
CLOCK_MODE() -
redeemDelay() -
_isRedeemAsync() -
_requestRedeem(shares, controller, owner, ) -
_consumeClaimableWithdraw(assets, controller) -
_consumeClaimableRedeem(shares, controller) -
_pendingRedeemRequest(requestId, controller) -
_claimableRedeemRequest(requestId, controller) -
_asyncMaxWithdraw(owner) -
_asyncMaxRedeem(owner) -
_readyRedeemAt(owner, timepoint)
-
supportsInterface(interfaceId) -
isOperator(controller, operator) -
setOperator(operator, approved) -
_setOperator(controller, operator, approved) -
_checkOperatorOrController(async, controller, operator) -
decimals() -
asset() -
share() -
vault(asset_) -
totalAssets() -
totalSupply() -
pendingDepositRequest(requestId, controller) -
claimableDepositRequest(requestId, controller) -
pendingRedeemRequest(requestId, controller) -
claimableRedeemRequest(requestId, controller) -
totalPendingDepositAssets() -
totalPendingRedeemShares() -
convertToShares(assets) -
convertToAssets(shares) -
maxDeposit(owner) -
maxMint(owner) -
maxWithdraw(owner) -
maxRedeem(owner) -
previewDeposit(assets) -
previewMint(shares) -
previewWithdraw(assets) -
previewRedeem(shares) -
requestDeposit(assets, controller, owner) -
deposit(assets, receiver) -
deposit(assets, receiver, controller) -
mint(shares, receiver) -
mint(shares, receiver, controller) -
requestRedeem(shares, controller, owner) -
withdraw(assets, receiver, ownerOrController) -
redeem(shares, receiver, ownerOrController) -
_convertToShares(assets, rounding) -
_convertToAssets(shares, rounding) -
_requestDeposit(assets, controller, owner, requestId) -
_mintSharesOnDepositFulfill(assets, shares) -
_deposit(callerOrController, receiver, assets, shares) -
_burnSharesOnRedeemFulfill(, shares) -
_withdraw(caller, receiver, owner, assets, shares) -
_transferIn(from, assets) -
_transferOut(to, assets) -
_decimalsOffset() -
_depositShareOrigin() -
_redeemShareDestination() -
_isDepositAsync() -
_pendingDepositRequest(, ) -
_claimableDepositRequest(, ) -
_consumeClaimableDeposit(, ) -
_consumeClaimableMint(, ) -
_asyncMaxDeposit() -
_asyncMaxMint()
-
name() -
symbol() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_update(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
Deposit(sender, owner, assets, shares) -
Withdraw(sender, receiver, owner, assets, shares)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
RedeemRequest(controller, owner, requestId, sender, shares)
-
DepositRequest(controller, owner, requestId, sender, assets)
-
OperatorSet(controller, operator, approved)
-
ERC7540DelayInvalidRedeemShareDestination()
-
ERC4626ExceededMaxDeposit(receiver, assets, max) -
ERC4626ExceededMaxMint(receiver, shares, max) -
ERC4626ExceededMaxWithdraw(owner, assets, max) -
ERC4626ExceededMaxRedeem(owner, shares, max) -
ERC7540InvalidOperator(controller, operator) -
ERC7540SyncDeposit() -
ERC7540AsyncDeposit() -
ERC7540SyncRedeem() -
ERC7540AsyncRedeem() -
ERC7540MissingAsync() -
ERC7540UnauthorizedMintSharesOnDepositFulfill() -
ERC7540UnauthorizedBurnSharesOnRedeemFulfill()
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
clock() → uint48 public
Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting).
redeemDelay(address) → uint48 public
Returns the delay duration before a redeem request becomes claimable. Defaults to 1 hour.
For any given controller, the maturity timepoint clock() + redeemDelay(controller) MUST
be non-decreasing across successive requestRedeem calls. Overrides that shrink the delay faster
than clock() advances will cause new requests to revert until the previous maturity is reached.
|
_isRedeemAsync() → bool internal
Returns true if the redeem flow is asynchronous (Request-based). When false, withdraw and
redeem behave as standard synchronous ERC-4626 operations.
Override to return true in extensions that provide an async redeem fulfillment strategy.
_requestRedeem(uint256 shares, address controller, address owner, uint256) → uint256 internal
Pushes a new cumulative checkpoint at the maturity timepoint and delegates to
ERC7540._requestRedeem with the timepoint as requestId.
_consumeClaimableWithdraw(uint256 assets, address controller) → uint256 internal
Consumes assets from claimable redeems, returns proportional shares (rounded up).
_consumeClaimableRedeem(uint256 shares, address controller) → uint256 internal
Consumes shares from claimable redeems, returns proportional assets (rounded down).
_pendingRedeemRequest(uint256 requestId, address controller) → uint256 internal
Returns the shares in Pending state for a specific requestId (timepoint).
A request is pending only if its timepoint is strictly in the future.
_claimableRedeemRequest(uint256 requestId, address controller) → uint256 internal
Returns the shares in Claimable state for a specific requestId (timepoint).
A request is claimable once its timepoint has elapsed and the shares haven’t been claimed yet.
_asyncMaxWithdraw(address owner) → uint256 internal
Returns the asset-equivalent of _asyncMaxRedeem (rounded down).
_asyncMaxRedeem(address owner) → uint256 internal
Returns the total claimable shares across all matured timepoints for owner.
_readyRedeemAt(address owner, uint48 timepoint) → uint256 internal
Internal helper: fetch the amount that is expected to be claimable at a given timepoint, if any. Any amount that has already been claimed is taken into consideration.
ERC7540DelayInvalidRedeemShareDestination() error
Triggered if _redeemShareDestination is not address(0), as this is not supported by this module.
ERC7540SyncDeposit
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC7540SyncDeposit.sol";
Module for enabling synchronous behavior (ERC-4626) for the deposit flow of an ERC-7540 vault.
Note that an ERC-7540 vault is required to have at least one flow operating in asynchronous mode, so this module
cannot be combined with ERC7540SyncRedeem.
-
_isDepositAsync() -
_consumeClaimableDeposit(, ) -
_consumeClaimableMint(, ) -
_pendingDepositRequest(, ) -
_claimableDepositRequest(, ) -
_asyncMaxDeposit() -
_asyncMaxMint()
-
supportsInterface(interfaceId) -
isOperator(controller, operator) -
setOperator(operator, approved) -
_setOperator(controller, operator, approved) -
_checkOperatorOrController(async, controller, operator) -
decimals() -
asset() -
share() -
vault(asset_) -
totalAssets() -
totalSupply() -
pendingDepositRequest(requestId, controller) -
claimableDepositRequest(requestId, controller) -
pendingRedeemRequest(requestId, controller) -
claimableRedeemRequest(requestId, controller) -
totalPendingDepositAssets() -
totalPendingRedeemShares() -
convertToShares(assets) -
convertToAssets(shares) -
maxDeposit(owner) -
maxMint(owner) -
maxWithdraw(owner) -
maxRedeem(owner) -
previewDeposit(assets) -
previewMint(shares) -
previewWithdraw(assets) -
previewRedeem(shares) -
requestDeposit(assets, controller, owner) -
deposit(assets, receiver) -
deposit(assets, receiver, controller) -
mint(shares, receiver) -
mint(shares, receiver, controller) -
requestRedeem(shares, controller, owner) -
withdraw(assets, receiver, ownerOrController) -
redeem(shares, receiver, ownerOrController) -
_convertToShares(assets, rounding) -
_convertToAssets(shares, rounding) -
_requestDeposit(assets, controller, owner, requestId) -
_mintSharesOnDepositFulfill(assets, shares) -
_deposit(callerOrController, receiver, assets, shares) -
_requestRedeem(shares, controller, owner, requestId) -
_burnSharesOnRedeemFulfill(, shares) -
_withdraw(caller, receiver, owner, assets, shares) -
_transferIn(from, assets) -
_transferOut(to, assets) -
_decimalsOffset() -
_depositShareOrigin() -
_redeemShareDestination() -
_isRedeemAsync() -
_pendingRedeemRequest(, ) -
_claimableRedeemRequest(, ) -
_consumeClaimableWithdraw(, ) -
_consumeClaimableRedeem(, ) -
_asyncMaxWithdraw() -
_asyncMaxRedeem()
-
name() -
symbol() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_update(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
Deposit(sender, owner, assets, shares) -
Withdraw(sender, receiver, owner, assets, shares)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
RedeemRequest(controller, owner, requestId, sender, shares)
-
DepositRequest(controller, owner, requestId, sender, assets)
-
OperatorSet(controller, operator, approved)
-
ERC4626ExceededMaxDeposit(receiver, assets, max) -
ERC4626ExceededMaxMint(receiver, shares, max) -
ERC4626ExceededMaxWithdraw(owner, assets, max) -
ERC4626ExceededMaxRedeem(owner, shares, max) -
ERC7540InvalidOperator(controller, operator) -
ERC7540SyncDeposit() -
ERC7540AsyncDeposit() -
ERC7540SyncRedeem() -
ERC7540AsyncRedeem() -
ERC7540MissingAsync() -
ERC7540UnauthorizedMintSharesOnDepositFulfill() -
ERC7540UnauthorizedBurnSharesOnRedeemFulfill()
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
_isDepositAsync() → bool internal
Returns true if the deposit flow is asynchronous (Request-based). When false, deposit and
mint behave as standard synchronous ERC-4626 operations.
Override to return true in extensions that provide an async deposit fulfillment strategy.
_consumeClaimableDeposit(uint256, address) → uint256 internal
Consumes assets from the claimable deposit and returns the proportional shares (rounded down).
_consumeClaimableMint(uint256, address) → uint256 internal
Consumes shares from the claimable deposit and returns the proportional assets (rounded up).
_pendingDepositRequest(uint256, address) → uint256 internal
Returns the amount of assets in Pending state for controller with the given requestId.
_claimableDepositRequest(uint256, address) → uint256 internal
Returns the amount of assets in Claimable state for controller with the given requestId.
_asyncMaxDeposit(address) → uint256 internal
Returns the maximum assets that can be claimed via deposit for an async owner.
_asyncMaxMint(address) → uint256 internal
Returns the maximum shares that can be claimed via mint for an async owner.
ERC7540SyncRedeem
import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC7540SyncRedeem.sol";
Module for enabling synchronous behavior (ERC-4626) for the redeem flow of an ERC-7540 vault.
Note that an ERC-7540 vault is required to have at least one flow operating in asynchronous mode, so this module
cannot be combined with ERC7540SyncDeposit.
-
_isRedeemAsync() -
_consumeClaimableWithdraw(, ) -
_consumeClaimableRedeem(, ) -
_pendingRedeemRequest(, ) -
_claimableRedeemRequest(, ) -
_asyncMaxWithdraw() -
_asyncMaxRedeem()
-
supportsInterface(interfaceId) -
isOperator(controller, operator) -
setOperator(operator, approved) -
_setOperator(controller, operator, approved) -
_checkOperatorOrController(async, controller, operator) -
decimals() -
asset() -
share() -
vault(asset_) -
totalAssets() -
totalSupply() -
pendingDepositRequest(requestId, controller) -
claimableDepositRequest(requestId, controller) -
pendingRedeemRequest(requestId, controller) -
claimableRedeemRequest(requestId, controller) -
totalPendingDepositAssets() -
totalPendingRedeemShares() -
convertToShares(assets) -
convertToAssets(shares) -
maxDeposit(owner) -
maxMint(owner) -
maxWithdraw(owner) -
maxRedeem(owner) -
previewDeposit(assets) -
previewMint(shares) -
previewWithdraw(assets) -
previewRedeem(shares) -
requestDeposit(assets, controller, owner) -
deposit(assets, receiver) -
deposit(assets, receiver, controller) -
mint(shares, receiver) -
mint(shares, receiver, controller) -
requestRedeem(shares, controller, owner) -
withdraw(assets, receiver, ownerOrController) -
redeem(shares, receiver, ownerOrController) -
_convertToShares(assets, rounding) -
_convertToAssets(shares, rounding) -
_requestDeposit(assets, controller, owner, requestId) -
_mintSharesOnDepositFulfill(assets, shares) -
_deposit(callerOrController, receiver, assets, shares) -
_requestRedeem(shares, controller, owner, requestId) -
_burnSharesOnRedeemFulfill(, shares) -
_withdraw(caller, receiver, owner, assets, shares) -
_transferIn(from, assets) -
_transferOut(to, assets) -
_decimalsOffset() -
_depositShareOrigin() -
_redeemShareDestination() -
_isDepositAsync() -
_pendingDepositRequest(, ) -
_claimableDepositRequest(, ) -
_consumeClaimableDeposit(, ) -
_consumeClaimableMint(, ) -
_asyncMaxDeposit() -
_asyncMaxMint()
-
name() -
symbol() -
balanceOf(account) -
transfer(to, value) -
allowance(owner, spender) -
approve(spender, value) -
transferFrom(from, to, value) -
_transfer(from, to, value) -
_update(from, to, value) -
_mint(account, value) -
_burn(account, value) -
_approve(owner, spender, value) -
_approve(owner, spender, value, emitEvent) -
_spendAllowance(owner, spender, value)
-
Deposit(sender, owner, assets, shares) -
Withdraw(sender, receiver, owner, assets, shares)
-
Transfer(from, to, value) -
Approval(owner, spender, value)
-
RedeemRequest(controller, owner, requestId, sender, shares)
-
DepositRequest(controller, owner, requestId, sender, assets)
-
OperatorSet(controller, operator, approved)
-
ERC4626ExceededMaxDeposit(receiver, assets, max) -
ERC4626ExceededMaxMint(receiver, shares, max) -
ERC4626ExceededMaxWithdraw(owner, assets, max) -
ERC4626ExceededMaxRedeem(owner, shares, max) -
ERC7540InvalidOperator(controller, operator) -
ERC7540SyncDeposit() -
ERC7540AsyncDeposit() -
ERC7540SyncRedeem() -
ERC7540AsyncRedeem() -
ERC7540MissingAsync() -
ERC7540UnauthorizedMintSharesOnDepositFulfill() -
ERC7540UnauthorizedBurnSharesOnRedeemFulfill()
-
ERC20InsufficientBalance(sender, balance, needed) -
ERC20InvalidSender(sender) -
ERC20InvalidReceiver(receiver) -
ERC20InsufficientAllowance(spender, allowance, needed) -
ERC20InvalidApprover(approver) -
ERC20InvalidSpender(spender)
_isRedeemAsync() → bool internal
Returns true if the redeem flow is asynchronous (Request-based). When false, withdraw and
redeem behave as standard synchronous ERC-4626 operations.
Override to return true in extensions that provide an async redeem fulfillment strategy.
_consumeClaimableWithdraw(uint256, address) → uint256 internal
Consumes assets from the claimable redeem and returns the proportional shares (rounded up).
_consumeClaimableRedeem(uint256, address) → uint256 internal
Consumes shares from the claimable redeem and returns the proportional assets (rounded down).
_pendingRedeemRequest(uint256, address) → uint256 internal
Returns the amount of shares in Pending state for controller with the given requestId.
_claimableRedeemRequest(uint256, address) → uint256 internal
Returns the amount of shares in Claimable state for controller with the given requestId.
_asyncMaxWithdraw(address) → uint256 internal
Returns the maximum assets that can be claimed via withdraw for an async owner.
_asyncMaxRedeem(address) → uint256 internal
Returns the maximum shares that can be claimed via redeem for an async owner.