Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/developers/addresses/yvusd-contracts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# yvUSD Contract Addresses

## yvUSD domain (Ethereum mainnet)

| Name | Chain | Address |
| --- | --- | --- |
| yvUSD vault | Ethereum | [`0x696d02Db93291651ED510704c9b286841d506987`](https://etherscan.io/address/0x696d02Db93291651ED510704c9b286841d506987) |
| LockedyvUSD | Ethereum | [`0xAaaFEa48472f77563961Cdb53291DEDfB46F9040`](https://etherscan.io/address/0xAaaFEa48472f77563961Cdb53291DEDfB46F9040) |
| APR oracle | Ethereum | [`0x1981AD9F44F2EA9aDd2dC4AD7D075c102C70aF92`](https://etherscan.io/address/0x1981AD9F44F2EA9aDd2dC4AD7D075c102C70aF92) |
| Fee splitter | Ethereum | [`0xd744B7D6bE69b334766802245Db2895e861cb470`](https://etherscan.io/address/0xd744B7D6bE69b334766802245Db2895e861cb470) |
49 changes: 49 additions & 0 deletions docs/developers/yvusd/apr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# yvUSD APR (Oracle + APR Service)

yvUSD APR is derived from a mix of onchain data (vault/strategy accounting and APR-oracle reads) and an offchain service that periodically computes and caches results for fast frontend access.

## Sources Of Truth

- **Vault/strategy accounting** is onchain (ERC-4626 `totalAssets`, `totalSupply`, strategy debt allocations, fee config)
- **APR oracle** is onchain and provides strategy-level APR estimation
- **APR service** aggregates these inputs into a debt-weighted vault APR and exposes it via a cached API

## Onchain APR Oracle

The APR service is configured to read an onchain APR oracle address. This oracle is used to fetch strategy APRs and to compute derivatives like LockedyvUSD's locker bonus APR.

## APR Service (Offchain)

The yvUSD APR API:

- Indexes strategy membership from onchain events.
- Hydrates onchain metadata for strategies and vaults.
- Computes a **debt-weighted** APR for each configured vault.

The service is designed so frontends can read APR data without performing expensive onchain reads on every request.

### API Routes

[The API](https://github.com/yearn/yearn-yvusd-apr-service) exposes routes like:

- `GET /api/health`: Health and data freshness.
- `GET /api/sync`: run a full sync + recompute cycle (typically triggered by cron).
- `GET /api/aprs`: return precomputed APR results.
- `GET /api/aprs/<address>`: APR for a single vault address.
- `GET /api/snapshot`: raw indexed strategy cache.

## Data Freshness

APR outputs can be stale if:

- The sync job has not run recently.
- One of the configured RPC endpoints is degraded.
- A particular strategy type requires an offchain calculator that fails or is temporarily disabled.

In these cases, vault operations (deposit/withdraw/report) continue unaffected; only the rate display is impacted.

## Links

<PrettyLink>[yvUSD developer docs index](/developers/yvusd)</PrettyLink>

<PrettyLink>[yvUSD contract addresses](/developers/addresses/yvusd-contracts)</PrettyLink>
166 changes: 166 additions & 0 deletions docs/developers/yvusd/cross-chain-strategies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# Cross-Chain Strategies

yvUSD deploys capital cross-chain through a pair of contracts: an **origin strategy** on Ethereum mainnet and a **remote strategy** on the destination chain. Two remote strategy implementations exist: a standard ERC-4626 variant (`CCTPRemoteStrategy`) and a HyperLiquid HLP variant (`HyperRemoteStrategy`).

## Architecture

![Cross-chain USDC deployment flow](/img/diagrams/yvusd/cross-chain.png)

### Origin strategy (`CCTPStrategy`)

`CCTPStrategy` is a standard Yearn V3 tokenized strategy deployed on Ethereum mainnet. It:

- Bridges USDC to the remote chain via Circle CCTP (`depositForBurn`)
- Tracks remote capital in a `remoteAssets` storage variable
- Receives accounting updates from the remote strategy via incoming CCTP messages (`handleReceiveFinalizedMessage`)
- Restricts deposits to a single `DEPOSITER` address (typically the yvUSD vault)
- Only exposes local USDC balance as immediately withdrawable — remote assets must be bridged back with a delay before they can be withdrawn

> **Withdrawal availability vs. total accounting**
>
> Only `balanceOfAsset()`, the amount of local USDC on mainnet, is immediately withdrawable from yvUSD. Remote capital on other chains is included in yvUSD's `totalAssets()` value, but must be bridged back before it can be redeemed.

## Discovering Destinations (Onchain)

The yvUSD vault does not store a list of destination-chain addresses. Instead, yvUSD allocates to **origin-chain strategies**, and each cross-chain strategy contains its own destination configuration as queryable public immutables.

Not all yvUSD strategies are cross-chain. The vault can also hold mainnet-only strategies (for example, Morpho-based looper strategies that deploy capital without bridging). Cross-chain strategies can be identified because a set of `REMOTE_*` public immutables that mainnet strategies do not have (and usually the strategy name on mainnet is CCTPStrategy).

To learn "where yvUSD is sending assets", you:

1. Enumerate the strategy addresses used by the yvUSD vault on Ethereum.
2. For each strategy, determine whether it is a cross-chain strategy.
3. For cross-chain strategies, read the destination configuration (`REMOTE_*` immutables).
4. (Optional) On the destination chain, read the remote strategy to learn where it deploys funds (for example, the target ERC-4626 vault).

### 1) Enumerate Origin Strategy Addresses

Onchain, the vault can only expose *arrays* of strategies via limited mechanisms (for example, the withdrawal `default_queue`, max length 10). For a complete and always-up-to-date list, you typically need to index events offchain.

Practical options:

- **Quick view (onchain call):** `VaultV3.get_default_queue()` returns the current default withdrawal queue (max 10 strategies).
- **Canonical list (offchain indexing):** index strategy add/remove events for the vault (or related periphery like a Debt Allocator / Role Manager) and maintain the active set.
- **Periphery:** if you have access to a Yearn Registry / Role Manager for the chain, use those helpers to retrieve vault/strategy configuration.

### 2) Identify Whether A Strategy Is Cross-Chain

Call `REMOTE_CHAIN_ID()` on the strategy contract. Cross-chain strategies (`CCTPStrategy`) expose this as a public immutable returning the destination EVM chain ID. Mainnet-only strategies do not implement this function and the call will revert.

A non-zero return value confirms the strategy is cross-chain and bridges assets to another chain. A revert (or a return value of `0`) indicates a mainnet-only strategy.

As a secondary check, `REMOTE_COUNTERPART()` returns the address of the paired remote strategy contract. A non-zero address further confirms the strategy is cross-chain.

### 3) Read Destination Configuration From The Strategy

For cross-chain strategies (origin side), the key queryable fields are:

- `REMOTE_ID()` (CCTP domain encoded as `bytes32`)
- `REMOTE_CHAIN_ID()` (EVM chain id)
- `REMOTE_COUNTERPART()` (remote strategy contract address on the destination chain)
- `DEPOSITER()` (address allowed to deposit into the strategy; typically the yvUSD vault)

This is the source of truth for where the origin strategy bridges to.

### 4) Read The Remote Strategy’s Deployment Target (Optional)

For the standard remote implementation (`CCTPRemoteStrategy`), the remote strategy deploys into an ERC-4626 vault that is stored as an immutable `vault` (see `BaseRemote4626`).

## Remote strategy (standard: `CCTPRemoteStrategy`)

Deployed on the destination chain. It:

- Receives USDC from the origin via CCTP and deposits it into a target ERC-4626 vault
- Reports total assets back to the origin by sending a CCTP *message* (no token transfer)
- Processes withdrawal requests by redeeming from the vault, bridging USDC back via CCTP, and sending an updated accounting message

## Accounting model

`remoteAssets` on the origin strategy on mainnet is updated in two situations:

1. **Outbound bridge** (`_deployFunds`): incremented immediately when USDC is bridged out
2. **Inbound message** (`handleReceiveFinalizedMessage`): overwritten with the value sent by the remote strategy's `report()` or `processWithdrawal()`

Because the inbound update depends on a CCTP message relay, `remoteAssets` can be stale between keeper cycles. A report or withdrawal from the remote always sends a fresh accounting message to resync.

## Keeper Operations

### Remote strategy keepers

| Function | Description |
|---|---|
| `report()` | Computes `totalAssets`, bridges the value as a CCTP message to the origin |
| `processWithdrawal(amount)` | Withdraws `amount` from the vault, bridges USDC back to origin, sends accounting message |
| `tend()` | Pushes idle local USDC into the vault |

### Origin strategy keepers

The origin strategy itself is a standard Yearn V3 tokenized strategy — its `report()` triggers the vault's normal accounting. The vault's debt allocator controls how much is allocated to each cross-chain strategy.

## Deployment

Origin and remote strategy addresses are pre-computed so each side can be configured with the other's address before either is deployed.

- **Origin** (`StrategyFactory.newStrategy()`): deployed with CREATE, nonce-based address prediction
- **Remote** (`RemoteStrategyFactory.deployRemoteStrategy()`): deployed with CREATE3, deterministic salt of `keccak256(vault, remoteDomain, remoteCounterpart)`

The factories are deployed at the same address on every chain.

---

## HyperLiquid HLP Variant

The HyperLiquid strategy uses the same origin-side `CCTPStrategy` on Ethereum mainnet, but replaces `CCTPRemoteStrategy` with `HyperRemoteStrategy` on HyperEVM. Instead of depositing into an ERC-4626 vault, capital is deployed into HyperCore's **HLP (HyperLiquidity Provider) vault**, which earns yield by providing liquidity to HyperLiquid's perpetual exchange.

### What is different

- The EVM↔Core bridge is asynchronous and uses HyperLiquid's native precompiles — it is not atomic
- The HLP vault enforces a **4-day lockup** on withdrawals
- Deposits and withdrawals are each a **2-step keeper process**
- `report()` does not auto-push idle funds (pushing to Core is async and would break accounting)

### Deposit flow (2 steps)

```
Step 1: pushFunds(amount)
HyperEVM USDC → CoreDepositWallet → HyperCore spot account [async]

Step 2: depositToVault(amount)
HyperCore spot → perps account → HLP vault
```

Call `depositToVault` only after confirming funds have arrived in the spot account via `coreSpotBalance()`.

### Withdrawal flow (2 steps)

```
Step 1: withdrawFromVault(amount)
HLP vault → HyperCore perps → spot account [subject to 4-day lockup]

Step 2: processWithdrawal(amount)
HyperCore spot → HyperEVM → CCTP bridge → Ethereum mainnet
+ sends accounting message to origin strategy
```

Call `processWithdrawal` only after the lockup has elapsed and funds are confirmed in `coreSpotBalance()`.

### View functions

| Function | Returns |
|---|---|
| `coreSpotBalance()` | USDC in HyperCore spot account (bridgeable to EVM) |
| `corePerpsBalance()` | USDC in HyperCore perps account |
| `vaultEquity()` | USDC value of position in the HLP vault |
| `valueOfDeployedAssets()` | Sum of vault equity + spot + perps (used in `totalAssets`) |

### HLP-specific risks

- **4-day lockup**: capital committed to HLP cannot be retrieved for at least 4 days after initiating a withdrawal
- **HyperLiquid exchange risk**: the HLP vault is exposed to losses from the HyperLiquid perpetual exchange, which are socialized across depositors
- **Async accounting**: `remoteAssets` on the mainnet strategy reflects the last relayed CCTP message; there is an inherent lag between on-Core state changes and mainnet accounting

## Links

<PrettyLink>[yvUSD developer docs index](/developers/yvusd)</PrettyLink>

<PrettyLink>[yvUSD contract addresses](/developers/addresses/yvusd-contracts)</PrettyLink>
8 changes: 8 additions & 0 deletions docs/developers/yvusd/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# yvUSD

```mdx-code-block
import DocCardList from '@theme/DocCardList';

<DocCardList />
```

43 changes: 43 additions & 0 deletions docs/developers/yvusd/locked-yvusd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# LockedyvUSD (Cooldown Vault)

LockedyvUSD is a vault that wraps `yvUSD` shares and restricts withdrawals behind a cooldown period plus a withdrawal window.

## Default Parameters

In the current contract code, defaults are:

- Cooldown duration: `14 days`
- Withdrawal window: `7 days`

These are configurable by management onchain (for example `setCooldownDuration` and `setWithdrawalWindow`).

![Withdrawal timeline for LockedyvUSD](/img/diagrams/yvusd/lockedyvUSD-timeline.png)

## Key Behaviors (Integrator Notes)

- **Withdrawals are gated**: `maxWithdraw` / `maxRedeem` will return `0` unless the owner has started a cooldown and is inside the valid withdrawal window.
- **Cooldown is per-owner and will overwrite**: starting a new cooldown overwrites the previous cooldown state for that owner.
- **Transfer restrictions**: shares that are in cooldown cannot be transferred (non-cooldown shares may still be transferable).
- **Shutdown bypass**: when cooldown is disabled or the strategy is shutdown, the gating checks are bypassed (behavior depends on onchain configuration).

If you integrate LockedyvUSD, assume user withdrawals can revert unless your UI guides them through the cooldown flow.

## Cooldown Flow (Contract Methods)

Primary methods to be aware of:

- `startCooldown(uint256 shares)`: starts or overwrites the cooldown for `shares` owned by `msg.sender`.
- `cancelCooldown()`: clears the cooldown state for `msg.sender`.
- `maxWithdraw(address owner)` / `maxRedeem(address owner)`: returns `0` if cooldown is not active, still pending, or the withdrawal window has expired.
- `getCooldownStatus(address user)`: returns `(cooldownEnd, windowEnd, shares)` for UI state.

Management methods (onchain configuration):

- `setCooldownDuration(uint256)`: set to `0` to disable cooldown gating.
- `setWithdrawalWindow(uint256)`: window after cooldown during which withdrawals are allowed.

## Links

<PrettyLink>[yvUSD developer docs index](/developers/yvusd)</PrettyLink>

<PrettyLink>[yvUSD contract addresses](/developers/addresses/yvusd-contracts)</PrettyLink>
53 changes: 53 additions & 0 deletions docs/getting-started/products/yvaults/yvusd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# yvUSD

## Overview

**yvUSD** is a USDC-denominated cross-chain Yearn V3 vault. In standard Yearn v3 vaults, the assets deposited into a vault stay on the same chain.

![Standard mainnet Yearn vault](/img/diagrams/yvusd/mainnet.png)

But yvUSD applies a new design approach: combine the battle-tested Yearn v3 vault with cross-chain capital deployment to maximize yield. Users deposit their USDC to the vault on mainnet and the vault uses Circle's CCTP protocol to send the assets to strategies on other chains.

![yvUSD Design](/img/diagrams/yvusd/summary1.png)

Because only a strategy contract is needed on any CCTP-supported chain, rather than the entire Yearn v3 vault infra, the new design allows for a more nimble approach to capturing yield for users across chains.

![yvUSD with strategies on 3 chains](/img/diagrams/yvusd/summary2.png)

## How yvUSD differs from a standard V3 vault

- **Cross-chain deployment:** yvUSD strategies can deploy capital on other chains via Circle CCTP. Most V3 vaults keep assets on the same chain as the vault.
- **Withdrawals can be non-atomic:** because some capital may be deployed remotely, not all assets are necessarily immediately available on mainnet at all times.
- **Optional lock wrapper:** `LockedYvUSD` adds a cooldown plus a withdrawal window to make withdrawals more predictable for users who opt in, and it can add a "locker bonus" yield component.
- **Different strategy risk profile:** yvUSD can include cross-chain components and leveraged loopers (e.g., Morpho Blue), adding additional cross-chain and liquidation/borrow-rate risks compared to standard Yearn v3 vaults.
- **APR computation/display:** yvUSD APR is typically an aggregated, debt-weighted rate and is often surfaced via an onchain APR oracle plus an offchain APR service/cache (so displayed APR can lag conditions).

## LockedYvUSD

`LockedYvUSD` is a companion vault that wraps `yvUSD` shares and enforces a withdrawal cooldown. This is an optional opt-in product for users who can commit to delayed withdrawals, in exchange for an additional yield component (a "locker bonus") sourced from the vault's fee mechanics. The rationale for this feature is that standard Yearn v3 vaults allow for atomic withdrawals (the assets are already on the correct chain and can be withdrawn immediately), but CCTP involves a delay in bridging assets, meaning that not all vault assets are available immediately in yvUSD as they are in standard Yearn v3 vaults.

### Withdrawal process

Withdrawing from `LockedYvUSD` is a two-step process:

1. **Start cooldown** — call `startCooldown(shares)` to lock a specific number of shares for withdrawal. The default cooldown period is 14 days.
2. **Withdraw** — once the cooldown expires, withdraw within the 7-day withdrawal window.

If the withdrawal window expires before the user withdraws, the cooldown must be restarted from step 1. Shares locked in an active cooldown cannot be transferred.

![Withdrawal timeline for LockedyvUSD](/img/diagrams/yvusd/lockedyvUSD-timeline.png)

## Risks To Understand

yvUSD and its strategies involve risks beyond standard single-chain Yearn v3 vaults:

- Smart contract risk (Yearn vaults, strategies, and integrations)
- Stablecoin risk (depegs, issuer/custody risk, liquidity)
- Cross-chain risk (bridging and remote execution/accounting)
- Leverage/liquidation risk (for looper strategies that borrow against collateral)

## Read More

<PrettyLink>[yvUSD Deep Dive](/developers/yvusd)</PrettyLink>

<PrettyLink>[Circle Cross-Chain Transfer Protocol (CCTP)](https://www.circle.com/cross-chain-transfer-protocol)</PrettyLink>
2 changes: 1 addition & 1 deletion scripts/fetchedAddressData.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"timeLastChecked": 1772219650,
"timeLastChecked": 1773235722,
"addressesData": {
"v3ContractAddresses": {
"topLevel": {
Expand Down
26 changes: 26 additions & 0 deletions sidebars/sidebarsDeveloperDocs.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@ export default {
// id: 'v1/introduction',
// },
items: [
{
type: 'category',
label: 'yvUSD',
link: {
type: 'doc',
id: 'yvusd/index',
},
collapsed: true,
items: [
'yvusd/cross-chain-strategies',
'yvusd/locked-yvusd',
'yvusd/apr',
{
type: 'link',
label: 'yvUSD Contract Addresses →',
// Use a hardcoded URL so this link is never treated as "active" in the yvUSD sidebar.
// Otherwise both this link and the actual Addresses sidebar entry are highlighted.
href: 'https://docs.yearn.fi/developers/addresses/yvusd-contracts',
},
],
},
{
type: 'category',
label: 'yVaults v3',
Expand Down Expand Up @@ -141,6 +162,11 @@ export default {
label: 'General',
id: 'addresses/core-contracts',
},
{
type: 'doc',
label: 'yvUSD',
id: 'addresses/yvusd-contracts',
},
{
type: 'doc',
label: 'yVaults v3',
Expand Down
Loading
Loading