Base is the hub. All vault state lives here: shares, withdrawal requests, bonding timers, exchange rates. This page covers the flows an integrator on Base touches directly. For cross-chain flows that originate on Avalanche or Katana, see Spoke chain operations.Documentation Index
Fetch the complete documentation index at: https://docs.yieldpoint.io/llms.txt
Use this file to discover all available pages before exploring further.
Upfront notes
- UTY vault mint (USDC → UTY) and redeem (UTY → USDC) run only on Base. The underlying USDC custody lives here; there is no cross-chain route to USDC. To exit UTY from a spoke, bridge UTY to Base first (see Bridge operations), then redeem.
- Every deposit and redemption request requires a prior ERC-20
approveon the underlying token granting the vault allowance. - Bonding periods are configurable vault state, not protocol constants. Call
getBondingPeriod()on each vault as the authoritative source; at the time of writing, yUTY returns0(claims available the same block as the request) and UTY returns7 days. Integrators building bonding-aware logic should read the function, not hard-code the value.
Deposit USDC into the UTY vault
UTY is USDC-backed at a strict 1:1 peg. You deposit USDC; the vault mints UTY 1:1; USDC is swept to the custodian wallet by the vault’s extension logic.Common failure. If the deposit amount underflows the vault’s internal accounting, the call reverts with
FeeExceedsAmount(fee, amount). See Gotchas.Deposit UTY into the yUTY vault
yUTY is an ERC-4626-style yield-bearing vault over UTY. The exchange rate is not 1:1 — the mainnet yUTY vault has received donations, sototalAssets() != totalSupply(). Use convertToAssets(shares) and convertToShares(assets) to convert accurately; don’t assume a 1:1 relationship.
Withdraw from yUTY
yUTY uses the ERC-7540 async request-and-claim pattern. The bonding period is currently0, so the claim is available in the same block as the request — but the call sequence is still two steps.
Request
yUTY.requestRedeem(shares, controller, owner) — burns shares, creates a WithdrawalRequest, and returns a requestId. controller is the address authorized to claim; owner must be msg.sender or an approved operator.Claim (same block, since bondingPeriod == 0)
yUTY.redeemById(requestId, receiver) — transfers the underlying UTY to receiver. Call this in the next transaction once the request confirms, or in the same transaction if your integration batches both calls. To drain multiple matured requests in a single call, see Hub claim paths for the redeem and withdraw alternatives.Common failure. If
msg.sender isn’t the controller and isn’t approved via setOperator on the hub, the claim reverts with InvalidRequest() — an overloaded error that also surfaces when the request doesn’t exist or was already claimed. See Gotchas for the debugging recipe.Withdraw from UTY
UTY redemption (UTY → USDC) runs through the same ERC-7540 pattern but the bonding period is 7 days. The spoke doesn’t gate the claim client-side — if you claim before the bonding period elapses, the hub rejects (with a different revert name per claim path; see the Common-failure note below). Checkrequest.unlockTime against block.timestamp before claiming.
Approve UTY
UTY.approve(UTY_VAULT, amount) on Base (required even for redemption because the vault transfers shares internally).Request
UTY.requestRedeem(shares, controller, owner) — burns UTY shares, creates a WithdrawalRequest with unlockTime = block.timestamp + getBondingPeriod().Wait for bonding
7 days at current configuration. Read
getBondingPeriod() for the authoritative value.Claim
UTY.redeemById(requestId, receiver) — transfers USDC to receiver. To drain multiple matured requests in a single call, see Hub claim paths for the redeem and withdraw alternatives.Common failure. Premature claim revert names differ per path:
redeemByIdreverts withBondingPeriodNotOver().redeemreverts withERC4626ExceededMaxRedeem(controller, shares, maxShares)becausemaxRedeem(controller)returns0during bonding.withdrawreverts withERC4626ExceededMaxWithdraw(controller, assets, maxAssets)becausemaxWithdraw(controller)returns0during bonding.
request.unlockTime against block.timestamp before claiming on any path. See Gotchas.Hub claim paths
The hub vault exposes three claim functions. All three require the bonding period to have elapsed and apply the same controller-or-operator authorization rules described above. They differ in how they select which request or requests to consume.| Function | Denomination | Targets | Partial-drain | When to use |
|---|---|---|---|---|
redeemById(requestId, receiver) | full request | one specific request by ID | no — closes the entire request | Per-request accounting where the caller tracks individual request IDs |
redeem(shares, receiver, controller) | shares | consumes the controller’s matured requests in storage order until the requested share total is fulfilled | yes — partially consumes the trailing request when the share total runs out mid-request | Aggregate claim across multiple matured requests in a single call, sized in shares |
withdraw(assets, receiver, controller) | assets | consumes the controller’s matured requests in storage order until the requested asset total is fulfilled | yes — partially consumes the trailing request when the asset total runs out mid-request | Aggregate claim across multiple matured requests in a single call, sized in assets |
redeemandwithdrawskip non-matured requests in the loop, so a single call cleanly handles a queue that mixes matured and bonding requests.- All three paths are hub-only. None are exposed on the spoke
UTYVaultInterface— see Spoke claim constraints. - Partners doing per-request accounting (gauges, vault-of-vaults, anything that tracks individual request IDs) should use
redeemById. It is the only path with a stable caller-controlled request identity. Iteration order across multiple matured requests inredeemandwithdrawis implementation-defined and must not be relied on for accounting.
Function reference
UTY hub vault
| Function | Purpose | Who can call it | Returns |
|---|---|---|---|
deposit(assets, receiver) | Mint UTY at 1:1 to receiver | Anyone (after USDC approve) | uint256 shares |
requestRedeem(shares, controller, owner) | Open a UTY → USDC redemption request | owner (or operator) | uint256 requestId |
redeemById(requestId, receiver) | Claim a settled redemption | controller of the request (or operator) | uint256 assets |
redeem(shares, receiver, controller) | Claim across the controller’s matured requests in storage order | controller (or operator) | uint256 assets |
withdraw(assets, receiver, controller) | Claim a target asset amount across the controller’s matured requests in storage order | controller (or operator) | uint256 shares |
previewRequestRedeem(shares) | Expected USDC output for a given share burn | Anyone (view) | uint256 assets |
getBondingPeriod() | Current bonding period in seconds | Anyone (view) | uint256 |
getWithdrawalRequests(controller, offset, limit) | Paginated list of a controller’s pending requests | Anyone (view) | WithdrawalRequest[] |
claimableRedeemRequest(requestId, controller) | Claimable shares for a specific request | Anyone (view) | uint256 shares |
convertToAssets(shares) / convertToShares(assets) | Exchange-rate conversions | Anyone (view) | uint256 |
totalAssets() / totalSupply() | Vault state | Anyone (view) | uint256 |
maxRedeem(controller) | Maximum claimable shares right now | Anyone (view) | uint256 |
yUTY hub vault
| Function | Purpose | Who can call it | Returns |
|---|---|---|---|
deposit(assets, receiver) | Mint yUTY shares from UTY (ERC-4626) | Anyone (after UTY approve) | uint256 shares |
requestRedeem(shares, controller, owner) | Open a yUTY → UTY redemption request | owner (or operator) | uint256 requestId |
redeemById(requestId, receiver) | Claim a settled redemption | controller (or operator) | uint256 assets |
redeem(shares, receiver, controller) | Claim across the controller’s matured requests in storage order | controller (or operator) | uint256 assets |
withdraw(assets, receiver, controller) | Claim a target asset amount across the controller’s matured requests in storage order | controller (or operator) | uint256 shares |
previewRequestRedeem(shares) | Expected UTY output for a given share burn | Anyone (view) | uint256 assets |
getBondingPeriod() | Current bonding period in seconds (currently 0) | Anyone (view) | uint256 |
getWithdrawalRequests(controller, offset, limit) | Paginated list of pending requests | Anyone (view) | WithdrawalRequest[] |
setOperator(operator, approved) | Delegate claim authority over your own requests | Anyone — delegates msg.sender’s own requests only | bool |
isOperator(controller, operator) | Check operator approval | Anyone (view) | bool |
The WithdrawalRequest struct
Event reference
This section is the canonical home for the cross-chain event correlation recipe. The Bridge operations and Spoke chain operations pages link here rather than re-derive it.Hub vault (UTYAsyncVaultV1, on Base)
| Event | When it fires | Key fields |
|---|---|---|
Deposit(sender, owner, assets, shares) | On deposit() | Standard ERC-4626 |
Withdraw(sender, receiver, owner, assets, shares) | On any hub claim (redeemById, redeem, or withdraw) — fires once per call with aggregated assets and shares | Standard ERC-4626 |
RedeemRequest(controller, owner, requestId, sender, assets) | On requestRedeem() | requestId, controller |
RequestClosed(requestId, controller, receiver, assets) | Once per fully-closed request — always once per redeemById; fires 0..N times per redeem or withdraw call (only on full-drain branches; the trailing partial-drain request emits no RequestClosed) | requestId |
Donation(from, assets) | On donate() (yUTY only; UTY donate() reverts) | Increases yUTY share price |
Hub composer (UTYVaultComposer, on Base)
| Event | When it fires | Key fields |
|---|---|---|
RedeemRequested(...) | On spoke-originated redemption requests after lzCompose | OFT message guid |
GasTankDebited(guid, operationType, remainingBalance) | Each outbound LayerZero message from the hub to a spoke | guid (the correlation key) |
GasTankFunded(remainingBalance) | Native token sent to the Composer | — |
RefundPending(id, token, amount, receiver) | A cross-chain action couldn’t complete; retriable | id for retryRefund(id) |
RefundCompleted(id) | Refund retry succeeded | — |
Spoke VaultInterface (UTYVaultInterface, on each spoke — included here for correlation)
The spoke emits no per-request event. Partner indexers watching for the on-spoke handle on a cross-chain request use GasTankDebited’s guid field as the correlation key.
| Event | When it fires |
|---|---|
FeeCollected(token, amount) | Flat fee taken on deposit or redeem request |
FeesWithdrawn(token, recipient, amount) | Operations sweeps accumulated fees |
FlatFeeUpdated(feeType, oldValue, newValue) | Fee parameter change (timelocked) |
GasTankFunded(remainingBalance) | Native token sent to the spoke interface |
GasTankDebited(guid, operationType, remainingBalance) | Each outbound LayerZero message from the spoke to the hub |
GasTokensRecovered(to, amount, remainingBalance) | Operations withdraws excess native from the gas tank |
Correlation recipe
For a cross-chain flow initiated on a spoke, match the spoke’sGasTankDebited.guid to the corresponding hub event:
- Withdrawal request (spoke → hub): spoke
GasTankDebited.guid→ hub vaultRedeemRequest(theguidappears in the hub composer’sRedeemRequestedevent, which is emitted immediately before the vault’sRedeemRequest). - Deposit return-hop (hub → spoke): watch the hub composer’s
GasTankDebited.guidas the signal that the deposit’s return message has been paid for by the protocol’s hub gas tank. - Claim return-hop (hub → spoke): watch the spoke
VaultInterface’sGasTankDebited.guidfor the claim-phase return trip.
https://layerzeroscan.com/tx/<txhash> — the message may be queued pending a gas-tank refill. See Gotchas: InsufficientFunds.
Why donate() reverts on UTY but works on yUTY
The UTY vault overrides
donate() to revert. UTY maintains a strict 1:1 peg with USDC — a donation would inflate the share price and break the peg. The yUTY vault allows donate(); that’s the mechanism by which yield is distributed to yUTY holders (the per-share price increases).