Skip to main content

Cross-Chain Strategies

yvUSD deploys capital cross-chain through a pair of contracts: an origin strategy on Ethereum mainnet and a remote vault on the destination chain. There is currently one remote vault implementation in production: a standard ERC-4626 variant (CCTPRemoteStrategy). Additional remote vault implementations that use different native bridges are currently in development.

Architecture

Cross-chain USDC deployment flow

Origin strategy (example: CCTPStrategy)

The Origin Strategy is a standard Yearn V3 tokenized strategy deployed on Ethereum mainnet. The CCTP strategy works like this:

  • Bridges USDC to the remote chain via Circle CCTP (depositForBurn)
  • Tracks remote capital in a remoteAssets storage variable
  • Receives accounting updates from the remote vault 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.

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, the vault() value is 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 or use the yvUSD API.

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 (ie. 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 vault 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 vault 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 (ie. CCTPRemoteStrategy), the remote vault deploys into an ERC-4626 vault that is stored as an immutable vault (see BaseRemote4626).

Remote strategy (example: CCTPRemoteStrategy)

This is the strategy that is deployed on the destination chain. A remote CCTP strategy works like this:

  • 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 an asset is bridged out
  2. Inbound message (handleReceiveFinalizedMessage): overwritten with the value sent by the remote vault's report() or processWithdrawal()

Because the inbound update depends on a bridge 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

FunctionDescription
report()Computes totalAssets, bridges the value as a bridge 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 vault 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.

yvUSD developer docs index yvUSD contract addresses