Synchronous flow
Deposit and redeem in a single transaction when the curator enables it, with the conditions, balance changes and gotchas of each.
When the curator enables it, a vault can skip the epoch cycle of the async flow: syncDeposit mints shares and syncRedeem pays out assets in the same transaction, priced at the current totalAssets / totalSupply. This page describes v0.6.0; where v0.5.x behaves differently, a tab shows both.
When sync is available
A sync call needs all three conditions. Read them live: the curator can change the mode and the valuation expires over time.
Vault open
—
Open
Open
Only deposits can be synchronous: there is no sync mode and no sync redeem. A sync deposit needs the vault to be Open and the valuation to be valid: while isTotalAssetsValid() is true deposits must be synchronous, and once it expires they must be asynchronous.
Sync deposit
Underlying asset
approve(vault, amount)
none
Vault
Asset: user → curator address (safe()). Shares minted to receiver (Transfer from address(0))
Vault
Same, with native value (msg.value != 0)
Native balance leaves the user with no ERC-20 Transfer. The pendingSilo wraps it and forwards it: Transfer pendingSilo → curator address. Shares minted to receiver
Reverts when
Sync mode does not allow sync deposits
SyncOperationNotAllowed
Valuation expired
TotalAssetsExpired
Vault not Open
NotOpen(state)
msg.sender or receiver fails isAllowed (not whitelisted, blacklisted or sanctioned)
AddressNotAllowed
totalAssets() + pending deposits (underlying held by the pendingSilo) + assets > maxCap()
MaxCapReached
Native value sent but the underlying is not the wrapped native token
CantDepositNativeToken
Vault paused
EnforcedPause
Notes
Pass
address(0)asreferralwhen there is none. The call always emits aReferralevent.An entry fee (
feeRates().entryRate, in bps) is taken in shares.previewSyncDeposit(assets)returns the net shares.There is no slippage parameter. The price is the current valuation, and the valuation lifespan is the protection against a stale price.
With native value,
assetsis ignored and replaced bymsg.value, and no approval is needed.
Reverts when
Valuation expired: use requestDeposit
OnlyAsyncDepositAllowed
Vault not Open
NotOpen(state)
Whitelist enabled and an involved address not whitelisted
NotWhitelisted
Native value sent but the underlying is not the wrapped native token
CantDepositNativeToken
Vault paused
EnforcedPause
Notes
Pass
address(0)asreferralwhen there is none. The call always emits aReferralevent.There is no entry fee and no deposit cap.
There is no slippage parameter. The price is the current valuation, and the valuation lifespan is the protection against a stale price.
With native value,
assetsis ignored and replaced bymsg.value, and no approval is needed.
Sync redeem
Vault
Shares of the caller burnt (Transfer to address(0)). Asset: curator address → receiver
Reverts when
Sync mode does not allow sync redeems
SyncOperationNotAllowed
Valuation expired
TotalAssetsExpired
Vault not Open
NotOpen(state)
msg.sender or receiver fails isAllowed (not whitelisted, blacklisted or sanctioned)
AddressNotAllowed
receiver is address(0)
InvalidReceiver
Net assets below minimumAssets
BelowMinimumAssets(assets, minimumAssets)
Curator address balance or allowance to the vault too low
Underlying token's transfer error
Vault paused
EnforcedPause
Notes
The shares are always the caller's own: there is no
ownerorcontrollerargument.Two fees apply: the exit fee, then a haircut (
haircutRate, 0 to 20%) on the remaining shares. When the haircut is above 0, a sync redeem costs more than an async one.previewSyncRedeem(shares)returns the net assets.Use
minimumAssetsas a slippage guard, e.g. thepreviewSyncRedeemresult: it protects against a haircut or fee change between the preview and the execution.A
HaircutTakenevent is emitted when a haircut applies.
Choosing the deposit path with viem
The vault state has no on-chain getter, so these snippets assume an Open vault. Read state from the Lagoon API and only deposit when it is Open.
Choosing the deposit path with the Lagoon API
The Lagoon API returns the same inputs in one query. On v0.5.x vaults it reports syncMode as Both and totalAssetsExpiration as 0 even while the valuation is valid, so for them read isTotalAssetsValid() on-chain, as in the v0.5.x tab above. Send it to https://api.lagoon.finance/query:
version
Implementation version, e.g. v0.6.0
version()
syncMode
Both, SyncDeposit, SyncRedeem or None
syncMode()
totalAssetsExpiration
Unix timestamp after which the valuation is stale. 0 on v0.5.x vaults
isTotalAssetsValid() is true while it is in the future
state
Open, Closing or Closed
—
Checking a sync redeem with the Lagoon API
syncRedeem only exists from v0.6.0, and the API reports syncMode as Both for v0.5.x vaults, so check version as well. The query also returns the curator address's balance of the underlying. Its allowance to the vault and the net output are not in the API: read them on-chain.
version
Implementation version, e.g. v0.6.0
version()
syncMode
Both, SyncDeposit, SyncRedeem or None
syncMode()
totalAssetsExpiration
Unix timestamp after which the valuation is stale
isTotalAssetsValid() is true while it is in the future
state
Open, Closing or Closed
—
safeAssetBalance
Underlying held by the curator address, in asset units
asset.balanceOf(safe)
roles.safe
Curator address
safe()
When canSyncRedeem is false or the curator address cannot cover assetsOut, fall back to the async redemption with claimSharesAndRequestRedeem(shares) while the vault is Open. Redemption requests revert with NotOpen once the vault is Closing; once it is Closed, exit with redeem as in Exit a closed vault.
Last updated