Skip to main content

OllaVault

What is OllaVault?

OllaVault is the user-facing entry point to the Olla protocol. It holds Aztec tokens, mints and burns stAztec shares, and tracks all async withdrawal requests in its own storage. It implements ERC-4626 (tokenized vault), ERC-7540 (async redemptions), and ERC-7575 (share/asset separation).

Pricing is delegated to OllaCore (exchange rate, totalAssets, withdrawalRate); share-token operations are delegated to StAztec.

Key responsibilities:

  • Accepting deposits and minting stAztec via StAztec.
  • Holding the buffer of unbonded Aztec tokens (bufferedAssets).
  • Tracking redemption requests in FIFO order and finalising them when liquidity is available.
  • Adjusting payouts down on request finalization if a slashing event reduced the rate after the request was made.
  • Executing OllaCore instructions during rebalance (transferring assets out, receiving unstaked funds, finalizing withdrawals, minting fee shares).

OllaVault is upgradeable via UUPS proxy. Its owner() (Ownable2Step) and DEFAULT_ADMIN_ROLE are both held by OllaGovernance. CORE_ROLE is held by OllaCore.

Deposits

Users deposit Aztec tokens and receive stAztec at the current exchange rate. Deposits land in the buffer and are staked on the rollup during the next rebalance.

Three variants:

  • deposit(assets, receiver, minSharesOut): standard deposit with slippage protection.
  • mint(shares, receiver, maxAssetsIn): deposit by exact share amount with slippage protection.
  • depositWithPermit(...): gasless approval via ERC-2612 permit. Includes frontrun protection: if the permit fails but sufficient allowance already exists, the deposit proceeds.

The plain ERC-4626 overloads deposit(assets, receiver) and mint(shares, receiver) exist for compatibility but have no slippage protection. Integrators should prefer the 3-arg variants.

Deposits are blocked when OllaVault is paused, when the SafetyModule is paused or has triggered, or when the deposit cap would be exceeded. A minimum-share check (SafetyModule.checkWithdrawalMinimum) is also enforced on entry, so a depositor cannot land in a state too small to redeem.

Withdrawals

All redemptions are asynchronous:

  1. requestRedeem(shares, controller, owner): burns stAztec, locks the per-request rate at OllaCore.withdrawalRate(), and enqueues a withdrawal request. controller is the address that can claim it; owner is the address whose shares are pulled. ERC-20 share allowance is a valid authorization path: if msg.sender != owner and is not an approved operator, the contract pulls shares via safeTransferFrom (the allowance check is the authorization).
  2. Wait for a rebalance cycle to finalize the request. Anyone can advance rebalance.
  3. claimRequestById(requestId): claim Aztec tokens. Payout may have been adjusted down at finalization if slashing occurred between request and finalization.

Two convenience variants are provided:

  • requestRedeemWithPermit(shares, controller, deadline, v, r, s): uses ERC-2612 permit to grant the share allowance in one tx. The permit variant always treats msg.sender as the owner; for operator-mediated redemptions on behalf of someone else, use the non-permit requestRedeem with setOperator (ERC-7540).
  • redeem(shares, receiver, controller): ERC-7540 redeem. Keeps the ERC-4626 signature but uses asynchronous semantics: it looks up a finalized request matching the given share amount for controller and claims it. Reverts if no matching finalized request exists. Prefer claimRequestById(requestId) when you control the integration; the ERC-7540 alias is provided for tooling that follows the ERC-4626/7540 surface.

Slashing-aware payout: at finalize time, if the per-request locked rate is higher than the current rate by more than 1 wei, the payout is reduced to shares * currentRate / 1e18. Zero-payout requests still finalize so the queue can advance.

See User Actions for sequence diagrams.

Methods

User

deposit()

Deposit Aztec tokens with slippage protection.

function deposit(uint256 assets, address recipient, uint256 minSharesOut) external returns (uint256 shares)

Plain ERC-4626 overload deposit(uint256 assets, address receiver) is also available but skips the minSharesOut check.

mint()

Mint an exact share amount with slippage protection.

function mint(uint256 shares, address receiver, uint256 maxAssetsIn) external returns (uint256 assets)

Plain ERC-4626 overload mint(uint256 shares, address receiver) is also available but skips the maxAssetsIn check.

depositWithPermit()

Deposit with gasless ERC-2612 approval and slippage protection.

function depositWithPermit(uint256 assets, address recipient, uint256 minSharesOut, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external returns (uint256 shares)

requestRedeem()

Enqueue a withdrawal request. Burns stAztec immediately and locks the per-request rate.

function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId)

requestRedeemWithPermit()

Same as requestRedeem but uses an ERC-2612 permit to grant the share allowance. Always treats msg.sender as the owner.

