Skip to main content
The Deposit Router is an attribution-only, non-custodial pass-through. It pulls tokens from the caller, dispatches to the correct vault protocol (ERC-4626, Midas issuance vault, Veda teller, Lido queue, or custom adapter), forwards the minted shares to the user, and emits a Routed event for on-chain attribution. No fees are deducted — 100% of the user’s tokens reach the vault. Current version: V3.2.0 on all chains (Ethereum, Base, Arbitrum, Optimism, HyperEVM, Katana). Mainnet upgraded 2026-04-25 in tx 0x2f7370658006e87972488159bc97dfc5cfef8067039e5127c8060c384ecbce21.

What Changed in V3.2.0

  • depositForAvailable(...) — new entry point that pulls min(allowance, balance) from msg.sender instead of an explicit amount argument. Eliminates the calldata-amount-mismatch revert that bridge-fee underflows would otherwise cause: any 1-wei underdelivery from Across/Stargate would previously revert the whole composer call. Now the router sweeps whatever actually arrived.
  • ERC-4626 void-return fallback — vaults whose deposit() returns no value (some forks of OpenZeppelin’s older 4626 reference) are detected via vrd.length and fall back to a balanceOf delta to compute shares. Removes a class of “Adapter: shares not delivered” reverts on niche forks.
  • All V3.1.1 changes (open caller model, no whitelist) carried forward.

What Changed in V3.1.1

  • Removed the authorizedCallers gate on depositFor / depositRequestFor. Any address can now call with an arbitrary user argument, which is used purely for the Routed event and as the share recipient. This removes ops friction of whitelisting every new LiFi bridge-receiver contract (ReceiverAcrossV3/V4, ReceiverStargateV2, ReceiverChainflip, per-chain Executors, etc.) and keeps the composer flow working across bridge updates without a router upgrade.
  • Security note: funds are pulled from msg.sender (the caller must own the tokens or have been approved), so no one can spend a third party’s balance. The remaining risk is attribution spoofing — anyone can emit a Routed event with an unrelated user/partnerId. Attribution consumers (revenue share, referrer tiering) should treat Routed events as advisory and cross-check against on-chain share balances where strict correctness matters.
  • authorizedCallers storage slot and the admin functions (setAuthorizedCaller, setAuthorizedCallerBatch) are preserved for forward compatibility but are not consulted by the current implementation.

What Changed in V3.1.0

  • 8-arg depositFor with minSharesOut — on-chain slippage floor. The 7-arg form is kept as a compatibility shim (forwards with minSharesOut=0).
  • Shares returned explicitly — _executeVaultCall now returns the exact shares minted, cross-checked against balanceOf(recipient) to detect silent failures in downstream adapters.
  • Routed event now includes shares — previously indexers had to read vault share balances to compute this.
  • Introduced authorizedCallers whitelist (removed again in V3.1.1 — see above).

Contract Addresses

All chains on V3.2.0 as of 2026-04-25. Same proxy address on Katana and HyperEVM is coincidental (CREATE2 on separate chains).

How Deposits Work

Same-Chain Deposit

msg.sender == user. No whitelist check needed.

Cross-Chain Deposit (Two-Step)

Used for vault types that aren’t composable with LiFi’s Composer (Midas, Veda, Custom, IPOR, Lido):
Step 2 is a normal same-chain deposit from the user’s perspective.

Cross-Chain Deposit (Single-Step, Composer)

Used for Morpho and other standard ERC-4626 vaults. LiFi bridges + calls depositFor atomically on the destination:
Because msg.sender is a LiFi bridge receiver (Executor, ReceiverAcrossV4, ReceiverStargateV2, etc.), the router must allow callers other than user. V3.1.1 accepts any msg.sender — only msg.sender’s own balance can be pulled.

depositForAvailable (V3.2.0+)

Cross-chain composer entry point — pulls min(allowance, balance) from msg.sender instead of an explicit amount. Used by the /v1/quote/build API for any composer route so the destination call cannot revert on bridge underdelivery.
Behavior:
Why: LiFi’s bridge receivers (Across, Stargate, etc.) approve the router for the post-bridge amount and call this. If the bridge delivered 1 wei less than the LiFi quote estimated, the explicit-amount depositFor would revert at safeTransferFrom. depositForAvailable sweeps the actual balance and proceeds.

depositFor

Primary entry point for same-chain user-initiated deposits. Two overloaded forms are exposed for backward compatibility:
Access control inside both forms (V3.1.1):
msg.sender is still the token source (safeTransferFrom(msg.sender, ...)), so only the caller’s own balance can ever be spent.

depositRequestFor

For vaults with async deposit queues (Yearn-style requestDeposit):
Emits DepositRequestRouted(partnerId, partnerType, user, vault, asset, amount, requestId).

Events

Vault Dispatch Priority

_executeVaultCall picks the deposit path in this order: Every path checks shares > 0 and cross-verifies balanceOf(recipient) deltas to fail closed.

Vault Adapter Pattern

New vault protocols can be added without a router upgrade. Deploy an adapter implementing IVaultAdapter:
The router transfers amount of asset to the adapter and calls adapter.deposit(...). The adapter must (a) return the actual share count and (b) deliver those shares to recipient. Retained assets on the adapter revert the deposit. Register an adapter:

Caller Model (V3.1.1)

V3.1.1 removes the caller whitelist. Any address may call depositFor(..., user=<anyone>). The admin setters (setAuthorizedCaller, setAuthorizedCallerBatch) and the authorizedCallers mapping still exist in storage but are not consulted by the current implementation — they remain in place so the whitelist can be re-enabled in a future release without a storage-layout migration. Why the gate was removed: LiFi routes composer deposits through several different bridge-specific receivers (ReceiverAcrossV3, ReceiverAcrossV4, ReceiverStargateV2, ReceiverChainflip, plus per-chain Executors), and each new bridge LiFi supports would otherwise require a whitelist update on every router proxy. V3.1.0’s Whitelist model couldn’t keep up. Trade-off: anyone can emit a Routed event with a spoofed user / partnerId. Funds are safe (safeTransferFrom pulls from msg.sender only), but attribution consumers should treat Routed events as informational and verify with on-chain share balances when exact attribution matters.

Admin Functions

Owner-only:

Security Properties

  • No custody — contract never holds a positive balance between transactions. Any stuck balance is rescuable by owner.
  • No fees — 100% of the deposited amount is forwarded to the vault. Attribution is event-only.
  • Access-controlled user spoofing — non-authorized callers can only pass user == msg.sender.
  • Reentrancy protected — all state-mutating deposit paths use the OpenZeppelin ReentrancyGuard.
  • Optional vault allowlist — vaultWhitelistEnabled can gate which vaults can be deposited into. Off by default.
  • Two-step ownership — prevents accidental transfer to dead addresses.
  • UUPS upgradeable — owner-controlled, storage layout preserved across all upgrades via _deprecated_ padding.

API Integration Notes

The Yieldo API (/v1/quote/build) returns pre-encoded depositFor calldata using the 7-arg form for maximum backward compat during the rollout window. After all integrators have migrated, the API will switch to the 8-arg form with a computed minSharesOut for real slippage protection. Users never sign an intent or typed-data message for deposits anymore — they only sign the approval (for ERC-20) and the deposit transaction itself. Withdrawals are handled by the vault protocols directly (ERC-4626 redeem / withdraw) and are outside the router’s scope.