1"use strict";(self.webpackChunkyearn_devdocs=self.webpackChunkyearn_devdocs||[]).push([["2780"],{29567:function(e,t,s){s.r(t),s.d(t,{metadata:()=>n,default:()=>h,frontMatter:()=>a,contentTitle:()=>o,toc:()=>l,assets:()=>d});var n=JSON.parse('{"id":"yvusd/cross-chain-strategies","title":"Cross-Chain Strategies","description":"yvUSD deploys capital cross-chain through a pair of contracts a standard ERC-4626 variant (CCTPRemoteStrategy). Additional remote vault implementations that use different native bridges are currently in development.","source":"@site/docs/developers/yvusd/cross-chain-strategies.md","sourceDirName":"yvusd","slug":"/yvusd/cross-chain-strategies","permalink":"/developers/yvusd/cross-chain-strategies","draft":false,"unlisted":false,"tags":[],"version":"current","lastUpdatedAt":1781092160000,"frontMatter":{},"sidebar":"developers","previous":{"title":"yvUSD","permalink":"/developers/yvusd/"},"next":{"title":"Locked yvUSD (Cooldown Vault)","permalink":"/developers/yvusd/locked-yvusd"}}'),r=s(74848),i=s(28453);let a={},o="Cross-Chain Strategies",d={},l=[{value:"Architecture",id:"architecture",level:2},{value:"Origin strategy (example: <code>CCTPStrategy</code>)",id:"origin-strategy-example-cctpstrategy",level:3},{value:"Discovering Destinations (Onchain)",id:"discovering-destinations-onchain",level:2},{value:"1) Enumerate Origin Strategy Addresses",id:"1-enumerate-origin-strategy-addresses",level:3},{value:"2) Identify Whether A Strategy Is Cross-Chain",id:"2-identify-whether-a-strategy-is-cross-chain",level:3},{value:"3) Read Destination Configuration From The Strategy",id:"3-read-destination-configuration-from-the-strategy",level:3},{value:"4) Read The Remote Strategy\u2019s Deployment Target (Optional)",id:"4-read-the-remote-strategys-deployment-target-optional",level:3},{value:"Remote strategy (example: <code>CCTPRemoteStrategy</code>)",id:"remote-strategy-example-cctpremotestrategy",level:2},{value:"Accounting model",id:"accounting-model",level:2},{value:"Keeper Operations",id:"keeper-operations",level:2},{value:"Remote strategy keepers",id:"remote-strategy-keepers",level:3},{value:"Origin strategy keepers",id:"origin-strategy-keepers",level:3},{value:"Deployment",id:"deployment",level:2},{value:"Links",id:"links",level:2}];function c(e){let t={a:"a",blockquote:"blockquote",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...e.components},{PrettyLink:n}=t;return n||function(e,t){throw Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("PrettyLink",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"cross-chain-strategies",children:"Cross-Chain Strategies"})}),"\n",(0,r.jsxs)(t.p,{children:["yvUSD deploys capital cross-chain through a pair of contracts: an ",(0,r.jsx)(t.strong,{children:"origin strategy"})," on Ethereum mainnet and a ",(0,r.jsx)(t.strong,{children:"remote vault"})," on the destination chain. There is currently one remote vault implementation in production: a standard ERC-4626 variant (",(0,r.jsx)(t.code,{children:"CCTPRemoteStrategy"}),"). Additional remote vault implementations that use different native bridges are currently in development."]}),"\n",(0,r.jsx)(t.h2,{id:"architecture",children:"Architecture"}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Cross-chain USDC deployment flow",src:s(75471).A+"",width:"3164",height:"780"})}),"\n",(0,r.jsxs)(t.h3,{id:"origin-strategy-example-cctpstrategy",children:["Origin strategy (example: ",(0,r.jsx)(t.code,{children:"CCTPStrategy"}),")"]}),"\n",(0,r.jsx)(t.p,{children:"The Origin Strategy is a standard Yearn V3 tokenized strategy deployed on Ethereum mainnet. The CCTP strategy works like this:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Bridges USDC to the remote chain via Circle CCTP (",(0,r.jsx)(t.code,{children:"depositForBurn"}),")"]}),"\n",(0,r.jsxs)(t.li,{children:["Tracks remote capital in a ",(0,r.jsx)(t.code,{children:"remoteAssets"})," storage variable"]}),"\n",(0,r.jsxs)(t.li,{children:["Receives accounting updates from the remote vault via incoming CCTP messages (",(0,r.jsx)(t.code,{children:"handleReceiveFinalizedMessage"}),")"]}),"\n",(0,r.jsxs)(t.li,{children:["Restricts deposits to a single ",(0,r.jsx)(t.code,{children:"DEPOSITER"})," address (typically the yvUSD vault)"]}),"\n",(0,r.jsx)(t.li,{children:"Only exposes local USDC balance as immediately withdrawable \u2014 remote assets must be bridged back with a delay before they can be withdrawn"}),"\n"]}),"\n",(0,r.jsxs)(t.blockquote,{children:["\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Withdrawal availability vs. total accounting"})}),"\n",(0,r.jsxs)(t.p,{children:["Only ",(0,r.jsx)(t.code,{children:"balanceOfAsset()"}),", the amount of local USDC on mainnet, is immediately withdrawable from yvUSD. Remote capital on other chains is included in yvUSD's ",(0,r.jsx)(t.code,{children:"totalAssets()"})," value, but must be bridged back before it can be redeemed."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"discovering-destinations-onchain",children:"Discovering Destinations (Onchain)"}),"\n",(0,r.jsxs)(t.p,{children:["The yvUSD vault does not store a list of destinationchain addresses. Instead, yvUSD allocates to ",(0,r.jsx)(t.strong,{children:"origin-chain strategies"}),", and each cross-chain strategy contains its own destination configuration as query
1able public immutables."]}),"\n",(0,r.jsxs)(t.p,{children:["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 ",(0,r.jsx)(t.code,{children:"REMOTE_*"})," public immutables that mainnet strategies do not have."]}),"\n",(0,r.jsx)(t.p,{children:'To learn "where yvUSD is sending assets", you:'}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsx)(t.li,{children:"Enumerate the strategy addresses used by the yvUSD vault on Ethereum."}),"\n",(0,r.jsx)(t.li,{children:"For each strategy, determine whether it is a cross-chain strategy."}),"\n",(0,r.jsxs)(t.li,{children:["For cross-chain strategies, read the destination configuration (",(0,r.jsx)(t.code,{children:"REMOTE_*"})," immutables)."]}),"\n",(0,r.jsxs)(t.li,{children:["(Optional) On the destination chain, the ",(0,r.jsx)(t.code,{children:"vault()"})," value is where it deploys funds (for example, the target ERC-4626 vault)."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"1-enumerate-origin-strategy-addresses",children:"1) Enumerate Origin Strategy Addresses"}),"\n",(0,r.jsxs)(t.p,{children:["Onchain, the vault can only expose ",(0,r.jsx)(t.em,{children:"arrays"})," of strategies via limited mechanisms (for example, the withdrawal ",(0,r.jsx)(t.code,{children:"default_queue"}),", max length 10). For a complete and always-up-to-date list, you typically need to index events offchain or use ",(0,r.jsx)(t.a,{href:"/developers/yvusd/api",children:"the yvUSD API"}),"."]}),"\n",(0,r.jsx)(t.p,{children:"Practical options:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Quick view (onchain call):"})," ",(0,r.jsx)(t.code,{children:"VaultV3.get_default_queue()"})," returns the current default withdrawal queue (max 10 strategies)."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"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."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Periphery:"})," if you have access to a Yearn Registry / Role Manager for the chain, use those helpers to retrieve vault/strategy configuration."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"2-identify-whether-a-strategy-is-cross-chain",children:"2) Identify Whether A Strategy Is Cross-Chain"}),"\n",(0,r.jsxs)(t.p,{children:["Call ",(0,r.jsx)(t.code,{children:"REMOTE_CHAIN_ID()"})," on the strategy contract. Cross-chain strategies (ie. ",(0,r.jsx)(t.code,{children:"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."]}),"\n",(0,r.jsxs)(t.p,{children:["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,r.jsx)(t.code,{children:"0"}),") indicates a mainnet-only strategy."]}),"\n",(0,r.jsxs)(t.p,{children:["As a secondary check, ",(0,r.jsx)(t.code,{children:"REMOTE_COUNTERPART()"})," returns the address of the paired remote vault contract. A non-zero address further confirms the strategy is cross-chain."]}),"\n",(0,r.jsx)(t.h3,{id:"3-read-destination-configuration-from-the-strategy",children:"3) Read Destination Configuration From The Strategy"}),"\n",(0,r.jsx)(t.p,{children:"For cross-chain strategies (origin side), the key queryable fields are:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"REMOTE_ID()"})," (CCTP domain encoded as ",(0,r.jsx)(t.code,{children:"bytes32"}),")"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"REMOTE_CHAIN_ID()"})," (EVM chain id)"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"REMOTE_COUNTERPART()"})," (remote vault contract address on the destination chain)"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"DEPOSITER()"})," (address allowed to deposit into the strategy; typically the yvUSD vault)"]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"This is the source of truth for where the origin strategy bridges to."}),"\n",(0,r.jsx)(t.h3,{id:"4-read-the-remote-strategys-deployment-target-optional",children:"4) Read The Remote Strategy\u2019s Deployment Target (Optional)"}),"\n",(0,r.jsxs)(t.p,{children:["For the standard remote implementation (ie. ",(0,r.jsx)(t.code,{children:"CCTPRemoteStrategy"}),"), the remote vault deploys into an ERC-4626 vault that is stored as an immutable ",(0,r.jsx)(t.code,{children:"vault"})," (see ",(0,r.jsx)(t.code,{children:"BaseRemote4626"}),")."]}),"\n",(0,r.jsxs)(t.h2,{id:"remote-strategy-example-cctpremotestrategy",children:["Remote strategy (example: ",(0,r.jsx)(t.code,{children:"CCTPRemoteStrategy"}),")"]}),"\n",(0,r.jsx)(t.p,{children:"This is the strategy that is deployed on the destination chain. A remote CCTP strategy works like this:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Receives USDC from the origin via CCTP and deposits it into a target ERC-4626 vault"}),"\n",(0,r.jsxs)(t.li,{children:["Reports total assets back to the origin by sending a CCTP ",(0,r.jsx)(t.em,{children:"message"})," (no token transfer)"]}),"\n",(0,r.jsx)(t.li,{children:"Processes withdrawal requests by redeeming from the vault, bridging USDC back via CCTP, and sending an updated accounting message"}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"accounting-model",children:"Accounting model"}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"remoteAssets"})," on the origin strategy on mainnet is updated in two situations:"]}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Outbound bridge"})," (",(0,r.jsx)(t.code,{children:"_deployFunds"}),"): incremented immediately when an asset is bridged out"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Inbound message"})," (",(0,r.jsx)(t.code,{children:"handleReceiveFinalizedMessage"}),"): overwritten with the value sent by the remote vault's ",(0,r.jsx)(t.code,{children:"report()"})," or ",(0,r.jsx)(t.code,{children:"processWithdrawal()"})]}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["Because the inbound update depends on a bridge message relay, ",(0,r.jsx)(t.code,{children:"remoteAssets"})," can be stale between keeper cycles. A report or withdrawal from the remote always sends a fresh accounting message to resync."]}),"\n",(0,r.jsx)(t.h2,{id:"keeper-operations",children:"Keeper Operations"}),"\n",(0,r.jsx)(t.h3,{id:"remote-strategy-keepers",children:"Remote strategy keepers"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Function"}),(0,r.jsx)(t.th,{children:"Description"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.code,{children:"report()"})}),(0,r.jsxs)(t.td,{children:["Computes ",(0,r.jsx)(t.code,{children:"totalAssets"}),", bridges the value as a bridge message to the origin"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.code,{children:"processWithdrawal(amount)"})}),(0,r.jsxs)(t.td,{children:["Withdraws ",(0,r.jsx)(t.code,{children:"amount"})," from the vault, bridges USDC back to origin, sends accounting message"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.code,{children:"tend()"})}),(0,r.jsx)(t.td,{children:"Pushes idle local USDC into the vault"})]})]})]}),"\n",(0,r.jsx)(t.h3,{id:"origin-strategy-keepers",children:"Origin strategy keepers"}),"\n",(0,r.jsxs)(t.p,{children:["The origin strategy itself is a standard Yearn V3 tokenized strategy \u2014 its ",(0,r.jsx)(t.code,{children:"report()"})," triggers the vault's normal accounting. The vault's debt allocator controls how much is allocated to each cross-chain strategy."]}),"\n",(0,r.jsx)(t.h2,{id:"deployment",children:"Deployment"}),"\n",(0,r.jsx)(t.p,{children:"Origin and remote vault addresses are pre-computed so each side can be configured with the other's address before either is deployed."}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Origin"})," (",(0,r.jsx)(t.code,{children:"StrategyFactory.newStrategy()"}),"): deployed with CREATE, nonce-based address prediction"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Remote"})," (",(0,r.jsx)(t.code,{children:"RemoteStrategyFactory.deployRemoteStrategy()"}),"): deployed with CREATE3, deterministic salt of ",(0,r.jsx)(t.code,{children:"keccak256(vault, remoteDomain, remoteCounterpart)"})]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The factories are deployed at the same address on every chain."}),"\n",(0,r.jsx)(t.h2,{id:"links",children:"Links"}),"\n",(0,r.jsx)(n,{children:(0,r.jsx)(t.a,{href:"/developers/yvusd",children:"yvUSD developer docs index"})}),"\n",(0,r.jsx)(n,{children:(0,r.jsx)(t.a,{href:"/developers/addresses/yvusd-contracts",children:"yvUSD contract addresses"})})]})}function h(e={}){let{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},75471:function(e,t,s){s.d(t,{A:()=>n});let n=s.p+"assets/images/cross-chain-3a8e9f5585bdb480413e7cef7d859f0e.png"},28453:function(e,t,s){s.d(t,{R:()=>a,x:()=>o});var n=s(96540);let r={},i=n.createContext(r);function a(e){let t=n.useContext(i);return n.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.