function requestRedeemWithPermit(uint256 shares, address controller, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external returns (uint256 requestId)

claimRequestById()

Claim a finalized withdrawal request by id. Preferred entry point.

function claimRequestById(uint256 requestId) external returns (uint256 assets)

redeem()

ERC-7540 redeem. The signature matches ERC-4626 but the semantics are asynchronous: it looks up a finalized request matching shares for controller and claims it. Reverts if no matching finalized request exists.

function redeem(uint256 shares, address receiver, address controller) external returns (uint256 assets)

setOperator()

Approve or revoke an operator to act on the caller's behalf for redemption requests (ERC-7540).

function setOperator(address operator, bool approved) external returns (bool)

Guardian

Requires GUARDIAN_ROLE (granted to OllaGovernance at init; expected to also be granted to a guardian multisig).

pause() / unpause()

Pause and resume vault operations.

function pause() external
function unpause() external

Core (CORE_ROLE)

These are called by OllaCore during rebalance. They are not user-facing.

function transferToCore(uint256 amount) external
function receiveUnstaked(uint256 amount) external
function finalizeWithdrawals(uint256 availableAssets, uint256 currentRate, uint256 maxRequestId) external returns (uint256 finalizedAmount, uint256 finalizedCount)
function mintFees(address treasury, uint256 treasuryShares, address provider, uint256 providerShares) external

Governance

Restricted to the OllaGovernance contract via Ownable2Step (onlyOwner). All such calls land here through the timelock. See OllaGovernance for the wrappers.

reconcileBufferedAssets()

Sync bufferedAssets with the actual token balance, absorbing any positive delta (e.g. donations sent directly to the vault).

function reconcileBufferedAssets() external returns (uint256 delta)

recoverStAztec()

Recover stAztec tokens accidentally sent to the vault. If recipient == address(0), sends to the OllaGovernance treasury.

function recoverStAztec(address recipient, uint256 amount) external

The vault has no fee setter and no SafetyModule setter of its own. The SafetyModule reference is read live from OllaCore, which exposes setSafetyModule. The finalization gas budget is an internal constant.

View methods

bufferedAssets()

Aztec tokens currently in the buffer.

pendingWithdrawalAssets()

Total assets currently outstanding across unfinalized requests.

pendingWithdrawalShares()

Total shares burned but not yet finalized.

cumulativeDeposits() / cumulativeWithdrawals() / cumulativeSlashingAdjustments()

Flow counters used by Core for accounting.

nextWithdrawalRequestId()

Id that will be assigned to the next new request.

nextUnfinalizedWithdrawalRequestId()

Head of the FIFO queue (first id eligible for finalization).

getWithdrawalRequest(id)

Full struct for a request (finalized, shares, assetsExpected, rate).

requestOwner(id)

Recorded controller for a request id.

activeRequestIds(owner)

All request ids tracked for an owner.

pendingRedeemRequest(requestId, controller)

Pending shares for a request (zero once finalized).

claimableRedeemRequest(requestId, controller)

Claimable shares for a request (non-zero once finalized).

maxRedeem(controller)

Total claimable shares across all finalized requests for a controller (0 if paused).

maxDeposit(account)

Max depositable under the SafetyModule deposit cap (0 if paused or cap reached).

maxMint(account)

Max mintable equivalent of maxDeposit.

previewDeposit(assets) / previewMint(shares)

Share/asset previews via OllaCore.

convertToShares(assets) / convertToAssets(shares)

Conversions delegated to OllaCore.

totalAssets()

Proxies to OllaCore.totalAssets().

asset() / share()

Underlying asset / share token addresses (ERC-7575).

core() / safetyModule()

Module references. The SafetyModule address is read live from OllaCore.

isOperator(controller, operator)

Operator approval state (ERC-7540).

previewWithdraw, previewRedeem and withdraw always revert. They are not supported in the async vault model. maxWithdraw always returns 0.

Events

event Deposit(address indexed caller, address indexed recipient, uint256 assets, uint256 shares)
event WithdrawalRequested(uint256 indexed requestId, address indexed controller, uint256 shares, uint256 assetsExpected, uint256 rate)
event RedeemRequest(address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 shares)
event WithdrawalRequestFinalized(uint256 indexed requestId, uint256 assets)
event WithdrawalAdjusted(uint256 indexed requestId, uint256 originalAmount, uint256 adjustedAmount)
event WithdrawalFinalized(uint256 available, uint256 used)
event WithdrawalClaimed(uint256 indexed requestId, address indexed recipient, uint256 assets)
event OperatorSet(address indexed controller, address indexed operator, bool approved)
event AssetsTransferredToStaking(uint256 amount)
event UnstakedAssetsReceived(uint256 amount)
event FeesMinted(uint256 treasuryShares, uint256 providerShares)
event BufferedAssetsReconciled(uint256 delta, uint256 newBufferedAssets, address indexed recipient)
event StAztecRecovered(uint256 amount, address indexed recipient)