Cross-Chain Vault Adapter
What is it
A CCIP adapter that lets users on other chains deposit into and redeem from your existing ERC-4626 vault, while vault accounting stays on the hub chain, the chain where the vault and the adapter are deployed.
What the adapter does
Right now, without the adapter, users of a De-Fi protocol backed by an ERC-4626 have to go through a multi-step process to deposit funds into, or redeem funds from, a vault deployed on a different chain from the one they currently have funds on. With Chainlink's Cross-Chain Vault Adapter, a team can accept deposits and redemptions from users on other chains in a single transaction.
Without the adapter, a user on a source chain bridges the asset to the hub chain themselves, switches their wallet network, holds the hub chain's gas token, approves and calls the vault, and bridges the shares back. With the adapter, they approve the source-chain CCIP Router, unless an allowance already exists, and send one CCIP message from the chain they are on.
A return requires the vault's share token to be a CCIP cross-chain token on both chains, as Requirements lists. Redemptions work the same way, in the reverse direction.
Deposit or redeem from another chain
This diagram illustrates the flow of deposits and redemptions with and without the adapter.
In a nutshell:
- When you deposit into a 4626 vault, you put in an ERC-20 asset compliant with the vault, and in return, you receive shares, sometimes referred to as vault tokens, or synthetic tokens, that represent your position in the vault.
- When you redeem those shares, you get back an equivalent amount of the underlying asset back.
Route comparison
Without the adapter
6 signatures
Step 1 of 10 Token approval. Approve the source Router. Approve the source-chain Router to spend your asset. Skipped when your allowance already covers the amount.
With the adapter
2 signatures
- aValidate
- bAdapter fee
- cDeposit
- dCheck the output
- eSend back
Step 1 of 6 Token approval. Approve the source Router. Approve the source-chain Router to spend your asset. Skipped when your allowance already covers the amount.
Click a numbered stop, or use the arrows, to read each step. transaction you sign token approval wallet network switch second CCIP message
Counts assume a successful request from an EVM wallet, CCIP fees paid in the native gas token, and one transaction per action. Approvals are skipped when the allowance already exists. Nothing here measures time or fee amounts.
The counts assume a successful request from an EVM wallet that uses CCIP directly, pays CCIP fees in the native gas token, and sends each transaction separately. Wallet network switches and CCIP execution are not transactions. A wallet whose allowance already covers the amount skips the approval steps.
The repository also contains a separate multibridge implementation for vaults whose asset or share token moves over other cross-chain protocols. These docs cover the CCIP implementation.
Who it's for
- Vault teams, such as issuers, protocols, and curators, that run an ERC-4626 vault on one chain and want deposits and redemptions from users on other chains connected by CCIP to become seamless.
- Integrators who build deposit and redeem interfaces on source chains. They encode the payload and send the CCIP message, and deploy no contracts.
Asynchronous vaults, multi-asset vaults, and targets that are not ERC-4626 vaults need a fork; see Use it as-is or customize it.
Requirements
Only tokens that cross chains need CCIP support. Which tokens those are depends on where users send tokens from and where they want to receive the result:
| If you want users to... | Tokens that must be CCIP-enabled |
|---|---|
| Deposit from another chain and receive shares on the hub chain | Asset only |
| Deposit from another chain and receive shares back on the source chain | Asset and shares |
| Redeem from another chain and receive the asset on the hub chain | Shares only |
| Redeem from another chain and receive the asset back on the source chain | Shares and asset |
Each token that crosses chains must be configured as a CCIP cross-chain token (CCT) between the source chain and the hub chain.
If your vault's asset is not CCIP-enabled, you can still offer redemptions from another chain with delivery on the hub chain. Users send their CCIP-enabled shares to the adapter, and the adapter redeems them and delivers the asset locally. The asset does not cross chains in this flow.
To enable cross-chain transfers of shares, the share token typically uses Lock & Release on the hub chain, because only the vault may mint shares, and Burn & Mint on source chains.
See the Lock & Mint tutorial for more details.
Your vault and deployment must also meet these requirements:
| Requirement | Needed for | Details |
|---|---|---|
| Standard ERC-4626 vault | All flows | Synchronous and single-asset. The adapter calls deposit and redeem itself as depositor and share owner, so the vault must accept a contract in both roles. |
| Standard ERC-20 behavior | All flows | The asset and share token must transfer exactly the amount requested. The adapter does not handle fee-on-transfer or rebasing tokens. |
| Shanghai-compatible hub chain | Deploying the adapter | The adapter bytecode uses the PUSH0 opcode. |
| Native gas token held by the adapter | Returning output to the source chain | The adapter pays each return leg's CCIP fee from its own native gas token balance. If the balance is too low, the request becomes a failed message. |
What you deploy and operate
You deploy one adapter on the hub chain with one call to
deployon theCrossChainERC4626AdapterFactory, and that's it.
That transaction sets the accepted source chains, allowlists your vault when you pass its address and enable it, sets the deposit and redeem switches and the adapter fees, and grants the admin, fee setter, and fee collector roles to your accounts. The factory then renounces all of its own roles. The Factory contract reference lists the factory's deployed addresses and its inputs. One adapter can allowlist several vaults on the same chain, and each payload names the vault it targets.
A lane's version is defined as the version of the CCIP OnRamp and OffRamp contracts that serve it, and the CCIP Directory shows it. The factory does not apply CCIP 2.0 lane settings or fund the adapter, so after deployment you:
- Set the return format for each CCIP 2.0 lane to
GENERIC_EXTRA_ARGS_V3_BASIC. - Optionally set the inbound finality and Cross-Chain Verifier (CCV) settings for each CCIP 2.0 source chain.
- Fund the adapter with the native gas token for return legs.
The deployment guide covers configuration and funding. Your team holds the three roles on the adapter:
Role | Controls |
|---|---|
DEFAULT_ADMIN_ROLE | Source chains, the vault allowlist, the deposit and redeem switches, CCIP 2.0 lane settings, roles, and withdrawing the entire native gas token balance |
FEE_SETTER_ROLE | Adapter fees |
FEE_COLLECTOR_ROLE | Withdrawing collected adapter fees |
Roles use OpenZeppelin AccessControlEnumerable. Role changes take effect in one step, and renouncing the last admin locks the configuration permanently.
You also monitor the MessageFailed event. A failed request leaves its tokens in the adapter until someone refunds or recovers them. Disabling a source chain, a vault, or processing does not pause CCIP delivery. Messages that arrive become failed messages. See What counts as a failure.
Design choices
Vault accounting stays on the hub chain. Every deposit and redemption executes against the vault on the hub chain, with no copy of the vault or its share price elsewhere. Each request waits for CCIP delivery and uses the vault's exchange rate at execution, not at send time. A minimum output bounds the difference, measured after the adapter fee.
No contracts on source chains. Users send a standard CCIP message, and the adapter has no sender allowlist, so any address on an enabled source chain can use it. Nothing checks the payload before the tokens reach the hub chain, and a malformed payload can strand tokens permanently. Build it as described in What a user sends.
Processing failures are held, not reverted. When processing reverts, for example in the vault call, the minimum output check, or the return send, the adapter rolls back the vault call, keeps the inbound tokens, and records a failed message. The CCIP Explorer still shows Success, so track MessageFailed instead. Nothing is retried or refunded automatically.
Permissionless cross-chain refund, optional local recovery. Anyone can call refundFailedMessage to return the tokens to the original sender on the source chain, and the caller pays the CCIP fee in the native gas token. Refunds go to the original sender, not the beneficiary. The payload's local refund address can call recoverFailedMessageLocally on the hub chain instead; that address must be set before sending. Either way, recovery is a hub-chain action. See Failures and recovery.
Fees. Local delivery has no adapter fee. When output returns to the source chain, the user pays any configured adapter fee in asset units, and the adapter pays the return leg's CCIP fee from its native gas token balance. Fees explains how fees are charged and funded, and Limitations covers the remaining trade-offs.
Use it as-is or customize it
Use the adapter as-is through the factory when your vault meets the requirements. Otherwise, fork the repository and edit CrossChainERC4626Adapter.sol. The contract has no virtual hooks for processing, so you change processMessage and _processTarget directly. Common reasons to fork are asynchronous vaults (typically for the redemption path), multi-asset vaults, targets that are not ERC-4626 vaults, custom payload encoding, and custom validation of the source chain, sender, or beneficiary.
A fork must keep these safety properties:
ccipReceiveaccepts calls only from the CCIP Router.- Processing runs in a self-call (
this.processMessage) insidetry/catch, so a processing revert does not revert CCIP execution. - Failed messages are stored and stay recoverable through cross-chain refund and local recovery.
- Address conversion checks reject malformed addresses, such as a beneficiary whose upper 96 bits are not zero.
- The failure handler (the
catchpath) must not revert on any input, because a revert there strands the tokens, as described in Failures with no recovery path.
The contracts in src/ccip are audited. A fork is not the audited code and needs its own review and its own deployment, because the factory deploys only the original adapter. Customizing the adapter covers the changes and safety checks.
Where to go next
- How it works: the payload, both flows, delivery options, and fees.
- Failures and recovery: failed requests and how users get their tokens back.
- Limitations: what the adapter does not do.
- Adapter contract: the
CrossChainERC4626Adapterinterface. - Factory contract: the
CrossChainERC4626AdapterFactoryinterface and deployed addresses. - Deploy the vault and set up its share token: deploy an example ERC-4626 vault on Ethereum Sepolia and make its share token a CCIP cross-chain token.
- Deploy the adapter: deploy, configure, and fund an adapter for that vault through the factory.
- Deposit from a source chain: deposit into the vault from Arbitrum Sepolia through the adapter and receive the shares on Arbitrum Sepolia.
- Redeem from a source chain: redeem the shares from Arbitrum Sepolia, receive CCIP-BnM back, and withdraw the adapter fees as the vault operator.