This page assumes you’ve read Base operations. Spoke chains hold no vault state — they proxy calls cross-chain to the hub on Base via LayerZero. The ERC-7540 request/claim pattern and the canonical function and event references are on the Base operations page.
VaultInterface, and the gotcha that trips up most partners (the controller parameter).
Upfront notes
- Cross-chain round trips typically settle in under a minute. No SLA. See Bridge operations for the latency discussion.
- The spoke
VaultInterfaceaddress differs per spoke (one on Avalanche, one on Katana). They are not the same contract. Look up the current addresses on the Contracts page; do not hard-code them from another source. - UTY vault mint (USDC → UTY) and redeem (UTY → USDC) are not available from a spoke. The UTY token itself bridges freely via OFT (see Bridge operations) — it’s only the vault operations against USDC that are Base-only.
Why UTY mint/redeem is Base-only
The UTY vault uses the
UTYAsyncVaultV1Custodian extension (introduced on Base operations): the custodian sweeps deposited USDC to an off-chain wallet and the vault tracks totalManagedAssets for the off-chain portion. USDC settlement runs through the custodian on Base — there’s no cross-chain equivalent. If you hold UTY on a spoke and want USDC, bridge UTY to Base first (see Bridge operations), then call UTY.requestRedeem on the hub.Deposit yUTY from a spoke
One user transaction initiates the flow; the protocol handles the hub-side deposit and the return hop.Approve UTY
UTY.approve(VAULT_INTERFACE, amount) on the spoke. The VaultInterface address is specific to the spoke.Deposit
VaultInterface.deposit(assets, receiver, controller) on the spoke. The three-arg form enforces _checkInputIsSender(controller) — controller must equal msg.sender. The two-arg form deposit(assets, receiver) is permissionless and is usually the right choice when a user is depositing for themselves.Flat deposit fee deducted
The
VaultInterface takes a flat deposit fee in UTY (see depositFlatFee() for the current value) and forwards the remaining UTY cross-chain.Hub composer completes the deposit
The hub
UTYVaultComposer receives the compose message, calls yUTY.deposit on the vault on the user’s behalf, and mints yUTY shares.yUTY shares bridge back to the spoke
The vault mints shares into the yUTY
ShareOFTAdapter lockbox, which emits a LayerZero message back to the originating spoke. On arrival, the spoke yUTY OFT mints the shares to the receiver address. Protocol pays this return-hop LZ fee from the hub Composer’s gas tank.GasTankDebited event on Base — that guid is the signal that the return-hop message has been paid for. The spoke yUTY OFT also emits an OFT receive event when the shares arrive. See Base operations event reference for the full correlation recipe.
Controller-safety warning
Withdraw yUTY from a spoke
yUTY spoke withdrawal is two user transactions — the protocol doesn’t round-trip a settlement message, so there’s no way to combine request and claim into a single tx. Between the two, the user (or their integration) watches hub state for settlement.Request (tx 1)
VaultInterface.requestRedeem(shares, controller, owner) on the spoke. Enforces _checkInputIsSender(owner) — owner must equal msg.sender. controller is arbitrary (that’s how Pattern 2 works: pass the user’s EOA so the user can claim from the spoke directly). A flat redeem fee is deducted from shares before bridging; see the fee guard below.Wait for hub settlement
No return message is sent. Partners watch on-hub state via indexer or Base RPC; the correlation recipe lives in the Base operations event reference — use the spoke
GasTankDebited.guid to match the hub RedeemRequest.Claim (tx 2)
VaultInterface.redeem(shares, receiver, controller) on the spoke. Enforces _checkInputIsSender(controller) — controller must equal msg.sender; no operator delegation on spokes. The claim sends a second cross-chain message; the hub composer calls redeemById on the vault using its COMPOSER_ROLE; UTY bridges back to the spoke to the receiver address. For yUTY the bonding period is 0, so this tx can run as soon as the hub confirms the request — typically within a minute of tx 1.Fee-underflow guard
The flat deposit fee and flat redeem fee are deducted from the amount before bridging. If the amount is less than or equal to the fee, the call reverts with
FeeExceedsAmount(fee, amount) — named fee and amount fields, easy to match on. Read redeemFlatFee() or depositFlatFee() to get the current fee and require strict inequality: shares > redeemFlatFee() for requestRedeem, assets > depositFlatFee() for deposit.Preview reads are hub-only
Spokes hold no vault state, so every read function that inspects vault accounting (previewRequestRedeem, convertToAssets, convertToShares, totalAssets, getBondingPeriod, getWithdrawalRequests(controller, offset, limit) — note the three-arg signature) is only callable on the hub vault on Base. Integrators previewing a redemption or reading withdrawal-request state must RPC against Base. The canonical function signatures and return shapes are on the Base operations function reference.
Spoke event reference
The spokeVaultInterface emits no per-request event. To correlate a spoke request to its hub-side settlement, use the cross-chain event correlation recipe in the Base operations event reference — the spoke’s GasTankDebited event carries the OFT message guid that ties the spoke-side transaction to the hub’s RedeemRequest (for withdrawal) or the hub composer’s GasTankDebited (for deposit return-hops).
Events emitted on the spoke:
| Event | When it fires |
|---|---|
FeeCollected(token, amount) | Flat fee taken on a deposit or redeem request |
FeesWithdrawn(token, recipient, amount) | Operations sweeps accumulated fees |
FlatFeeUpdated(feeType, oldValue, newValue) | Fee parameter change |
GasTankFunded(remainingBalance) | Native token sent to the spoke interface |
GasTankDebited(guid, operationType, remainingBalance) | Each outbound LayerZero message from the spoke — the correlation key for cross-chain tracing |
GasTokensRecovered(to, amount, remainingBalance) | Operations withdraws excess native from the gas tank |
Cross-chain withdrawal flow
The diagram below traces a yUTY withdrawal initiated on a spoke. The gap in the middle marks the asynchronous boundary: after tx 1 returns, the protocol does not send a settlement message back — partners watch hub state (via indexer or Base RPC) and initiate tx 2 when they see the hub’sRedeemRequest event. For yUTY the bonding period is 0, so tx 2 can run as soon as the hub-side request confirms.
Figure: yUTY withdrawal from a spoke chain. Two user transactions bracket an indexer-watched gap. The protocol pays the return-hop gas (tx 2) from the hub Composer’s gas tank on Base.