The yoGateway contract is the single entry point for interacting with YO's ERC-4626 vaults. It provides a unified interface for deposits and redemptions across all YO vaults and automatically manages:
Asset transfers
Allowances and approvals
Vault interactions
It also enables:
Partner attribution tracking
Real-time quoting for assets ↔ shares
Built-in slippage protection
In this way, partners can integrate with one single interface and add support for all existing and future YO vaults at once.
yoGateway is available on Base, Ethereum and Arbitrum to handle deposits and redemptions on each chain independently. This means if you integrate yoGateway on Base, your users will receive their yoVault tokens on Base and can only be redeemed on Base.
Ping us on our Discord or Telegram to get your unique partner ID or if you have further questions.
The Gateway exposes helper functions to query allowances granted to the Gateway itself, either for redeeming shares or for depositing assets.
Solidity
JS/Ethers:
Depositing Assets
Solidity:
JS/Ethers:
Redeeming Shares
Solidity:
JS/Ethers:
Function Recap
Action
Quote Function
Execution Function
Deposit (assets→shares)
quotePreviewDeposit
deposit
Redeem (shares→assets)
quotePreviewWithdraw
redeem
Notes
Decimals must be respected when parsing values
WETH / yoETH: 18
cbBTC / yoBTC: 8
USDC / yoUSD: 6
USDT / yoUSDT: 6
EURC / yoEUR: 6
XAUT / yoGOLD: 6
Example: ethers.parseUnits("1.0", 18)
Redemption Liquidity
When calling redeem(), if the target vault does not have sufficient liquidity, the redemption will remain pending for up to 24 hours.
Once filled, the vault will send assets directly to the specified receiver.
Slippage protection calculations must be net of fees. Currently, the protocol does not charge any deposit or withdrawal fees, so the impact of fees is obviated in the examples quoted.
End-to-End Example (Deposit + Redeem with min-out estimation)
Below is a complete example using yoETH that covers: quoting, estimating minSharesOut and minAssetsOut via quoteConvertTo*, checking allowances, depositing, and redeeming.
gateway.deposit(
yoVault, // yoVault address
assets, // amount of assets
minSharesOut, // slippage protection, quote first to pass the result as the amount of shares
receiver, // recipient of shares
partnerId // attribution
);
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
const gatewayWithSigner = gateway.connect(signer);
const tx = await gatewayWithSigner.deposit(
yoVault, // yoVault address
ethers.parseUnits("1.0", 18), // 1 WETH
ethers.parseUnits("0.99", 18), // minSharesOut, quote using quotePreviewDeposit() first to pass the result as the amount of shares
signer.address, // receiver, recipient of shares
1234 // your unique partnerId
);
await tx.wait();
gateway.redeem(
yoVault, // yoVault address
shares, // shares to redeem
minAssetsOut, // slippage protection, quote first to pass the result as the amount of shares
receiver, // recipient of assets
partnerId // attribution
);
const tx = await gatewayWithSigner.redeem(
yoVault, // yoVault address
ethers.parseUnits("1.0", 18), // shares to redeem
ethers.parseUnits("0.99", 18), // minAssetsOut, quote first using quotePreviewWithdraw() to pass the result as the amount of shares
signer.address, // receiver of assets
1234 // your unique partnerId
);
await tx.wait();
import { ethers } from "ethers";
import YoGatewayAbi from "./abis/YoGateway.json" assert { type: "json" };
import ERC20Abi from "./abis/ERC20.json" assert { type: "json" };
async function main() {
const provider = new ethers.JsonRpcProvider("https://mainnet.base.org"); // use an Ethereum or Base RPC provider. mainnet.base.org used as an example
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
const gatewayAddr = "0xF1EeE0957267b1A474323Ff9CfF7719E964969FA";
const yoETH = "0x3a43aec53490cb9fa922847385d82fe25d0e9de7";
const gateway = new ethers.Contract(gatewayAddr, YoGatewayAbi, signer);
// ERC20 reference for WETH (asset of yoETH)
const WETH = "0x4200000000000000000000000000000000000006"; // canonical WETH on Base
const weth = new ethers.Contract(WETH, ERC20Abi, signer);
// ---- STEP 1: QUOTE & DEPOSIT ----
const depositAssets = ethers.parseUnits("1.0", 18); // 1 WETH
const quotedShares = await gateway.quotePreviewDeposit(yoETH, depositAssets);
const minSharesOut = quotedShares * 99n / 100n; // 1% slippage buffer
console.log("Quoted shares for deposit:", quotedShares.toString());
console.log("minSharesOut:", minSharesOut.toString());
// Approve WETH to Gateway if needed
const currentAssetAllowance = await gateway.getAssetAllowance(yoETH, signer.address);
if (currentAssetAllowance < depositAssets) {
const approveTx = await weth.approve(gatewayAddr, depositAssets);
await approveTx.wait();
}
// Deposit WETH into yoETH
const depositTx = await gateway.deposit(yoETH, depositAssets, minSharesOut, signer.address, 1234);
await depositTx.wait();
console.log("Deposit confirmed:", depositTx.hash);
// ---- STEP 2: QUOTE & REDEEM ----
const redeemShares = ethers.parseUnits("0.5", 18); // redeem half the shares
const quotedAssets = await gateway.quotePreviewWithdraw(yoETH, redeemShares);
const minAssetsOut = quotedAssets * 99n / 100n; // 1% slippage buffer
console.log("Quoted assets for redemption:", quotedAssets.toString());
console.log("minAssetsOut:", minAssetsOut.toString());
// Approve yoETH shares to Gateway if needed
const sharesAllowance = await gateway.getShareAllowance(yoETH, signer.address);
if (sharesAllowance < redeemShares) {
const approveSharesTx = await (new ethers.Contract(yoETH, ERC20Abi, signer)).approve(gatewayAddr, redeemShares);
await approveSharesTx.wait();
}
// Redeem yoETH shares back into WETH
const redeemTx = await gateway.redeem(yoETH, redeemShares, minAssetsOut, signer.address, 1234);
const receipt = await redeemTx.wait();
console.log("Redeem submitted:", receipt.hash);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});