# What is YO?

Yield Optimizer 101

YO stands for Yield Optimizer. YO is a DeFi protocol that helps you easily boost your crypto earnings without the hassle. YO automatically moves funds across the best-performing pools no matter the blockchain, so you’re always getting the **highest risk-adjusted yield**.&#x20;

YO leverages [Exponential.fi's Risk Ratings](https://exponential.fi/learn/risk-rating) to smartly balance risks and reward—so you don’t have to spend time managing risk yourself. YO is fully decentralized, meaning you’re always in control of your assets from your own wallet. If you want a simple, secure way to earn more from your crypto, YO’s got you covered.


# Why should I use YO?

Yield optimizer 101

If you’re tired of constantly chasing the highest yields across multiple blockchains and DeFi protocols: YO is designed specifically for you. Manually searching for yield opportunities is exhausting, time-consuming, and expensive, forcing you to pay bridging fees, endure trading slippage, and deal with volatile yields that change without notice.

YO eliminates these pain points by automatically seeking and investing in the best risk-adjusted yield opportunities across multiple blockchains. No manual chasing, bridging headaches, or slippage losses involved for you. Using a smart, risk-adjusted approach, YO delivers more consistent yield earnings and helps you achieve a steadier, predictable DeFi earnings.

Say goodbye to endless research, complex interfaces, high gas costs, and frustrating yield chasing. With YO, you get clarity, simplicity, and peace of mind knowing your crypto is continuously optimized in a safe, transparent environment. It’s your trusted companion to finally making DeFi earnings reliable, stress-free, and efficient.

<figure><img src="/files/rIHGesugDORaELImR5Kk" alt=""><figcaption></figcaption></figure>


# FAQ

## General FAQ

<details>

<summary>What is YO?</summary>

YO is your multi-chain yield optimizer, continuously rebalancing your assets across DeFi to deliver the best risk-adjusted yield.

</details>

<details>

<summary>How does YO work?</summary>

When you deposit, YO allocates your assets to the highest-yielding pools across multiple chains, optimizing yield and managing rebalancing for the vault. Allocations are adjusted based on pool risk using Exponential.fi's trusted ratings. The underlying pool listings are transparent and can be viewed on the vault page.

</details>

<details>

<summary>What makes YO different?</summary>

YO never stops hunting. YO scans the entire DeFi ecosystem, across chains and protocols, to find the best risk-adjusted yield for your assets. It continuously adds new opportunities and auto-rebalances across pools to keep your yield optimized.

</details>

<details>

<summary>Why does YO have superior yields?</summary>

YO looks for all the pools within a strategy and is asset-, protocol- and chain-agnostic: e.g. yoBTC can allocate cbBTC or tBTC, on Morpho or Aave, on Base or Ethereum.

\
YO optimizes yield on a risk-adjusted basis by investing new deposits in the most attractive yields and redeeming withdrawals from the least attractive yields, on a risk-adjusted basis.<br>

YO automates strategies you cannot perform on your own, like continuously moving to the highest tick to provide liquidity to cbETH-wETH on Aerodrome, or performing a carry trade on BTC to earn higher yields.

</details>

<details>

<summary>How does vault allocation work?</summary>

Vault allocation consists of two key components: underlying pools and target allocation. The target allocation defines how assets are distributed across these pools, ensuring diversification while maximizing risk-adjusted yield.

</details>

<details>

<summary>How is the YO yield calculated?</summary>

Yield is calculated as the weighted average of the yields from the underlying pools within a vault and considers any idle assets.

</details>

<details>

<summary>How can I embed YO yield in my dApp?</summary>

Check the section [Build with YO](/integrations/build-with-yo) here in our docs

</details>

## Vaults FAQ

<details>

<summary>How does the rebalancing of pools and allocation work?</summary>

Each yoVault has a target allocation of pools, which is a subset of all the whitelisted pools for the vault. Every day, the protocol calculates the optimal allocation based on the existing pools' risk rating and trending yield. The protocol then divests assets from the least attractive pools and invests those in the higher yielding ones.&#x20;

</details>

<details>

<summary>How are new protocols and chains selected for integration? Who does this?</summary>

The YO team, together with the YO community on Telegram and Discord, actively monitors the DeFi ecosystem to identify attractive yield opportunities, across all protocols and chains. Each opportunity is evaluated based on factors such as the sustainability of its yield source, its risk rating, and the efficiency of capital flows in and out of the position.

When a high-quality opportunity is identified, the development team is responsible for integrating the relevant protocol or chain into the YO vault infrastructure. Once integrated, the algorithm automatically allocates new deposits to the opportunity, but only if it offers the most attractive risk-adjusted return at that time.

Looking ahead, YO’s governance will play a more active role by voting on which pools and protocols should be prioritized for integration. The algorithm will continue to decide where capital is allocated and may choose not to allocate funds to a governance-approved opportunity if it doesn't meet performance or risk thresholds. Governance is not yet active but is planned for a future phase of the protocol.

</details>

<details>

<summary>How often are the vaults rebalanced?</summary>

Vaults are rebalanced for the optimal risk-adjusted yield on a daily basis.

</details>

<details>

<summary>How do you weigh yield vs risk?</summary>

YO uses Exponential.fi's risk ratings to quantify pool risk. Each rating has a quantitative score that represents the probability of the pool losing all of its value. All pools' APYs are weighted against their probability of a total wipeout and that results in a risk-adjusted yield for each pool. The YO algorithm then finds the allocation that maximizes the risk-adjusted yield of the vault.

</details>

<details>

<summary>How are gas costs, bridging fees and other costs handled?</summary>

At the moment, the Protocol is sponsoring gas fees. All of the other costs of the vault are socialized among depositors. The optimization algorithm does take costs into consideration to avoid unnecessary transactions on a daily basis. This means that even if one pool is particularly high-yielding on one day, the protocol will not rebalance towards that pool automatically to avoid incurring bridging and trading fees unnecessarily. Once a trend has been confirmed, the vault is rebalanced. <br>

This approach makes yield farming more efficient for you as an individual, given that keeping tabs on all of these costs, risks and pools is really a full-time job and that's why YO exists.&#x20;

</details>

<details>

<summary>Are the contracts audited? </summary>

Yes! You can find a link to our audits [here](/protocol/security-audits)

</details>

<details>

<summary>Can I instantly withdraw my funds? Are there any lock-up periods?</summary>

The yoVaults keep a % of their assets idle so that you can redeem your yoTokens instantly. When you want to redeem a larger portion of the vault's assets, your withdrawal will be queued and may take up to 24 hrs to execute.

\
In those cases, your yoTokens will be burnt and as soon as the protocol redeems assets from the existing positions, you will receive your assets in your wallet automatically without having to come back to claim them. \
\
You can read a more detailed explanation [in our blog.](https://www.yo.xyz/blog/post/how-yo-solves-vault-withdrawals)

</details>

<details>

<summary>How are third-party token rewards handled? </summary>

All rewards are continuously reinvested into the vault as soon as they are claimable. Including TOKE, FLUID, MORPHO, etc.. They are reflected in the top-level APY as well as in the performance of the vault. This means yoVaults sell the reward tokens for more of the underlying asset or in some edge cases, they are reinvested as-is (when rewards are in the same token as the underlying asset of the vault). These reinvestments are continuous and executed as soon as the rewards exceed a specific amount to not overpay in gas for reinvestments.

</details>

## yoVault tokens FAQ

<details>

<summary>What are yoVault tokens?</summary>

Each Vault has a dedicated strategy, or yoToken. yoETH is investing in yield strategies based on ETH. yoBTC is investing in yield strategies based on BTC. When you mint yoTokens, you are entering at a specific yoToken <> asset exchange rate and that rate increases over time. You don't have to claim yield or do anything, your assets grow automatically with the protocol. The yoTokens you receive after depositing an asset in the vault represent your share in the vault.&#x20;

</details>

<details>

<summary>Which wallets are compatible with yoVault tokens? </summary>

Any wallet that supports ERC20 tokens is compatible with yoTokens. If you need to manually import the token into your wallet, please check the list of [token addresses](/protocol/contract-addresses)&#x20;

</details>

<details>

<summary>How do yoVault tokens generate yield? </summary>

yoTokens increase in value relative to their underlying asset as yield accrues. Yield accrues through the various underlying pools and investment strategies that the vault is investing in. The yield accrues to all participants in the vault proportionally to their share in the vault while they are holding the yoTokens.

</details>

<details>

<summary>Can I use yoVault tokens in DeFi?</summary>

Yes! yoTokens are compatible with the ERC-4626 and ERC-20 standards so anyone can build using yoTokens. We are working to bring native DeFi integrations for yoTokens. Stay tuned in our X, Discord, or Telegram communities.

</details>

### $YO Rewards FAQ

<details>

<summary>How do I earn $YO rewards?</summary>

$YO rewards are earned for qualifying activities going forward. The Rewards Program will consist of multiple "Heats", and the first Heat began on January 29th, the same day $YO was introduced. You will be able to earn $YO rewards in two ways:<br>

1. Deposit into YO Vaults

   Choose between yoUSD, yoETH, yoEUR, yoBTC, or yoGOLD vaults and start earning base yield plus additional $YO rewards.
2. Participate in DeFi activities

   Add liquidity to all of our supported DeFi activities to earn $YO rewards.

</details>

<details>

<summary>For how long will $YO rewards be issued? </summary>

YO reserved 30% of its token supply to reward the community, including through the $YO Rewards program. Reward rates will vary over time but they will be active for the foreseaable future with no plans to stop them.&#x20;

</details>

<details>

<summary>What's the difference between native APY and reward APY?</summary>

Native APY is the yield earned by the vault's investments and positions in DeFi. This yield is paid in the same asset that you deposited and it compounds continuously. You don't need to do anything to earn this yield. Reward APY is an additional yield paid in $YO tokens to incentivize long-term holders. These additional $YO tokens have to be claimed in the app.&#x20;

</details>

<details>

<summary>How is the Reward APY calculated?</summary>

Reward APY is calculated based on the last price of $YO (FDV of $90M or $0.09 per $YO) and the amount of token rewards assigned to each activity such as deposit & hold or other DeFi activities. &#x20;

</details>

<details>

<summary>How long do I have to claim my rewards? How often can I claim them?</summary>

You can claim $YO rewards continuously throughout the day as your account will earn $YO rewards every few hours. Our provider Merkl, takes multiple snapshots in the day to distribute rewards, which you have to claim. In some ocassions, these snapshots are taken only once a day. You can claim new rewards only after the snapshots are taken. \
\
You have 90 days to claim your $YO rewards. If you don't, we may reassign those rewards.&#x20;

</details>


# How to Deposit into YO

🔹 How to Deposit:

1\. Connect your wallet

Launch the dApp and click on the top right to Connect your Wallet. YO supports all popular wallets already.

<figure><img src="/files/ajB5nYusw863Wt33b0mq" alt=""><figcaption></figcaption></figure>

2\. Tap “Deposit”

From the main screen, tap the *Deposit* button.

<figure><img src="/files/4NWQGTsOdSYN80YcMnSI" alt=""><figcaption></figcaption></figure>

3\. Select Asset

Choose the token/asset you want to deposit, either WETH or native ETH.&#x20;

Note: make sure you are on Base chain

<figure><img src="/files/vFoQThT9LpuyHKoy4RD6" alt=""><figcaption></figcaption></figure>

4\. Approve and Deposit&#x20;

Click on "Approve" to begin the Deposit transaction. You first have to sign a transaction to give the YO protocol an allowance to spend your WETH. You will not be asked for an approval if you deposit native ETH. Once the approval transaction is complete, your wallet will open again with the deposit transaction. Sign the transaction to deposit into the Vault.&#x20;

6\. Done!&#x20;

Within a few seconds, your deposit will reflect in your balance and you can follow your transaction history in-app at the bottom of the page.

<figure><img src="/files/UgzJpbsfjcsX2GWJPNay" alt=""><figcaption></figcaption></figure>


# How to Withdraw from YO

🔹 How to Deposit:

1\. Connect your wallet

Launch the dApp and click on the top right to Connect your Wallet. YO supports all popular wallets already.

2\. Tap “Withdraw”

From the main screen, tap the *Withdraw* button.

![](/files/5wPDiXWdz5AJJCIa6g2N)

3\. Enter an amount

Use the quick action buttons to withdraw 10, 25, 50, 75 or 100% of your assets. You can also enter an amount of yoTokens manually.&#x20;

Note that the exchange rate of yoTokens <> Asset is not 1:1 so beware of that when entering an amount manually.

<figure><img src="/files/UzzQsQRlehGbp95ytHGv" alt=""><figcaption></figcaption></figure>

4\. Confirm your Withdrawal

Your wallet will open and ask you to sign the withdrawal transaction. If the amount of assets is less than 5% of the vault TVL, your withdrawal will be executed instantly and your funds will be in your wallet as soon as the transaction is confirmed onchain.&#x20;

If you are withdrawing a large amount, the withdrawal may take up to 24 hours to finalize. In those cases, the Vault has to divest from existing positions to fill your order. You will receive your assets automatically when the Vault fills your order

5\. Done!&#x20;

Within a few seconds, your withdrawal will reflect in your wallet balance and you can follow your transaction history in-app at the bottom of the page.


# YO Protocol

For more technical readers

### Summary of the yoVaults&#x20;

The yoVault protocol is a robust, secure, and efficient smart contract system designed to streamline asset management across blockchain platforms. Built on the widely recognized ERC4626 standard, yoVault automates the optimization of user assets across various decentralized finance (DeFi) strategies and chains. This vault eliminates manual management by intelligently reallocating funds to ensure users consistently achieve optimal returns.

yoVault incorporates a unique asynchronous redemption mechanism. Users can initiate a withdrawal request at any time, and the vault immediately processes these if it has sufficient liquidity. If the vault lacks immediate liquidity, redemption requests are securely stored until fulfilled by authorized operators, who are empowered to manage liquidity efficiently.

Risk management is integral to yoVault’s design. It actively monitors asset valuations and implements automatic safeguards, such as pausing operations when significant percentage changes occur in asset values, protecting users against volatility and market disruptions.

Transparent and predictable fees can be charged on both deposits and withdrawals, clearly defined within preset limits to ensure fairness. Currently these fees are set to 0. yoVault employs rigorous access control through clearly defined user and operator permissions, bolstered by the AuthUpgradeable contract. The system’s transparency is enhanced by integrating oracle-driven reporting mechanisms that regularly update aggregated balances and asset valuations.

Overall, yoVault simplifies onchain asset management, offering a secure, automated, and transparent solution ideal for both individual users and institutional participants seeking optimized yield strategies with minimal manual intervention.


# yoVault Tokens

In a nutshell, yoVault tokens are a basket of yield-generating pools for a specific asset exposure. This means that yoETH is a basket of ETH pools, yoBTC a basket of BTC pools and so on. Anyone can mint yoTokens by depositing the corresponding underlying asset into the YO protocol, and anyone can redeem yoVault tokens for underlying assets.&#x20;

<figure><img src="/files/5m58UM8hJlZv5158zLYB" alt=""><figcaption></figcaption></figure>

yoVault tokens are fully self-custodial, compatible with any wallet that supports ERC20 tokens.&#x20;

### Yield-bearing tokens

yoVault tokens like yoETH are yield-bearing in nature as the assets that collateralize the token are invested in yield-generating pools across DeFi. As the value of those pools increase relative to the underlying asset of the vault, the exchange rate of yoToken <> underlying asset keeps increasing.&#x20;

Users do not need to interact with the protocol to claim or harvest yield. Simply by holding yoTokens in their wallet, they are already earning yield on the underlying asset. yoTokens are not rebasing to facilitate composability with partner protocols.&#x20;

<figure><img src="/files/bsl65bPrBn93TKZn0qz1" alt=""><figcaption></figcaption></figure>


# Contract Addresses

List of published contracts and protocol addresses

## yoVaults

<table><thead><tr><th width="113.19140625">yoVault</th><th width="156.55859375">Deposit Chains</th><th width="284.44921875">yoVault and token address</th><th width="471.328125">Underlying Asset</th></tr></thead><tbody><tr><td>yoETH</td><td>Base, Ethereum</td><td>0x3a43aec53490cb9fa922847385d82fe25d0e9de7</td><td>WETH on Base: 0x4200000000000000000000000000000000000006<br><br>WETH on Ethereum: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2</td></tr><tr><td>yoUSD</td><td>Base, Ethereum, Arbitrum, Katana, X-Layer</td><td>0x0000000f2eb9f69274678c76222b35eec7588a65</td><td>USDC on Base: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913<br><br>USDC on Ethereum:<br>0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48<br><br>USDC on Arbitrum:<br>0xaf88d065e77c8cC2239327C5EDb3A432268e5831<br><br>vbUSDC on Katana:<br>0x203A662b0BD271A6ed5a60EdFbd04bFce608FD36<br><br>USD₮0 on X-Layer:<br>0x779Ded0c9e1022225f8E0630b35a9b54bE713736</td></tr><tr><td>yoUSDT*</td><td>Ethereum</td><td>0xb9a7da9e90d3b428083bae04b860faa6325b721e</td><td>USDT on Ethereum: 0xdac17f958d2ee523a2206206994597c13d831ec7</td></tr><tr><td>yoUSD Edge</td><td>Base, Ethereum, Arbitrum</td><td>0x5dd8bfa6c5c68d05d25ef6143e05c11e26c4cdb7</td><td>USDC on Base: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913<br><br>USDC on Ethereum:<br>0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48<br><br>USDC on Arbitrum:<br>0xaf88d065e77c8cC2239327C5EDb3A432268e5831</td></tr><tr><td>yoGOLD</td><td>Ethereum</td><td>0x586675A3a46B008d8408933cf42d8ff6c9CC61a1</td><td>XAUt on Ethereum: 0x68749665FF8D2d112Fa859AA293F07A622782F38</td></tr><tr><td>yoBTC</td><td>Base, Ethereum</td><td>0xbcbc8cb4d1e8ed048a6276a5e94a3e952660bcbc</td><td>cbBTC on Base: 0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf<br><br>cbBTC on Ethereum:<br>0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf</td></tr><tr><td>yoEUR</td><td>Base, Ethereum</td><td>0x50c749ae210d3977adc824ae11f3c7fd10c871e9</td><td>EURC on Base: 0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42<br><br>EURC on Ethereum:<br>0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c</td></tr><tr><td>yoSOL</td><td>Solana</td><td><strong>Mint:</strong> yoSoLJkgRYFwmt8apEDVKxHy6FktjYEWLvxB6NyJuNj<br><br><strong>Program:</strong> yvSoLSBaLoqZ2yQttGbaYzHDXr9Bo9UdqtiRDiVaMxP</td><td>SOL on Solana:<br>So11111111111111111111111111111111111111111</td></tr></tbody></table>

\*yoUSDT accepts **USDT** as the deposit asset, whereas yoUSD accepts USDC. Both vaults have the same underlying exposure and yield.

## yoGateway

<table><thead><tr><th width="154.6640625">Contract</th><th width="244.69921875">Address</th><th width="144.69921875">Chains</th><th>Description</th></tr></thead><tbody><tr><td>yoGateway</td><td>0xF1EeE0957267b1A474323Ff9CfF7719E964969FA</td><td><p>Base, </p><p>Ethereum, Arbitrum</p></td><td>Single entry point into all yoVaults to facilitate integrations. <a href="/pages/5ArS74Cet0964KiJS2Nh">Learn more</a>.</td></tr><tr><td>Vault Registry</td><td>0x56c3119DC3B1a75763C87D5B0A2C55E489502232</td><td><p>Base, </p><p>Ethereum, Arbitrum</p></td><td>Authoritative registry of all active yoVaults. </td></tr></tbody></table>

## Core Protocol

<table><thead><tr><th width="150.8515625">Contract</th><th width="254.55859375">Address</th><th width="138.390625">Chain</th><th width="284.625">Description </th></tr></thead><tbody><tr><td>YO Oracle</td><td>0x6E879d0CcC85085A709eBf5539224f53d0D396B0</td><td>EVMs</td><td>This contract is used to manage the oracle data for yoVaults. It is used to store the latest price for each vault.</td></tr><tr><td>YO Timelock</td><td>0x38cE5e45D0f5d03E83863bb19B3b1A272C186F48</td><td>EVMs</td><td>Authority that gates contracts upgrades behind a 48 hr timelock.</td></tr><tr><td>YO Admin Multisig</td><td>0x67b6F699F1c8040414032a3C2C88a54db144FCd2</td><td>EVMs</td><td>Overall manager for all yoVaults, including contract upgrades, and whitelisting new protocols and pools.</td></tr><tr><td>YO Admin Multisig</td><td>9PVwkaG7tEqxVW5jZmeYjXiWMgnvQi6crDB67j2mbovq</td><td>Solana</td><td>Overall manager for all yoVaults, including contract upgrades, and whitelisting new protocols and pools.</td></tr><tr><td>YO Operator Multisig</td><td>0x93e5260ac975b475af8bf818c14deee7fefd5927</td><td>EVMs</td><td>Allowed only to rebalance assets among whitelisted contracts.</td></tr><tr><td>YO Operator Multisig</td><td>EF9p1k8UzKG6jNxkPRVemyaCD9eHiRf6MDfo57AmM717</td><td>Solana</td><td>Allowed only to rebalance assets among whitelisted contracts.</td></tr><tr><td>Roles authority</td><td>0x9524e25079b1b04D904865704783A5aA0202d44D</td><td>EVMs</td><td>Manages which addresses have specific roles within the yoVaults</td></tr><tr><td>Onchain worker</td><td>0x5c28b54e7e1f9aafbdc5c563c1a460106f41bd58</td><td>EVMs</td><td>Allowed to execute arbitrary tasks like harvest rewards or unwind positions to refill vaults' idle capital.</td></tr><tr><td>Redeemer</td><td>0x0439e941841f97dc1334d1a433379c6fcdcc2162</td><td>EVMs</td><td>Processes async withdrawals as soon as liquidity is available</td></tr><tr><td>Emergency pauser</td><td>0xaa06ac3cb11b84c1d1094818341b4796c2b43c71</td><td>EVMs</td><td>Can pause individual vaults should it detect anomalies</td></tr></tbody></table>

Individual address roles can be verified using the RolesAuthority contract on the respective chain.&#x20;

### Onchain Adapters

<table><thead><tr><th width="231.89453125">Contract</th><th width="283.78515625">Address</th><th width="326.52734375">Description</th></tr></thead><tbody><tr><td>YoApprovalRegistry</td><td>0xB4b3F5C964A360bBd7201f72a55D0c48B8aD7021 (EVMs)</td><td>Controls which contracts can use assets for each vault. Contracts not declared here cannot be set as "spenders" in token approval transactions. Each vault requires its own set of permitted contracts. </td></tr><tr><td>YoMorphoMarketRegistry</td><td>0xcB9737BdD076251744704cc37CE961E8417fDd7f <br>(EVMs)</td><td>Controls which Morpho Markets can be allocated to from each vault. Permissions are granted individually by vault.</td></tr><tr><td>YoSwapPairRegistry</td><td>0xcff9d39441eB668C7fffa752aD1eA47930bB8A76<br>(EVMs) </td><td>Controls which swap routes are permitted for each vault and how to validate the price of the swaps.</td></tr><tr><td>YoERC4626VaultRegistry</td><td>0x7bad596c26e175384Bd9985Cb97C6c3f7e158b6F<br>(EVMs)</td><td>Controls which ERC4626 vaults can be allocated to for each vault. Permissions are granted individually by vault. </td></tr><tr><td>YoBridgeRouteRegistry</td><td>0x5973cE676fBe8bE0ec1D2d2F371d989374FB672b (EVMs)</td><td>Controls which bridging routes and bridging assets can be used for each vault. </td></tr><tr><td>YoChainlinkOracle</td><td>0x2800FC940a9B3BCB2CDE3c70797b21296BEcbf07<br>(EVMs)</td><td>Fetches the onchain price of a specific swap pair from whitelisted oracle sources</td></tr><tr><td>YoMorphoAdapter</td><td><p>0x93A3A3325dE6aB429523D144b41A032e7D7456Ab (EVMs)<br><br>0x946FD049C47BeFF53a32588C67df6a5A16B805F0 (HyperEVM only)     </p><p>       0x2BcB71309554A5DC31932Cb3D5A547Cd8cc5ED26 (Monad only)     </p></td><td>Onchain adapter to interact with Morpho Markets that enforces the receiver of market shares and assets is always the corresponding yoVault. Never holds user assets. </td></tr><tr><td>YoSwapAdapter</td><td>0xa425d3c9A1c048BE1183d8e396406bdA813b4826 (EVMs)</td><td>Onchain adapter that routes swaps through a whitelisted DEX aggregator, while enforcing price protections directly onchain. Never holds users assets.</td></tr><tr><td>YoERC4626Adapter</td><td>0x206fF3F58F57d00c48aF6010De6dC26f913eFd64 (EVMs)</td><td>Onchain adapter that lets yoVaults interact with ERC4626-compliant third-party vaults, while enforcing that the receiver of the vault shares and assets is always the corresponding yoVault. Never holds users assets.</td></tr><tr><td>YoIPORAdapter</td><td>0x4409446B49E24861697d566e5c6D68C0d8F3C50f<br>(EVMs)</td><td>Onchain adapter that lets yoVaults interact with IPOR-Fusion third-party vaults, while enforcing that the receiver of the vault shares and assets is always the corresponding yoVault. Never holds users assets.</td></tr><tr><td>YoLidoAdapter</td><td>0xF837334c5c48F16A8A73aFFb09859Bb7FDB467E0<br>(Ethereum)</td><td>Onchain adapter that lets yoVaults interact with the Lido ETH staking protocol, while enforcing that the receiver of the assets is always the corresponding yoVault. Never holds users assets.</td></tr><tr><td>YoCCTPAdapter</td><td><p>0x4d8aC89776B548356e30372521F4835fa67eD298 (Ethereum)</p><p></p><p>0x6ab918019D5F7C155AAb21b7Bd22c0aC7897b4c5 (Arbitrum)</p><p></p><p>0xe1CFEcD5292fa1e6B098cA85E10181E3675C7fa4 (Base)<br><br>0xBb3c2B36E8517E03515C08F8A31e2746649917f4 (HyperEVM)</p></td><td>Ensures transfers of assets via the Cross-chain Transfer Protocol by Circle are relayed securely</td></tr><tr><td>YoMayanAdapter</td><td>0xbAF91d1A64e9A86C400E3DEeA4Eb97Cf631252dA (Ethereum &#x26; Base)</td><td>Ensures transfers of assets via the Mayan protocol are relayed securely</td></tr><tr><td>YoCcipAdapter</td><td>0x41E2Ae2271FD724DB474fD8F25012DeAdF2ad39f (Ethereum)<br><br>0x66C55881460Db8878BE2AfFbA36A15434cb12382 (Base)</td><td>Ensures transfers of assets via the Cross-chain Interop Protocol by Chainlink are relayed securely</td></tr><tr><td>YoAcrossAdapter</td><td>0x4A7104BE83093C3e1520259DA83d02461d6C7876 (Ethereum)<br><br>0xed8E485c8e48917090830822Fa86465A2366f8cC (Base)</td><td>Ensures transfers of assets via the Across protocol are relayed securely</td></tr></tbody></table>

## YO token

| Contract                             | Address                                    |
| ------------------------------------ | ------------------------------------------ |
| YO token                             | 0x1925450f5e5fb974b0aae1f3408cf5286fbd1a72 |
| Mint authority                       | 0xAE11F170491EDF4a139e32386153936792A3D262 |
| Genesis airdrop wallet               | 0x3502a1Ad809a0D948c42Ae3e76B3893aB5bc38a5 |
| Genesis airdrop distributor contract | 0x18A381Ba65F56D00516EB93eCb5C480aBA9E6aEc |
| Ecosystem fund                       | 0xa978230949A0d877d8ef5F1492488945D975e61F |
| Community fund                       | 0x5457E23c1f339c38dd52FD75e64Af97162Def04C |
| Core contributors allocation         | 0x0c580Ba64C5c06E941AEB98E95509c48b32BE89b |
| Investor allocation                  | 0x73AF93301E42190e71ed0E65E06E300d63C7e07d |


# Risks

Like all DeFi protocols, YO isn’t risk-free. While YO is built to optimize for the best risk-adjusted yield, there are still risks to be aware of when depositing your crypto:

### Smart contract risk

YO vaults rely on smart contracts to operate. While we’ve taken every measure to secure the protocol, including audits and continuous monitoring, there’s always a risk of a bug or vulnerability in the code, whether in YO or in the underlying protocols we allocate to.

### Protocol risk

YO allocates your funds across a curated list of pools from vetted protocols, but every DeFi protocol comes with its own risks. These include things like oracle manipulation, bad debt, and governance exploits. We mitigate this by only investing in pools with solid fundamentals and by using [Exponential.fi’s Risk Ratings](https://exponential.fi/learn/risk-rating) to avoid protocols with excessive risk.

### Chain risk

YO is multi-chain, so it interacts with multiple blockchains. We are currently live on Ethereum and Base, with more chains coming soon. If a specific chain goes down, is congested, or suffers from a consensus failure, it may affect the vault performance.

### Liquidity risk

Most of the time, you can redeem your assets instantly. But if a large number of users want to exit at the same time or a vault has heavy exposure to less liquid pools, your withdrawal may be delayed for up to 24 hours as the protocol unwinds positions.

### Strategy risk

YO directs funds to a variety of pools and strategies. YO may run advanced DeFi strategies like automated carry trades or concentrated liquidity farming in order to generate higher yields. Underlying pools and strategies are all verifiable onchain. These pools and strategies can sometimes underperform or incur losses due to market volatility or execution lag.

### Bridging risk

Moving assets across chains involves bridging, which introduces another layer of risk. YO minimizes bridging risk by only rebalances when a better opportunity is confirmed. However, in the rare case that a bridge is compromised, funds could be at risk.

YO is designed to reduce your exposure to unnecessary risk, but it can’t eliminate risk entirely. That’s why we optimize for risk-adjusted yield—maximizing returns while keeping risk in check.

Exponential.fi has a comprehensive report of YO protocol here:

{% embed url="<https://exponential.fi/protocols/yo/8056939b-d456-48f7-8611-e14e31a6f8e7>" %}


# Insure yoUSD with OpenCover

Risk-conscious users can hold yoUSD through an OpenCover Covered Vault to protect their position against DeFi risks. Coverage begins automatically when you deposit and ends when you withdraw, with the premium streamed continuously from your yield. There is no upfront cost and no lock-in. Cover is provided through OpenCover, with claims managed end-to-end.&#x20;

🔗 Get covered → [opencover.com/vaults/yo](https://opencover.com/vaults/yo)

### ⚙️ How it Works

When you deposit into the Covered yoUSD vault, your position is automatically insured for as long as you hold it.

No Signup, No Upfront Cost: The cover premium is streamed continuously from the vault's yield, meaning you earn a slightly lower net APY in exchange for peace of mind.

Full Flexibility: You can withdraw at any time; coverage ends exactly when your position does.

Hands-off Claims: If a covered loss event occurs, OpenCover manages the claim and payout process end-to-end.

### 🛡 What's Covered

The Covered yoUSD vault protects deposits against core DeFi risks affecting the yoUSD strategy and its underlying lending markets, including:

* Smart Contract Exploits: Loss of funds due to a bug or vulnerability in the covered contracts.
* Oracle Failure & Manipulation: Faulty price feeds or deliberate price manipulation leading to loss.
* Liquidation Failure / Bad Debt: Failure of liquidations to clear positions correctly, resulting in socialized bad debt.
* Governance Attacks: A malicious upgrade forced through an on-chain governance mechanism.

Standard exclusions apply, including phishing, private key compromise, and normal market price movements. Check the Cover Terms for the full list.

### 📊 Coverage Scope & Sublimits

Coverage is subject to per-component sublimits, meaning the maximum payout attributable to any single underlying market is capped as a percentage of your Cover Amount:

**Yo Protocol: Up to 70% of the Cover Amount**

Each Underlying Morpho Market: Up to 70% of the Cover Amount (e.g., cbBTC/USDC, WETH/USDC, wstETH/USDC, cbETH/USDC across Base and Ethereum)

**OpenCover Covered Vault: Up to 100% of the Cover Amount**

A 4% deductible of the Cover Amount applies to all claims. Sublimits and deductibles are defined in the Annex.

### 📋 Key Details & Reference

* Covered Asset: yoUSD
* Covered Vault (Base): 0x428dEDa4f7A026d62A4eb93C856DB9AEB7Ea92d3
* Designated yoUSD Vault (Base): 0x0000000f2eb9f69274678c76222b35eec7588a65
* Deductible: 4% of Cover Amount
* Upfront Cost: None (premium streams from yield)
* Duration: None (runs from deposit to withdrawal)
* Claims: Managed end-to-end by OpenCover

### 🔗 Canonical Links

Reference UI / Get Covered → <https://opencover.com/vaults/yo>

Cover Terms (Policy) → <https://api.nexusmutual.io/v2/ipfs/QmUJFWdxC7UxQBJXatgkUmJstcb6Kb9erYfSanVkReeXhE>

Annex (yoUSD-specific) → <https://api.nexusmutual.io/v2/ipfs/QmZVVt9Qk4DBbpLuPMHG5tovZuj1JgW31wnRfP1BGB8Ldq>


# Security Audits

The YO protocol prioritizes user security through robust and comprehensive practices. Developed following the ERC4626 standard, yoVault incorporates rigorous access control via an authorization mechanism, restricting sensitive operations exclusively to trusted operators. This ensures meticulous management of user funds, significantly reducing potential risks.

Security audits from reputable firms, including Hunter Security and Offbeat Security, confirm the solidity of yoVault’s smart contract code. No critical or high-severity vulnerabilities were identified, demonstrating the protocol’s reliability and showing the team's proactive security approach.

YO integrates mechanisms such as asynchronous redemption requests, clear fee structures, and strict controls over asset balance updates. Additionally, the protocol automatically pauses operations if asset valuations deviate significantly, providing an extra protective layer against market volatility or unexpected events. These carefully designed features collectively uphold the highest standards of user fund security.

### Existing audits

**Core Protocol**

<table><thead><tr><th width="161.24609375">Auditor</th><th width="180.7890625">Date</th><th width="166.390625">Scope</th><th data-type="files">Report</th></tr></thead><tbody><tr><td>Offbeat Security</td><td>15 January 2025</td><td>yoVault</td><td><a href="/files/rSNEhEaQ8C7ieOHQni51">/files/rSNEhEaQ8C7ieOHQni51</a></td></tr><tr><td>Hunter Security</td><td>21 January 2025</td><td>yoVault</td><td><a href="/files/T2E4r1OUCBw4IQHGtiZH">/files/T2E4r1OUCBw4IQHGtiZH</a></td></tr><tr><td>Spearbit</td><td>29 May 2025</td><td>yoVault</td><td><a href="/files/FHIm4QnD7PdGQNs6Mxyx">/files/FHIm4QnD7PdGQNs6Mxyx</a></td></tr><tr><td>Aether Labs</td><td>23 October 2025</td><td>yoVaultSecondary</td><td><a href="/files/Y95BvJ6FT7kFtM3PXxel">/files/Y95BvJ6FT7kFtM3PXxel</a></td></tr><tr><td>Paladin</td><td>21 November 2025</td><td>yoVaultSecondary</td><td><a href="/files/xXRcdPsE9r1huECAAl22">/files/xXRcdPsE9r1huECAAl22</a></td></tr><tr><td>Aetheryc</td><td>1 December 2025</td><td>yoVaultV2</td><td><a href="/files/MmwY3xscQcLADB0lvYPS">/files/MmwY3xscQcLADB0lvYPS</a></td></tr><tr><td>Zellic</td><td>24 February 2026</td><td>yoVault Solana</td><td><a href="/files/SFba7rFlTp9t8m1a2qmU">/files/SFba7rFlTp9t8m1a2qmU</a></td></tr><tr><td>Accretion</td><td>13 April 2026</td><td>yoVault Solana</td><td><a href="/files/5kRNmdZQCvWp8fqiPzjH">/files/5kRNmdZQCvWp8fqiPzjH</a></td></tr></tbody></table>

**YoGateway**

<table><thead><tr><th width="163.26171875">Auditor</th><th width="173.96875">Date</th><th data-type="files">Report</th></tr></thead><tbody><tr><td>Aether Labs</td><td>20 August 2025</td><td><a href="/files/z1KhFc5MBDlMSv60yZqa">/files/z1KhFc5MBDlMSv60yZqa</a></td></tr><tr><td>Paladin</td><td>21 November 2025</td><td><a href="/files/xXRcdPsE9r1huECAAl22">/files/xXRcdPsE9r1huECAAl22</a></td></tr></tbody></table>

#### Onchain Adapters

<table><thead><tr><th width="163.26171875">Auditor</th><th width="173.96875">Date</th><th data-type="files">Report</th></tr></thead><tbody><tr><td>Cantina</td><td>05 June 2026</td><td><a href="/files/Je3g4A5QKd42HnAztWni">/files/Je3g4A5QKd42HnAztWni</a></td></tr><tr><td>Cantina</td><td>23 June 2026</td><td><a href="/files/X24sVINee4wHiSGlGR8n">/files/X24sVINee4wHiSGlGR8n</a></td></tr></tbody></table>


# Security Framework

<figure><img src="/files/89ppoMsGEU1tXm9S6eMO" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/V3ag8c3xiewMP1xr6p9c" alt=""><figcaption></figcaption></figure>


# Build with YO

One integration. Optimized, risk-adjusted yield across chains.

### Why YO? <a href="#why-yo" id="why-yo"></a>

DeFi yield shouldn’t be complicated. With YO, your users can plug into optimized on-chain yield through a single integration.

Whether you’re building a wallet, DeFi app, or protocol, YO helps you distribute, access, or integrate yield at scale. Funds, curators, and liquidity providers can also participate in exclusive opportunities and deploy capital across the YO ecosystem.

Join the YO ecosystem and build the next generation of yield together.

#### Get started

{% content-ref url="/pages/fo14G46FSgKcvySDDidO" %}
[Integration Guides](/integrations/integration-guides)
{% endcontent-ref %}

### What YO Provides <a href="#what-yo-provides" id="what-yo-provides"></a>

| User Benefit                | Powered by YO                                                                                            |
| --------------------------- | -------------------------------------------------------------------------------------------------------- |
| Multi-chain yield sources   | 🌐 Access yield from dozens of protocols & chains                                                        |
| Risk-adjusted strategies    | 🛡️ Optimized strategies using Exponential’s proven [risk framework](https://exponential.fi/whitepaper). |
| Automated rebalancing       | ⚡ No more chasing yield. YO rebalances daily                                                             |
| Non-custodial & Transparent | 🔍 Your users stay in control. All assets allocations visible on-chain.                                  |
| Unified access              | 1️⃣ One integration: simplified user experience                                                          |
| Revenue share               | 💰 Receive a portion of protocol performance fees                                                        |

### Case Highlight: TUYO

<figure><img src="/files/x2xkNadofpMHfvYUL0TC" alt=""><figcaption></figcaption></figure>

* Tuyo users moved +$1M into Earn in the first 2 weeks, with Earn users proving significantly more sticky and engaged.
* Earn TVL grew +50% week-over-week since integrating YO.
* With YO, Tuyo can offer best-in-class yield:
  * +4% APY uplift on USDC vs prior options
  * +3% APY uplift on ETH
  * The only EUR yield option currently available!

> “YO helped us convert more users into ‘long-term’ users. Earn users are more engaged and generally hold higher TVL.”— [@izqui9](https://x.com/izqui9), Co-founder at [Tuyo](https://tuyo.com/)

### Get in touch

{% embed url="<https://www.yo.xyz/build#start-integrating>" %}

### Alternative Integration Paths <a href="#integration" id="integration"></a>

<table data-header-hidden><thead><tr><th>Integration option</th><th>How it works</th><th>Best for</th><th data-hidden>Rev-share possible?</th></tr></thead><tbody><tr><td>Via <a href="https://docs.enso.build/">Enso</a></td><td>Cross-chain API that routes deposits in the most efficient way.</td><td>Apps that need cross-chain capabilities</td><td>❌</td></tr><tr><td>Via <a href="http://yield.xyz/">Yield.xyz</a></td><td>Abstracted access through routing + distribution layer. Faster go-live.</td><td>Apps and platforms that want yield “plug-in ready”</td><td>Requires a contract with yieldxyz</td></tr></tbody></table>


# Integration Guides

There are three ways to integrate YO into your dApp or protocol:&#x20;

1\) **SDK:** a simple Typescript toolkit that lets developers interact with YO  vaults from their own apps.&#x20;

{% content-ref url="/pages/628067bfc45bbeeb9f57d3cd239ae4a3465d7841" %}
[SDK](/integrations/integration-guides/sdk)
{% endcontent-ref %}

2\) **Widget:** a plug-and-play solution for apps to embed YO directly in their UX

{% embed url="<https://www.npmjs.com/package/@yo-protocol/widget-sdk>" %}

3\) y**oGateway:** an onchain interface to interact with all current and future yoVaults, with built-in tools for slippage and allowance management. Integrate with 1 contract instead of multiple individual interfaces.&#x20;

{% content-ref url="/pages/5ArS74Cet0964KiJS2Nh" %}
[yoGateway](/integrations/integration-guides/yogateway)
{% endcontent-ref %}

4\) **Individual Contracts:** if you prefer to integrate a single contract, you can do it as well. Vaults follow the ERC 4626 standard.&#x20;

{% content-ref url="/pages/AJ7PnYTnqS3OpvLnBwtX" %}
[Individual Contracts](/integrations/integration-guides/individual-contracts)
{% endcontent-ref %}


# SDK

A TypeScript SDK for the Yo yield protocol. Full ERC-4626 vault support with React hooks and multi-chain coverage.

```
npm install @yo-protocol/core viem
```

## Quick Links

* [Installation](/integrations/integration-guides/sdk/getting-started/installation) — Get set up with npm, pnpm, or yarn.
* [Quick Start](/integrations/integration-guides/sdk/getting-started/quickstart) — Build your first integration in minutes.
* [@yo-protocol/core](/integrations/integration-guides/sdk/core/overview) — Framework-agnostic TypeScript client.
* [@yo-protocol/react](/integrations/integration-guides/sdk/react/overview) — React hooks with wagmi and TanStack Query.
* [Guides](/integrations/integration-guides/sdk/guides/wagmi-setup) — Wagmi setup, Next.js SSR, error handling.
* [Examples](/integrations/integration-guides/sdk/examples) — Complete code examples and patterns.

## Features

* **ERC-4626 Vaults** — Deposit, withdraw, and redeem with full tokenized vault support.
* **Multi-Chain** — Native support for Ethereum and Base with unified APIs.
* **Type-Safe** — Zod-validated API responses and end-to-end TypeScript types.
* **Built on viem** — Low-level contract interactions via viem for reliability and performance.
* **React Hooks** — Automatic caching, refetching, and optimistic updates via TanStack Query.
* **Gateway Deposits** — Deposit any supported asset with built-in slippage protection.

## Supported Vaults

| Vault    | Underlying | Chains         |
| -------- | ---------- | -------------- |
| `yoETH`  | WETH       | Ethereum, Base |
| `yoBTC`  | cbBTC      | Base           |
| `yoUSD`  | USDC       | Base           |
| `yoEUR`  | EURC       | Base           |
| `yoGOLD` | XAUt       | Ethereum       |
| `yoUSDT` | USDT       | Ethereum       |


# Summary

## Getting Started

* [Introduction](/integrations/integration-guides/sdk)
* [Installation](/integrations/integration-guides/sdk/getting-started/installation)
* [Quick Start](/integrations/integration-guides/sdk/getting-started/quickstart)

## @yo-protocol/core

* [Overview](/integrations/integration-guides/sdk/core/overview)
* [Client](/integrations/integration-guides/sdk/core/client)
* [Vault Reads](/integrations/integration-guides/sdk/core/vault-reads)
* [Actions](/integrations/integration-guides/sdk/core/actions)
* [API Client](/integrations/integration-guides/sdk/core/api-client)
* [Constants](/integrations/integration-guides/sdk/core/constants)
* [Types](/integrations/integration-guides/sdk/core/types)

## @yo-protocol/react

* [Overview](/integrations/integration-guides/sdk/react/overview)
* [YieldProvider](/integrations/integration-guides/sdk/react/provider)
* [Hooks](/integrations/integration-guides/sdk/react/hooks/readme)
  * [useVault](/integrations/integration-guides/sdk/react/hooks/use-vault)
  * [useVaults](/integrations/integration-guides/sdk/react/hooks/use-vaults)
  * [useUserBalance](/integrations/integration-guides/sdk/react/hooks/use-user-balance)
  * [useDeposit](/integrations/integration-guides/sdk/react/hooks/use-deposit)
  * [useRedeem](/integrations/integration-guides/sdk/react/hooks/use-redeem)
  * [useApprove](/integrations/integration-guides/sdk/react/hooks/use-approve)
  * [useVaultHistory](/integrations/integration-guides/sdk/react/hooks/use-vault-history)
  * [usePendingRedemptions](/integrations/integration-guides/sdk/react/hooks/use-pending-redemptions)
* [YoKitProvider](/integrations/integration-guides/sdk/react/yo-kit-provider)

## Guides

* [Wagmi Setup](/integrations/integration-guides/sdk/guides/wagmi-setup)
* [Error Handling](/integrations/integration-guides/sdk/guides/error-handling)

## Resources

* [Examples](/integrations/integration-guides/sdk/examples)


# Getting Started


# Quickstart

## Using @yo-protocol/core

```ts
import { createYoClient } from '@yo-protocol/core'

const client = createYoClient({
  chainId: 8453, // Base
})

// Read vault state
const vault = await client.getVaultState('0x3a43aec53490cb9fa922847385d82fe25d0e9de7')
console.log(vault.name, vault.totalAssets)

// Get API snapshot (TVL, APY)
const snapshot = await client.getVaultSnapshot('0x3a43aec53490cb9fa922847385d82fe25d0e9de7')
console.log(`APY: ${snapshot.apy}%`)
```

## Using @yo-protocol/react

Wrap your app with the required providers, then use hooks:

```tsx
import { WagmiProvider } from 'wagmi'
import { QueryClientProvider, QueryClient } from '@tanstack/react-query'
import { YieldProvider } from '@yo-protocol/react'
import { config } from './wagmi'

const queryClient = new QueryClient()

function App({ children }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <YieldProvider>
          {children}
        </YieldProvider>
      </QueryClientProvider>
    </WagmiProvider>
  )
}
```

Then use hooks in your components:

```tsx
import { useVault, useDeposit } from '@yo-protocol/react'
import { parseEther } from 'viem'

function VaultPage() {
  const { vault, isLoading } = useVault('yoETH')
  const { deposit, isLoading: depositing } = useDeposit({ vault: 'yoETH' })

  if (isLoading) return <div>Loading...</div>

  return (
    <div>
      <h1>{vault?.name}</h1>
      <p>Total assets: {vault?.totalAssets.toString()}</p>
      <button
        onClick={() => deposit(parseEther('0.1'))}
        disabled={depositing}
      >
        Deposit 0.1 ETH
      </button>
    </div>
  )
}
```


# Installation

## Core Package

The core SDK works in any JavaScript environment — Node.js, browsers, serverless, or scripts.

```bash
pnpm add @yo-protocol/core viem
```

```bash
npm install @yo-protocol/core viem
```

```bash
yarn add @yo-protocol/core viem
```

| Dependency          | Purpose                                                          |
| ------------------- | ---------------------------------------------------------------- |
| `@yo-protocol/core` | Client, vault reads, actions, API client, constants              |
| `viem`              | Low-level EVM interaction (contract calls, encoding, transports) |

{% hint style="info" %}
**Zod included**

`@yo-protocol/core` bundles `zod` internally for runtime validation of API responses. You do not need to install it separately.
{% endhint %}

## React Package

For React apps using wagmi and TanStack Query:

```bash
pnpm add @yo-protocol/react @yo-protocol/core viem wagmi @tanstack/react-query
```

```bash
npm install @yo-protocol/react @yo-protocol/core viem wagmi @tanstack/react-query
```

```bash
yarn add @yo-protocol/react @yo-protocol/core viem wagmi @tanstack/react-query
```

### Peer Dependencies

| Package                 | Minimum version |
| ----------------------- | --------------- |
| `react`                 | 18.0.0          |
| `react-dom`             | 18.0.0          |
| `wagmi`                 | 2.0.0           |
| `viem`                  | 2.0.0           |
| `@tanstack/react-query` | 5.0.0           |

## TypeScript

Both packages ship with full TypeScript declarations. TypeScript 5.0+ is recommended but not required — the SDK works fine in plain JavaScript.

## Verify Installation

```ts
import { createYoClient } from '@yo-protocol/core'

const client = createYoClient({ chainId: 8453 })
const vaults = client.getVaults()

console.log(`Found ${vaults.length} vaults on Base`)
```

## Next Steps

* [Quick Start](broken://pages/cc26cc2ce5c3e110ce4caca32b7a263168920bd6) — Build your first integration
* [@yo-protocol/core Overview](file:///3007190/core/overview.md) — Core SDK reference
* [@yo-protocol/react Overview](file:///3007190/react/overview.md) — React hooks reference


# Core


# Overview

The framework-agnostic TypeScript SDK for the Yo yield protocol. Use it in any environment — Node.js, serverless functions, scripts, or the browser.

## What's Inside

| Module          | Purpose                                                                        |
| --------------- | ------------------------------------------------------------------------------ |
| **YoClient**    | Main entry point — wraps reads, actions, and API calls in a single interface   |
| **Vault reads** | On-chain state queries: vault state, balances, allowances, conversion previews |
| **Actions**     | Transaction builders: deposit via gateway, request withdrawal, redeem, approve |
| **API client**  | REST client for off-chain data: snapshots, APY/TVL timeseries, user history    |
| **Constants**   | Vault addresses, chain configs, contract ABIs                                  |

## Architecture

```
YoClient (entry point)
├── publicClient (viem) — On-chain reads
├── walletClient (viem) — Transaction signing
└── apiClient (fetch) — REST API calls
```

The client is initialized with a `chainId` and optional viem clients. If no `publicClient` is provided, one is created automatically via `http()` transport.

## Quick Example

```ts
import { createYoClient, VAULTS } from '@yo-protocol/core'

// 1 — Create a client targeting Base
const client = createYoClient({ chainId: 8453 })

// 2 — Read on-chain vault state
const state = await client.getVaultState(VAULTS.yoETH.address)
console.log(state.name, state.totalAssets)

// 3 — Fetch off-chain snapshot (TVL, APY, pools)
const snapshot = await client.getVaultSnapshot(VAULTS.yoETH.address)
console.log(`APY: ${snapshot.apy}%`, `TVL: $${snapshot.tvl}`)
```

{% hint style="info" %}
**No framework required**

`@yo-protocol/core` has zero React or DOM dependencies. It works anywhere that supports `fetch` and `BigInt` — backend services, CLI tools, scripts, or browsers.
{% endhint %}

## Chains

| Chain    | Chain ID | Status    |
| -------- | -------- | --------- |
| Ethereum | `1`      | Supported |
| Base     | `8453`   | Supported |

## Next Steps

* [Client](broken://pages/9d7260e75dd75f06619208e7e14336dbf6509033) — Creating and configuring YoClient
* [Vault Reads](broken://pages/d68e3d414b4e85e74716da059762a410642e5b70) — Querying on-chain vault state
* [Actions](broken://pages/c0d48baa517ce45149c5d9a002ad6e0e80295eb2) — Building deposit, withdraw, and approve transactions
* [API Client](broken://pages/5ca6b1a45df09b8899f1089e56c0b4869ca537e3) — Fetching snapshots, timeseries, and user history
* [Constants](broken://pages/316177dbbaa039279d32a4e39dff04638fd16ee6) — Vault addresses and chain configs
* [Types](broken://pages/058f9022a1a38cb759535b76991f8cc6fb77704b) — Full type reference


# Actions

Transaction-building functions that require a `walletClient` on the `YoClient`.

## Deposit

Deposits assets into a vault via the Yo Gateway contract. Uses `quotePreviewDeposit` to calculate slippage protection.

```ts
const result = await client.deposit({
  vault: '0x3a43aec...',
  amount: parseEther('1'),
  slippageBps: 50,       // 0.5% slippage (optional, default: 50)
  recipient: account,    // optional, defaults to signer
})

console.log(result.hash)   // transaction hash
console.log(result.shares) // expected shares
```

## Redeem

Redeems vault shares for underlying assets via the Yo Gateway. Uses `quotePreviewRedeem` to calculate slippage protection.

```ts
const result = await client.redeem({
  vault: vaultAddress,
  shares: parseEther('10'),
  slippageBps: 50,         // optional, default: 50
  recipient: account,      // optional, defaults to signer
  minAssetsOut: 0n,        // optional, overrides slippageBps
})

console.log(result.hash)
console.log(result.assets) // expected assets
```

## Approve

Approves token spending. Defaults to the Yo Gateway as spender.

```ts
// Approve specific amount
await client.approve(tokenAddress, parseEther('10'))

// Approve max
await client.approveMax(tokenAddress)

// Custom spender
await client.approve(tokenAddress, parseEther('10'), spenderAddress)
```

## Deposit with Approval

Checks allowance and approves if needed before depositing — all in one call.

```ts
const result = await client.depositWithApproval({
  vault: vaultAddress,
  token: underlyingTokenAddress,
  amount: parseUnits('100', 6),
  slippageBps: 50,
})

console.log(result.approveHash)  // undefined if approval wasn't needed
console.log(result.depositHash)
console.log(result.shares)
```

## Prepared Transactions

Build `{ to, data, value }` call data without executing. Useful for AA wallet bundling or custom transaction flows.

```ts
import { createYoClient } from '@yo-protocol/core'

const client = createYoClient({ chainId: 8453 })

// Build approve call data
const approveTx = client.prepareApprove({
  token: underlyingTokenAddress,
  amount: parseUnits('100', 6),
})

// Build deposit call data (needs RPC for preview quote)
const depositTx = await client.prepareDeposit({
  vault: vaultAddress,
  amount: parseUnits('100', 6),
})

// Build redeem call data
const redeemTx = await client.prepareRedeem({
  vault: vaultAddress,
  shares: parseEther('10'),
})

// Build approve + deposit bundle (checks allowance, returns 1 or 2 txs)
const bundle = await client.prepareDepositWithApproval({
  vault: vaultAddress,
  token: underlyingTokenAddress,
  owner: accountAddress,
  amount: parseUnits('100', 6),
})

// Send via AA wallet bundler
await bundler.sendBundle(bundle.map(tx => ({
  to: tx.to,
  data: tx.data,
  value: tx.value,
})))
```

## Transaction Confirmation

Wait for transaction confirmation and decode events.

```ts
// General-purpose wait
const receipt = await client.waitForTransaction(hash)
console.log(receipt.status)      // 'success' | 'reverted'
console.log(receipt.blockNumber)

// Redeem-specific: decodes the YoGatewayRedeem event
const redeemReceipt = await client.waitForRedeemReceipt(hash)
console.log(redeemReceipt.instant)           // true if redeemed instantly
console.log(redeemReceipt.assetsOrRequestId) // assets returned or pending request ID
console.log(redeemReceipt.shares)            // shares redeemed
```


# Types

All TypeScript types exported from `@yo-protocol/core`.

## Client Config

```ts
interface YoClientConfig {
  chainId: SupportedChainId  // 1 | 8453
  publicClient?: PublicClient
  walletClient?: WalletClient
  partnerId?: number          // Gateway partner attribution ID (default: 0)
}
```

## Vault Types

```ts
interface VaultState {
  address: Address
  name: string
  symbol: string
  decimals: number
  totalAssets: bigint
  totalSupply: bigint
  asset: Address
  assetDecimals: number
  exchangeRate: bigint
}

interface VaultConfig {
  address: Address
  name: string
  symbol: VaultId
  underlying: {
    symbol: string
    decimals: number
    address: Record<number, Address>
  }
  chains: readonly number[]
}

type VaultId = 'yoETH' | 'yoBTC' | 'yoUSD' | 'yoEUR' | 'yoGOLD' | 'yoUSDT'
```

## User Types

```ts
interface UserVaultPosition {
  shares: bigint
  assets: bigint
}

interface TokenBalance {
  token: Address
  balance: bigint
  decimals: number
}

interface TokenAllowance {
  token: Address
  owner: Address
  spender: Address
  allowance: bigint
}
```

## Action Results

```ts
interface DepositResult {
  hash: Hash
  shares: bigint
}

interface RedeemResult {
  hash: Hash
  assets: bigint
}

interface ApproveResult {
  hash: Hash
}

interface DepositWithApprovalResult {
  approveHash?: Hash    // undefined if approval wasn't needed
  depositHash: Hash
  shares: bigint
}

interface RedeemReceipt {
  hash: Hash
  status: 'success' | 'reverted'
  instant: boolean               // true if redeemed instantly
  assetsOrRequestId: bigint      // assets returned or pending request ID
  shares: bigint
  blockNumber: bigint
}

interface TransactionReceipt {
  hash: Hash
  status: 'success' | 'reverted'
  blockNumber: bigint
  gasUsed: bigint
}

interface PreparedTransaction {
  to: Address
  data: Hex
  value: bigint
}
```

## Action Params

```ts
interface DepositParams {
  vault: Address
  amount: bigint
  recipient?: Address
  minShares?: bigint
}

interface RedeemParams {
  vault: Address
  shares: bigint
  recipient?: Address
  minAssetsOut?: bigint
  slippageBps?: number
}
```

## API Types

```ts
type Network = 'base' | 'ethereum' | 'unichain' | 'arbitrum' | 'tac' | 'plasma' | 'hyperevm'

interface FormattedValue {
  raw: number | string
  formatted: string
}

interface VaultSnapshot {
  address: string
  name: string
  symbol: string
  tvl: FormattedValue
  apy: number
  underlying: { address: string; symbol: string; decimals: number }
  pools?: { name: string; allocation: number; apy: number }[]
}

interface TimeseriesPoint {
  timestamp: number
  value: number
}

interface UserHistoryItem {
  type: 'deposit' | 'withdraw' | 'redeem'
  timestamp: number
  assets: FormattedValue
  shares: FormattedValue
  txHash: string
}

interface UserPoints {
  totalPoints: number
  rank?: number
  activities?: { type: string; points: number; timestamp: number }[]
}

interface PendingRedeem {
  assets?: FormattedValue
  shares?: FormattedValue
}
```


# API client

The `ApiClient` provides access to off-chain data from the Yo REST API (`https://api.yo.xyz`).

## Usage via YoClient

The `YoClient` creates an `ApiClient` internally:

```ts
const client = createYoClient({ chainId: 8453 })

const snapshot = await client.getVaultSnapshot(vaultAddress)
const yieldHistory = await client.getVaultYieldHistory(vaultAddress)
const tvlHistory = await client.getVaultTvlHistory(vaultAddress)
const userHistory = await client.getUserHistory(vaultAddress, userAddress, 50)
const points = await client.getUserPoints(userAddress)
```

## Standalone Usage

```ts
import { createApiClient } from '@yo-protocol/core'

const api = createApiClient()
// or with custom base URL:
const api = createApiClient({ baseUrl: 'https://custom-api.example.com' })
```

## Pending Redemptions

Query pending async redemptions for a user or an entire vault.

```ts
// User-specific pending redemptions
const pending = await client.getPendingRedemptions(vaultAddress, userAddress)
console.log(pending.assets?.formatted)  // e.g. "100.50"
console.log(pending.shares?.formatted)  // e.g. "95.20"

// Vault-level pending redeems
const vaultPending = await client.getVaultPendingRedeems(vaultAddress)
```

### PendingRedeem

| Field    | Type                          | Description          |
| -------- | ----------------------------- | -------------------- |
| `assets` | `FormattedValue \| undefined` | Pending asset amount |
| `shares` | `FormattedValue \| undefined` | Pending share amount |

## Response Types

### VaultSnapshot

| Field        | Type             | Description               |
| ------------ | ---------------- | ------------------------- |
| `address`    | `string`         | Vault address             |
| `name`       | `string`         | Vault name                |
| `symbol`     | `string`         | Vault symbol              |
| `tvl`        | `FormattedValue` | Total value locked        |
| `apy`        | `number`         | Current APY percentage    |
| `underlying` | `object`         | Underlying token info     |
| `pools`      | `Pool[]`         | Optional pool allocations |

### TimeseriesPoint

| Field       | Type     | Description      |
| ----------- | -------- | ---------------- |
| `timestamp` | `number` | Unix timestamp   |
| `value`     | `number` | APY or TVL value |

### UserHistoryItem

| Field       | Type                                  | Description      |
| ----------- | ------------------------------------- | ---------------- |
| `type`      | `'deposit' \| 'withdraw' \| 'redeem'` | Transaction type |
| `timestamp` | `number`                              | Unix timestamp   |
| `assets`    | `FormattedValue`                      | Asset amount     |
| `shares`    | `FormattedValue`                      | Share amount     |
| `txHash`    | `string`                              | Transaction hash |

### Error Handling

API errors throw `ApiError` with a `statusCode` property:

```ts
import { ApiError } from '@yo-protocol/core'

try {
  await client.getVaultSnapshot(address)
} catch (err) {
  if (err instanceof ApiError) {
    console.error(err.statusCode, err.message)
  }
}
```


# Vault Reads

On-chain read functions for querying vault state, balances, and allowances.

## Vault State

```ts
const state = await client.getVaultState(vaultAddress)
```

Returns a `VaultState` object:

| Field           | Type      | Description                              |
| --------------- | --------- | ---------------------------------------- |
| `address`       | `Address` | Vault contract address                   |
| `name`          | `string`  | Vault name (e.g., "YO ETH Vault")        |
| `symbol`        | `string`  | Vault symbol (e.g., "yoETH")             |
| `decimals`      | `number`  | Vault share decimals                     |
| `totalAssets`   | `bigint`  | Total assets under management            |
| `totalSupply`   | `bigint`  | Total shares issued                      |
| `asset`         | `Address` | Underlying asset address                 |
| `assetDecimals` | `number`  | Underlying asset decimals                |
| `exchangeRate`  | `bigint`  | Current exchange rate (shares per asset) |

## Preview Functions

```ts
// How many shares will I get for 1 ETH?
const shares = await client.previewDeposit(vault, parseEther('1'))

// How many assets will I get for 100 shares?
const assets = await client.previewRedeem(vault, 100n)

// Conversion helpers
const assetsFromShares = await client.convertToAssets(vault, shares)
const sharesFromAssets = await client.convertToShares(vault, parseEther('1'))
```

## Gateway Quote Functions

Quote functions read from the Yo Gateway contract and account for fees and routing.

```ts
// Gateway-aware previews
const shares = await client.quotePreviewDeposit(vault, parseEther('1'))
const assets = await client.quotePreviewRedeem(vault, shares)
const sharesNeeded = await client.quotePreviewWithdraw(vault, parseEther('1'))

// Gateway-aware conversions
const assetsOut = await client.quoteConvertToAssets(vault, shares)
const sharesOut = await client.quoteConvertToShares(vault, parseEther('1'))
```

## Balance Queries

```ts
// ERC-20 token balance
const { balance, decimals } = await client.getTokenBalance(tokenAddress, account)

// Vault share balance
const shares = await client.getShareBalance(vaultAddress, account)

// Full user position
const position = await client.getUserPosition(vaultAddress, account)
// position.shares, position.assets
```

## Allowance Queries

```ts
// ERC-20 allowance
const allowance = await client.getAllowance(token, owner, spender)
const sufficient = await client.hasEnoughAllowance(token, owner, spender, amount)

// Gateway-specific allowance helpers
const shareAllowance = await client.getShareAllowance(vault, owner)
const assetAllowance = await client.getAssetAllowance(vault, owner)
```


# Constants

Exported contract addresses, vault configs, and chain information. All constants are fully typed and tree-shakeable.

## Contract Addresses

```ts
import {
  YO_GATEWAY_ADDRESS,
  VAULT_REGISTRY_ADDRESS,
  YO_ORACLE_ADDRESS,
  REDEEMER_ADDRESS,
} from '@yo-protocol/core'
```

| Constant                 | Description               | Address        |
| ------------------------ | ------------------------- | -------------- |
| `YO_GATEWAY_ADDRESS`     | Deposit gateway router    | `0xF1EeE…69FA` |
| `VAULT_REGISTRY_ADDRESS` | On-chain vault registry   | `0x56c31…2232` |
| `YO_ORACLE_ADDRESS`      | Price oracle              | `0x6E879…96B0` |
| `REDEEMER_ADDRESS`       | Async withdrawal redeemer | `0x0439e…2162` |

{% hint style="info" %}
**Checksummed**

All address constants are checksummed `0x${string}` literals — they work directly with viem without additional formatting.
{% endhint %}

## Vault Registry

The `VAULTS` object exposes every supported vault with its address, underlying token, and available chains.

```ts
import { VAULTS } from '@yo-protocol/core'

VAULTS.yoETH.address            // '0x3a43aec...'
VAULTS.yoETH.underlying.symbol  // 'WETH'
VAULTS.yoETH.chains             // [1, 8453]
VAULTS.yoUSD.chains             // [8453]
```

### Available Vaults

| ID       | Underlying | Chains         |
| -------- | ---------- | -------------- |
| `yoETH`  | WETH       | Ethereum, Base |
| `yoBTC`  | cbBTC      | Base           |
| `yoUSD`  | USDC       | Base           |
| `yoEUR`  | EURC       | Base           |
| `yoGOLD` | XAUt       | Ethereum       |
| `yoUSDT` | USDT       | Ethereum       |

Each vault entry includes:

| Property              | Type       | Description                     |
| --------------------- | ---------- | ------------------------------- |
| `address`             | `Address`  | Vault contract address          |
| `underlying.address`  | `Address`  | Underlying ERC-20 token address |
| `underlying.symbol`   | `string`   | Token symbol                    |
| `underlying.decimals` | `number`   | Token decimals                  |
| `chains`              | `number[]` | Supported chain IDs             |

## Chain Helpers

```ts
import {
  SUPPORTED_CHAINS,
  SUPPORTED_CHAIN_IDS,
  isSupportedChain,
  getChain,
} from '@yo-protocol/core'

SUPPORTED_CHAIN_IDS  // [1, 8453]

isSupportedChain(8453) // true
isSupportedChain(137)  // false

const chain = getChain(8453)  // viem Chain object for Base
```

| Export                 | Type                      | Description                      |
| ---------------------- | ------------------------- | -------------------------------- |
| `SUPPORTED_CHAINS`     | `Chain[]`                 | Array of viem chain objects      |
| `SUPPORTED_CHAIN_IDS`  | `number[]`                | `[1, 8453]`                      |
| `isSupportedChain(id)` | `(id: number) => boolean` | Check if a chain ID is supported |
| `getChain(id)`         | `(id: number) => Chain`   | Get viem chain object by ID      |


# Client

The `YoClient` class is the main entry point for `@yo-protocol/core`. It wraps all vault reads, actions, and API calls.

## Creating a Client

```ts
import { createYoClient } from '@yo-protocol/core'

// Minimal — auto-creates a publicClient
const client = createYoClient({ chainId: 8453 })

// With partner ID and custom viem clients
import { createPublicClient, http } from 'viem'
import { base } from 'viem/chains'

const client = createYoClient({
  chainId: 8453,
  partnerId: 42,
  publicClient: createPublicClient({ chain: base, transport: http() }),
  walletClient: myWalletClient,
})
```

## Config

| Property       | Type           | Description                                                    |
| -------------- | -------------- | -------------------------------------------------------------- |
| `chainId`      | `1 \| 8453`    | Ethereum (1) or Base (8453)                                    |
| `publicClient` | `PublicClient` | Optional viem public client                                    |
| `walletClient` | `WalletClient` | Optional viem wallet client (needed for transactions)          |
| `partnerId`    | `number`       | Optional partner attribution ID for gateway calls (default: 0) |

## Methods

### Vault Reads

| Method                           | Returns         | Description                                                  |
| -------------------------------- | --------------- | ------------------------------------------------------------ |
| `getVaults()`                    | `VaultConfig[]` | List vaults for the current chain                            |
| `getVaultState(vault)`           | `VaultState`    | On-chain vault state (name, totalAssets, exchangeRate, etc.) |
| `previewDeposit(vault, assets)`  | `bigint`        | Preview shares received for a deposit                        |
| `previewRedeem(vault, shares)`   | `bigint`        | Preview assets received for a redemption                     |
| `convertToAssets(vault, shares)` | `bigint`        | Convert share amount to assets                               |
| `convertToShares(vault, assets)` | `bigint`        | Convert asset amount to shares                               |

### Gateway Quote Reads

| Method                                | Returns  | Description                                    |
| ------------------------------------- | -------- | ---------------------------------------------- |
| `quotePreviewDeposit(vault, assets)`  | `bigint` | Gateway-aware deposit preview                  |
| `quotePreviewRedeem(vault, shares)`   | `bigint` | Gateway-aware redeem preview                   |
| `quotePreviewWithdraw(vault, assets)` | `bigint` | Gateway-aware withdraw preview (shares needed) |
| `quoteConvertToAssets(vault, shares)` | `bigint` | Gateway-aware share-to-asset conversion        |
| `quoteConvertToShares(vault, assets)` | `bigint` | Gateway-aware asset-to-share conversion        |

### Balance Reads

| Method                            | Returns             | Description                    |
| --------------------------------- | ------------------- | ------------------------------ |
| `getTokenBalance(token, account)` | `TokenBalance`      | ERC-20 balance                 |
| `getShareBalance(vault, account)` | `bigint`            | Vault share balance            |
| `getUserPosition(vault, account)` | `UserVaultPosition` | Full position (shares, assets) |

### Allowance Reads

| Method                                              | Returns          | Description                      |
| --------------------------------------------------- | ---------------- | -------------------------------- |
| `getAllowance(token, owner, spender)`               | `TokenAllowance` | Current ERC-20 allowance         |
| `hasEnoughAllowance(token, owner, spender, amount)` | `boolean`        | Check if allowance is sufficient |
| `getShareAllowance(vault, owner)`                   | `bigint`         | Gateway share allowance          |
| `getAssetAllowance(vault, owner)`                   | `bigint`         | Gateway asset allowance          |

### Actions (require walletClient)

| Method                             | Returns                     | Description                                    |
| ---------------------------------- | --------------------------- | ---------------------------------------------- |
| `deposit(params)`                  | `DepositResult`             | Deposit assets via gateway                     |
| `redeem(params)`                   | `RedeemResult`              | Redeem shares for assets via gateway           |
| `approve(token, amount, spender?)` | `ApproveResult`             | Approve token spending                         |
| `approveMax(token, spender?)`      | `ApproveResult`             | Approve max uint256                            |
| `depositWithApproval(params)`      | `DepositWithApprovalResult` | Approve (if needed) + deposit in one call      |
| `waitForTransaction(hash)`         | `TransactionReceipt`        | Wait for transaction confirmation              |
| `waitForRedeemReceipt(hash)`       | `RedeemReceipt`             | Wait + decode instant/requestId from redeem tx |

### Prepared Transactions (call data mode)

| Method                               | Returns                 | Description                                 |
| ------------------------------------ | ----------------------- | ------------------------------------------- |
| `prepareApprove(params)`             | `PreparedTransaction`   | Build approve call data without executing   |
| `prepareDeposit(params)`             | `PreparedTransaction`   | Build deposit call data without executing   |
| `prepareRedeem(params)`              | `PreparedTransaction`   | Build redeem call data without executing    |
| `prepareDepositWithApproval(params)` | `PreparedTransaction[]` | Build approve+deposit bundle for AA wallets |

### API Methods

| Method                                | Returns              | Description                          |
| ------------------------------------- | -------------------- | ------------------------------------ |
| `getVaultSnapshot(vault)`             | `VaultSnapshot`      | Off-chain snapshot (TVL, APY, pools) |
| `getVaultYieldHistory(vault)`         | `TimeseriesPoint[]`  | Historical APY timeseries            |
| `getVaultTvlHistory(vault)`           | `TimeseriesPoint[]`  | Historical TVL timeseries            |
| `getUserHistory(vault, user, limit?)` | `UserHistoryItem[]`  | User transaction history             |
| `getUserPoints(user)`                 | `UserPoints \| null` | User points and rank                 |
| `getPendingRedemptions(vault, user)`  | `PendingRedeem`      | User pending redemptions             |
| `getVaultPendingRedeems(vault)`       | `PendingRedeem`      | Vault-level pending redeems          |


# React


# YO Kit Provider

`YoKitProvider` is an optional theming provider for the pre-built UI components in `@yo-protocol/react` (VaultCard, DepositModal, RedeemModal).

## Usage

```tsx
import { YoKitProvider } from '@yo-protocol/react'

// Use a preset theme
<YoKitProvider theme="dark">
  <App />
</YoKitProvider>

// Or customize the theme
<YoKitProvider theme={{
  colors: {
    primary: '#6366f1',
    background: '#0f0f0f',
  },
}}>
  <App />
</YoKitProvider>
```

## Props

| Prop       | Type                                       | Default  | Description                      |
| ---------- | ------------------------------------------ | -------- | -------------------------------- |
| `children` | `ReactNode`                                | —        | Required                         |
| `theme`    | `'light' \| 'dark' \| Partial<YoKitTheme>` | `'dark'` | Theme preset or custom overrides |

## Theme Object

When providing a custom theme, you can override any subset of:

```ts
interface YoKitTheme {
  colors: Record<string, string>
  radii: Record<string, string>
  fonts: Record<string, string>
  shadows: Record<string, string>
}
```

Custom themes are merged on top of the dark theme defaults.

## How It Works

`YoKitProvider` injects a `<style>` tag with CSS custom properties into the document head. The pre-built components reference these variables for styling.

This is separate from the docs-site theme (managed by `next-themes`). You only need `YoKitProvider` if you use the pre-built UI components.


# Overview

React hooks and providers for the Yo yield protocol, built on `@yo-protocol/core`, wagmi, and TanStack Query.

## Key Concepts

| Concept           | Description                                                                                                                                             |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **YieldProvider** | Context provider that creates and exposes a `YoClient`. Must sit inside `WagmiProvider` and `QueryClientProvider`.                                      |
| **Read hooks**    | `useVault`, `useVaults`, `useUserBalance`, `useVaultHistory` — backed by TanStack Query with automatic caching, refetching, and stale-while-revalidate. |
| **Action hooks**  | `useDeposit`, `useRedeem`, `useApprove` — mutation-style hooks with loading, error, and transaction confirmation tracking.                              |
| **YoKitProvider** | Optional theming provider for pre-built UI components.                                                                                                  |

## Setup

```tsx
import { WagmiProvider } from 'wagmi'
import { QueryClientProvider, QueryClient } from '@tanstack/react-query'
import { YieldProvider } from '@yo-protocol/react'
import { config } from './wagmi'

const queryClient = new QueryClient()

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <YieldProvider>
          {children}
        </YieldProvider>
      </QueryClientProvider>
    </WagmiProvider>
  )
}
```

{% hint style="warning" %}
**Provider order matters**

`YieldProvider` must be nested inside both `WagmiProvider` and `QueryClientProvider`. It reads the wagmi config and query client from context.
{% endhint %}

## Usage Example

```tsx
import { useVault, useDeposit } from '@yo-protocol/react'
import { parseEther } from 'viem'

function DepositCard() {
  const { vault, isLoading } = useVault('yoETH')
  const { deposit, isPending, isSuccess } = useDeposit({ vault: 'yoETH' })

  if (isLoading) return <p>Loading vault...</p>

  return (
    <div>
      <h2>{vault?.name}</h2>
      <p>Total assets: {vault?.totalAssets.toString()}</p>
      <button onClick={() => deposit(parseEther('0.1'))} disabled={isPending}>
        {isPending ? 'Depositing...' : 'Deposit 0.1 ETH'}
      </button>
      {isSuccess && <p>Deposit confirmed!</p>}
    </div>
  )
}
```

## Exports

### Providers

| Export           | Description                                                  |
| ---------------- | ------------------------------------------------------------ |
| `YieldProvider`  | Core context provider — creates `YoClient` from wagmi config |
| `useYoClient`    | Access the underlying `YoClient` instance                    |
| `useYieldConfig` | Access the provider configuration                            |
| `YoKitProvider`  | Optional theming provider for pre-built UI                   |

### Read Hooks

| Hook                     | Returns                         | Description                      |
| ------------------------ | ------------------------------- | -------------------------------- |
| `useVault(name)`         | `{ vault, isLoading, error }`   | Single vault state + snapshot    |
| `useVaults()`            | `{ vaults, isLoading, error }`  | All vaults for the current chain |
| `useUserBalance(vault)`  | `{ balance, isLoading, error }` | Connected user's vault position  |
| `useVaultHistory(vault)` | `{ history, isLoading, error }` | APY and TVL timeseries data      |

### Action Hooks

| Hook                    | Returns                                    | Description                          |
| ----------------------- | ------------------------------------------ | ------------------------------------ |
| `useDeposit({ vault })` | `{ deposit, isPending, isSuccess, error }` | Deposit assets via gateway           |
| `useRedeem({ vault })`  | `{ redeem, isPending, isSuccess, error }`  | Redeem shares for assets via gateway |
| `useApprove({ token })` | `{ approve, isPending, isSuccess, error }` | Approve token spending               |

## Next Steps

* [YieldProvider](broken://pages/6d0d2f8b4e967cf9c46c81d304aa74a01b0d9bf2) — Provider configuration and options
* [Hooks Reference](broken://pages/f3be6a35f60074357529ed440efb10df8091a499) — Full hook API reference starting with useVault
* [Wagmi Setup](file:///3007190/guides/wagmi-setup.md) — Configuring wagmi for use with @yield


# Provider

The `YieldProvider` creates the context required for all `@yo-protocol/react` hooks.

## Usage

```tsx
import { YieldProvider } from '@yo-protocol/react'

<YieldProvider
  partnerId="my-app"
  defaultSlippageBps={50}
  onError={(error) => console.error(error)}
>
  {children}
</YieldProvider>
```

## Props

| Prop                 | Type                     | Default     | Description                                  |
| -------------------- | ------------------------ | ----------- | -------------------------------------------- |
| `children`           | `ReactNode`              | —           | Required                                     |
| `partnerId`          | `string`                 | `undefined` | Optional partner identifier                  |
| `defaultSlippageBps` | `number`                 | `50`        | Default slippage in basis points (50 = 0.5%) |
| `onError`            | `(error: Error) => void` | `undefined` | Global error handler for action hooks        |

## Placement

`YieldProvider` must be placed **inside** `WagmiProvider` and `QueryClientProvider`:

```tsx
<WagmiProvider config={config}>
  <QueryClientProvider client={queryClient}>
    <YieldProvider>           {/* ← here */}
      <App />
    </YieldProvider>
  </QueryClientProvider>
</WagmiProvider>
```

## Related Hooks

* `useYoClient()` — Returns the `YoClient` instance (or `null` if not ready)
* `useYieldConfig()` — Returns `{ partnerId, defaultSlippageBps, onError }`


# Hooks


# README

`@yo-protocol/react` provides two categories of hooks:

**Read hooks** — backed by TanStack Query with automatic caching, refetching, and stale-while-revalidate:

* [useVault](broken://pages/9109e754e9fdc319af8bab6c9a35faa38a7cb4e6) — Single vault state + snapshot
* [useVaults](broken://pages/9c0627ef7f225a1cab0fd5fafc12a234c1ff8e22) — All vaults for the current chain
* [useUserBalance](broken://pages/62a2d76d1e9b8fc7c8dec24d33154aa1ac3f35a2) — Connected user's vault position
* [useVaultHistory](broken://pages/870d3d2fa9d398f5bc7d676f982d0fe873e10608) — APY and TVL timeseries data

**Action hooks** — mutation-style hooks with loading, error, and transaction confirmation tracking:

* [useDeposit](broken://pages/09392f3ad639911e45efd9b00a2cb7ac84d5e56a) — Deposit assets via gateway
* [useRedeem](broken://pages/f84f3b0d8a9be45a60a07f55ee55cefe8a2811f0) — Redeem shares for assets via gateway
* [useApprove](broken://pages/4603efa0d6ec049f211a87ef47ad36e5fb912db9) — Approve token spending

**Query hooks:**

* [usePendingRedemptions](broken://pages/0ddc9f7ef24f66b2c8e7cb1da87283409ded4ee2) — Pending async redemptions for a user


# use vault

Fetches on-chain vault state and off-chain snapshot data with automatic caching and background refetching.

```tsx
const { vault, isLoading, isError, error, refetch } = useVault('yoETH')
```

## Usage

```tsx
import { useVault } from '@yo-protocol/react'

function VaultInfo() {
  const { vault, isLoading, isError, error, refetch } = useVault('yoETH')

  if (isLoading) return <p>Loading vault...</p>
  if (isError) return <p>Error: {error?.message}</p>

  return (
    <div>
      <h2>{vault?.name}</h2>
      <p>Total Assets: {vault?.totalAssets.toString()}</p>
      <p>Exchange Rate: {vault?.exchangeRate.toString()}</p>
      <button onClick={() => refetch()}>Refresh</button>
    </div>
  )
}
```

## Parameters

| Parameter | Type                 | Required | Description                                            |
| --------- | -------------------- | -------- | ------------------------------------------------------ |
| `vault`   | `Address \| VaultId` | Yes      | Vault address or named ID (`'yoETH'`, `'yoUSD'`, etc.) |

## Return Value

| Field       | Type                      | Description                                                                         |
| ----------- | ------------------------- | ----------------------------------------------------------------------------------- |
| `vault`     | `VaultState \| undefined` | On-chain vault state including `name`, `totalAssets`, `exchangeRate`, `totalSupply` |
| `isLoading` | `boolean`                 | `true` while the initial fetch is in progress                                       |
| `isError`   | `boolean`                 | `true` if the query failed                                                          |
| `error`     | `Error \| null`           | Error object if the query failed                                                    |
| `refetch`   | `() => void`              | Manually trigger a refetch                                                          |

## Caching

| Setting           | Value | Description                             |
| ----------------- | ----- | --------------------------------------- |
| `staleTime`       | 30s   | Data is considered fresh for 30 seconds |
| `refetchInterval` | 60s   | Background refetch every 60 seconds     |

{% hint style="info" %}
**Automatic updates**

After a successful `useDeposit` or `useRedeem` transaction, the `useVault` query is automatically invalidated so the UI reflects the latest state without a manual refetch.
{% endhint %}


# use deposit

Mutation hook for depositing assets into a vault via the gateway contract, with transaction tracking and automatic query invalidation.

```tsx
const { deposit, isPending, isSuccess, hash } = useDeposit({ vault: 'yoETH' })
```

## Usage

```tsx
import { useDeposit } from '@yo-protocol/react'
import { parseEther } from 'viem'

function DepositButton() {
  const {
    deposit,
    isPending,
    isSuccess,
    hash,
    error,
    reset,
  } = useDeposit({
    vault: 'yoETH',
    slippageBps: 50,
    onSubmitted: (hash) => console.log('Deposited:', hash),
    onError: (err) => console.error(err),
  })

  return (
    <div>
      <button onClick={() => deposit(parseEther('0.1'))} disabled={isPending}>
        {isPending ? 'Depositing...' : 'Deposit 0.1 ETH'}
      </button>

      {isSuccess && <p>Confirmed! Tx: {hash}</p>}
      {error && (
        <p>
          Error: {error.message}
          <button onClick={reset}>Dismiss</button>
        </p>
      )}
    </div>
  )
}
```

## Options

| Option        | Type                     | Default     | Description                                        |
| ------------- | ------------------------ | ----------- | -------------------------------------------------- |
| `vault`       | `Address \| VaultId`     | —           | **Required.** Target vault                         |
| `slippageBps` | `number`                 | `50` (0.5%) | Slippage tolerance in basis points                 |
| `onSubmitted` | `(hash: Hash) => void`   | —           | Called after the transaction is sent               |
| `onConfirmed` | `(hash: Hash) => void`   | —           | Called after the transaction is confirmed on-chain |
| `onError`     | `(error: Error) => void` | —           | Called on error                                    |

## Return Value

| Field       | Type                                | Description                                             |
| ----------- | ----------------------------------- | ------------------------------------------------------- |
| `deposit`   | `(amount: bigint) => Promise<Hash>` | Execute a deposit for the given asset amount            |
| `isPending` | `boolean`                           | `true` while the transaction is being sent or confirmed |
| `isError`   | `boolean`                           | `true` if the transaction failed                        |
| `error`     | `Error \| null`                     | Error object                                            |
| `isSuccess` | `boolean`                           | `true` after the transaction is confirmed on-chain      |
| `hash`      | `Hash \| undefined`                 | Transaction hash once submitted                         |
| `reset`     | `() => void`                        | Reset all state back to idle                            |

## Behavior

| Behavior                  | Detail                                                                                                        |
| ------------------------- | ------------------------------------------------------------------------------------------------------------- |
| **Query invalidation**    | Automatically invalidates `useVault` and `useUserBalance` queries on success                                  |
| **Confirmation tracking** | Uses `useWaitForTransactionReceipt` internally — `isSuccess` flips to `true` only after on-chain confirmation |
| **Error propagation**     | Fires both the local `onError` callback and the global `YieldProvider.onError` handler                        |
| **Slippage**              | The gateway calculates the minimum output based on `slippageBps` and reverts if not met                       |

{% hint style="warning" %}
**Approval required**

The user must have approved the gateway to spend their tokens before depositing. Use `useApprove` to handle this — see the [useApprove docs](broken://pages/4603efa0d6ec049f211a87ef47ad36e5fb912db9).
{% endhint %}


# use pending redemptions

Query hook for fetching pending async redemptions for a user.

```tsx
const { pendingRedemptions, isLoading } = usePendingRedemptions({
  vault: 'yoETH',
  user: accountAddress,
})
```

## Usage

```tsx
import { usePendingRedemptions } from '@yo-protocol/react'
import { useAccount } from 'wagmi'

function PendingRedeems() {
  const { address } = useAccount()

  const { pendingRedemptions, isLoading, refetch } = usePendingRedemptions({
    vault: 'yoETH',
    user: address,
  })

  if (isLoading) return <p>Loading...</p>

  if (!pendingRedemptions?.assets && !pendingRedemptions?.shares) {
    return <p>No pending redemptions</p>
  }

  return (
    <div>
      {pendingRedemptions.assets && (
        <p>Pending assets: {pendingRedemptions.assets.formatted}</p>
      )}
      {pendingRedemptions.shares && (
        <p>Pending shares: {pendingRedemptions.shares.formatted}</p>
      )}
      <button onClick={() => refetch()}>Refresh</button>
    </div>
  )
}
```

## Options

| Option  | Type                 | Default | Description                                   |
| ------- | -------------------- | ------- | --------------------------------------------- |
| `vault` | `Address \| VaultId` | —       | **Required.** Target vault                    |
| `user`  | `Address`            | —       | User address to query pending redemptions for |

## Return Value

| Field                | Type                         | Description                                                            |
| -------------------- | ---------------------------- | ---------------------------------------------------------------------- |
| `pendingRedemptions` | `PendingRedeem \| undefined` | Pending redemption data with `assets` and `shares` as `FormattedValue` |
| `isLoading`          | `boolean`                    | `true` while the query is loading                                      |
| `isError`            | `boolean`                    | `true` if the query failed                                             |
| `error`              | `Error \| null`              | Error object                                                           |
| `refetch`            | `() => void`                 | Manually refetch pending redemptions                                   |

## Behavior

| Behavior       | Detail                                                          |
| -------------- | --------------------------------------------------------------- |
| **Stale time** | 30 seconds — pending redeems are polled relatively frequently   |
| **Enabled**    | Only runs when both the client and a user address are available |
| **Query key**  | `['yo-pending-redemptions', vaultAddress, user, chainId]`       |


# use user balance

Fetches a connected user's position in a vault — shares and equivalent asset value.

```tsx
const { position, isLoading, refetch } = useUserBalance('yoETH', address)
```

## Usage

```tsx
import { useUserBalance } from '@yo-protocol/react'
import { useAccount } from 'wagmi'
import { formatEther } from 'viem'

function UserPosition() {
  const { address } = useAccount()
  const { position, isLoading } = useUserBalance('yoETH', address)

  if (!address) return <p>Connect wallet to view position</p>
  if (isLoading) return <p>Loading position...</p>

  return (
    <dl>
      <dt>Shares</dt>
      <dd>{formatEther(position?.shares ?? 0n)}</dd>
      <dt>Assets</dt>
      <dd>{formatEther(position?.assets ?? 0n)}</dd>
    </dl>
  )
}
```

## Parameters

| Parameter | Type                   | Required | Description                                       |
| --------- | ---------------------- | -------- | ------------------------------------------------- |
| `vault`   | `Address \| VaultId`   | Yes      | Vault address or named ID                         |
| `account` | `Address \| undefined` | No       | User address. Query is disabled when `undefined`. |

## Return Value

| Field       | Type                             | Description                                   |
| ----------- | -------------------------------- | --------------------------------------------- |
| `position`  | `UserVaultPosition \| undefined` | Full user position                            |
| `isLoading` | `boolean`                        | `true` while the initial fetch is in progress |
| `isError`   | `boolean`                        | `true` if the query failed                    |
| `error`     | `Error \| null`                  | Error object if the query failed              |
| `refetch`   | `() => void`                     | Manually trigger a refetch                    |

### UserVaultPosition shape

| Property | Type     | Description                                     |
| -------- | -------- | ----------------------------------------------- |
| `shares` | `bigint` | Vault share balance                             |
| `assets` | `bigint` | Equivalent asset value at current exchange rate |

## Caching

| Setting           | Value | Description                                      |
| ----------------- | ----- | ------------------------------------------------ |
| `staleTime`       | 15s   | Position data is considered fresh for 15 seconds |
| `refetchInterval` | 30s   | Background refetch every 30 seconds              |

{% hint style="info" %}
**Automatic invalidation**

Queries are automatically invalidated after a successful `useDeposit`, `useRedeem`, or `useApprove` transaction.
{% endhint %}


# use approve

Mutation hook for ERC-20 token approvals. Supports both exact amounts and unlimited (`maxUint256`) approval.

```tsx
const { approve, approveMax, isPending, isSuccess } = useApprove({ token })
```

## Usage

```tsx
import { useApprove } from '@yo-protocol/react'
import { parseEther } from 'viem'

function ApproveButton({ token }: { token: `0x${string}` }) {
  const {
    approve,
    approveMax,
    isPending,
    isSuccess,
    hash,
    error,
    reset,
  } = useApprove({
    token,
    onSubmitted: (hash) => console.log('Approved:', hash),
  })

  return (
    <div>
      <button onClick={() => approve(parseEther('10'))} disabled={isPending}>
        {isPending ? 'Approving...' : 'Approve 10 tokens'}
      </button>
      <button onClick={approveMax} disabled={isPending}>
        Approve unlimited
      </button>

      {isSuccess && <p>Approved! Tx: {hash}</p>}
      {error && (
        <p>
          Error: {error.message}
          <button onClick={reset}>Dismiss</button>
        </p>
      )}
    </div>
  )
}
```

{% hint style="info" %}
**When to approve**

Call `approve` or `approveMax` before the first deposit. The gateway checks allowance on-chain and will revert if it's insufficient. You can check the current allowance via `YoClient.hasEnoughAllowance()`.
{% endhint %}

## Options

| Option        | Type                     | Default              | Description                                        |
| ------------- | ------------------------ | -------------------- | -------------------------------------------------- |
| `token`       | `Address`                | —                    | **Required.** ERC-20 token address to approve      |
| `spender`     | `Address`                | `YO_GATEWAY_ADDRESS` | Contract that receives the allowance               |
| `onSubmitted` | `(hash: Hash) => void`   | —                    | Called after the transaction is sent               |
| `onConfirmed` | `(hash: Hash) => void`   | —                    | Called after the transaction is confirmed on-chain |
| `onError`     | `(error: Error) => void` | —                    | Called on error                                    |

## Return Value

| Field        | Type                                | Description                                             |
| ------------ | ----------------------------------- | ------------------------------------------------------- |
| `approve`    | `(amount: bigint) => Promise<Hash>` | Approve a specific token amount                         |
| `approveMax` | `() => Promise<Hash>`               | Approve `maxUint256` (unlimited)                        |
| `isPending`  | `boolean`                           | `true` while the transaction is being sent or confirmed |
| `isError`    | `boolean`                           | `true` if the transaction failed                        |
| `error`      | `Error \| null`                     | Error object                                            |
| `isSuccess`  | `boolean`                           | `true` after the transaction is confirmed on-chain      |
| `hash`       | `Hash \| undefined`                 | Transaction hash once submitted                         |
| `reset`      | `() => void`                        | Reset all state back to idle                            |

## Behavior

| Behavior                  | Detail                                                                                 |
| ------------------------- | -------------------------------------------------------------------------------------- |
| **Default spender**       | Defaults to `YO_GATEWAY_ADDRESS` — the standard deposit entry point                    |
| **Confirmation tracking** | Uses `useWaitForTransactionReceipt` internally                                         |
| **Error propagation**     | Fires both the local `onError` callback and the global `YieldProvider.onError` handler |


# use redeem

Mutation hook for redeeming vault shares for underlying assets via the Yo Gateway, with transaction tracking and automatic query invalidation.

```tsx
const { redeem, isPending, isSuccess, hash, instant, assetsOrRequestId } = useRedeem({ vault: 'yoETH' })
```

## Usage

```tsx
import { useRedeem } from '@yo-protocol/react'

function RedeemButton({ shares }: { shares: bigint }) {
  const {
    redeem,
    isPending,
    isSuccess,
    hash,
    instant,
    assetsOrRequestId,
    error,
    reset,
  } = useRedeem({
    vault: 'yoETH',
    onSubmitted: (hash) => console.log('Redeemed:', hash),
  })

  return (
    <div>
      <button onClick={() => redeem(shares)} disabled={isPending}>
        {isPending ? 'Redeeming...' : 'Redeem'}
      </button>

      {isSuccess && (
        <div>
          <p>Redemption complete! Tx: {hash}</p>
          {instant !== undefined && (
            <p>{instant ? 'Instant redemption' : `Pending — request ID: ${assetsOrRequestId}`}</p>
          )}
        </div>
      )}
      {error && (
        <p>
          Error: {error.message}
          <button onClick={reset}>Dismiss</button>
        </p>
      )}
    </div>
  )
}
```

{% hint style="info" %}
**Instant vs async redemptions**

The gateway `redeem` may complete instantly if sufficient liquidity is available. If not, the redemption remains pending for up to 24 hours. The `YoGatewayRedeem` event's `instant` field indicates which path was taken.
{% endhint %}

## Options

| Option        | Type                     | Default | Description                                        |
| ------------- | ------------------------ | ------- | -------------------------------------------------- |
| `vault`       | `Address \| VaultId`     | —       | **Required.** Target vault                         |
| `onSubmitted` | `(hash: Hash) => void`   | —       | Called after the transaction is sent               |
| `onConfirmed` | `(hash: Hash) => void`   | —       | Called after the transaction is confirmed on-chain |
| `onError`     | `(error: Error) => void` | —       | Called on error                                    |

## Return Value

| Field               | Type                                | Description                                                                                 |
| ------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------- |
| `redeem`            | `(shares: bigint) => Promise<Hash>` | Redeem the given share amount for underlying assets                                         |
| `isPending`         | `boolean`                           | `true` while the transaction is being sent or confirmed                                     |
| `isError`           | `boolean`                           | `true` if the transaction failed                                                            |
| `error`             | `Error \| null`                     | Error object                                                                                |
| `isSuccess`         | `boolean`                           | `true` after the transaction is confirmed on-chain                                          |
| `hash`              | `Hash \| undefined`                 | Transaction hash once submitted                                                             |
| `instant`           | `boolean \| undefined`              | `true` if redemption completed instantly, `false` if pending. Available after confirmation. |
| `assetsOrRequestId` | `bigint \| undefined`               | Assets returned (if instant) or pending request ID. Available after confirmation.           |
| `reset`             | `() => void`                        | Reset all state back to idle                                                                |

## Behavior

| Behavior                  | Detail                                                                                 |
| ------------------------- | -------------------------------------------------------------------------------------- |
| **Query invalidation**    | Automatically invalidates `useUserBalance` queries on success                          |
| **Confirmation tracking** | Uses `useWaitForTransactionReceipt` internally                                         |
| **Error propagation**     | Fires both the local `onError` callback and the global `YieldProvider.onError` handler |
| **Slippage protection**   | Uses `quotePreviewRedeem` to calculate `minAssetsOut` with default 0.5% slippage       |


# use vaults

Returns the list of vault configurations for the connected chain. Vault configs are static and cached indefinitely.

```tsx
const { vaults, isLoading, isError, error } = useVaults()
```

## Usage

```tsx
import { useVaults } from '@yo-protocol/react'

function VaultList() {
  const { vaults, isLoading } = useVaults()

  if (isLoading) return <p>Loading vaults...</p>

  return (
    <ul>
      {vaults.map((v) => (
        <li key={v.address}>
          <strong>{v.name}</strong> ({v.symbol}) — {v.underlying.symbol}
        </li>
      ))}
    </ul>
  )
}
```

## Return Value

| Field       | Type            | Description                                                        |
| ----------- | --------------- | ------------------------------------------------------------------ |
| `vaults`    | `VaultConfig[]` | Array of vault configs for the current chain (empty while loading) |
| `isLoading` | `boolean`       | `true` while the initial fetch is in progress                      |
| `isError`   | `boolean`       | `true` if the query failed                                         |
| `error`     | `Error \| null` | Error object if the query failed                                   |

### VaultConfig shape

| Property     | Type                            | Description               |
| ------------ | ------------------------------- | ------------------------- |
| `address`    | `Address`                       | Vault contract address    |
| `name`       | `string`                        | Human-readable vault name |
| `symbol`     | `string`                        | Vault share token symbol  |
| `underlying` | `{ address, symbol, decimals }` | Underlying ERC-20 token   |
| `chains`     | `number[]`                      | Supported chain IDs       |

## Caching

| Setting     | Value      | Description                                 |
| ----------- | ---------- | ------------------------------------------- |
| `staleTime` | `Infinity` | Vault configs are static and never go stale |

{% hint style="info" %}
**Chain-aware**

The returned list automatically filters to vaults available on the currently connected chain. Switching chains returns a different set.
{% endhint %}


# use vault history

Fetches historical APY and TVL timeseries data for a vault from the off-chain API.

```tsx
const { yieldHistory, tvlHistory, isLoading } = useVaultHistory('yoETH')
```

## Usage

```tsx
import { useVaultHistory } from '@yo-protocol/react'

function VaultChart() {
  const { yieldHistory, tvlHistory, isLoading } = useVaultHistory('yoETH')

  if (isLoading) return <p>Loading history...</p>

  const latest = yieldHistory[yieldHistory.length - 1]

  return (
    <div>
      <p>
        Latest APY: {latest?.value}% —{' '}
        {new Date(latest?.timestamp * 1000).toLocaleDateString()}
      </p>
      <p>Total data points: {yieldHistory.length} yield, {tvlHistory.length} TVL</p>

      <ul>
        {yieldHistory.slice(-7).map((point) => (
          <li key={point.timestamp}>
            {new Date(point.timestamp * 1000).toLocaleDateString()}: {point.value}%
          </li>
        ))}
      </ul>
    </div>
  )
}
```

## Parameters

| Parameter | Type                 | Required | Description               |
| --------- | -------------------- | -------- | ------------------------- |
| `vault`   | `Address \| VaultId` | Yes      | Vault address or named ID |

## Return Value

| Field          | Type                | Description                          |
| -------------- | ------------------- | ------------------------------------ |
| `yieldHistory` | `TimeseriesPoint[]` | Historical APY data points           |
| `tvlHistory`   | `TimeseriesPoint[]` | Historical TVL data points           |
| `isLoading`    | `boolean`           | `true` while either query is loading |
| `isError`      | `boolean`           | `true` if either query failed        |
| `error`        | `Error \| null`     | First error encountered              |
| `refetch`      | `() => void`        | Refetch both timeseries queries      |

### TimeseriesPoint shape

| Property    | Type     | Description                  |
| ----------- | -------- | ---------------------------- |
| `timestamp` | `number` | Unix timestamp (seconds)     |
| `value`     | `number` | APY percentage or TVL in USD |

## Caching

| Setting     | Value | Description                                       |
| ----------- | ----- | ------------------------------------------------- |
| `staleTime` | 5 min | Historical data is considered fresh for 5 minutes |

{% hint style="info" %}
**Charting**

The timeseries arrays are sorted chronologically (oldest first) and work directly with charting libraries like Recharts, Chart.js, or Visx — just map `timestamp` to x and `value` to y.
{% endhint %}


# Guides


# Error handling

## Global Error Handler

Set a global error handler on `YieldProvider` to catch errors from all action hooks:

```tsx
<YieldProvider onError={(error) => {
  // Log to your error tracking service
  Sentry.captureException(error)
  toast.error(error.message)
}}>
  {children}
</YieldProvider>
```

## Per-Hook Error Handling

Each action hook (`useDeposit`, `useRedeem`, `useApprove`) accepts local `onError` callbacks:

```tsx
const { deposit, error } = useDeposit({
  vault: 'yoETH',
  onError: (err) => {
    toast.error(`Deposit failed: ${err.message}`)
  },
})
```

Both the local and global handlers are called when an error occurs.

## Error States in Read Hooks

Read hooks expose `isError` and `error` fields:

```tsx
const { vault, isError, error } = useVault('yoETH')

if (isError) {
  return <div>Failed to load vault: {error?.message}</div>
}
```

## API Errors

The `ApiClient` throws `ApiError` with an HTTP status code:

```ts
import { ApiError } from '@yo-protocol/core'

try {
  const snapshot = await client.getVaultSnapshot(address)
} catch (err) {
  if (err instanceof ApiError) {
    if (err.statusCode === 404) {
      // Vault not found
    } else if (err.statusCode >= 500) {
      // Server error — retry
    }
  }
}
```

## Common Errors

| Error                      | Cause                                   | Solution                                         |
| -------------------------- | --------------------------------------- | ------------------------------------------------ |
| "Client not available"     | Hook used before providers are ready    | Ensure `YieldProvider` is inside `WagmiProvider` |
| "Account not connected"    | Action called without wallet connection | Check `useAccount()` before calling actions      |
| "WalletClient is required" | Core client used for tx without wallet  | Call `client.setWalletClient()` first            |
| User rejected transaction  | User declined in wallet                 | Catch and show appropriate UI                    |


# Wagmi setup

`@yo-protocol/react` requires a wagmi config with the chains you want to support.

## Basic Setup

```ts
// wagmi.ts
import { http, createConfig } from 'wagmi'
import { base, mainnet } from 'wagmi/chains'
import { injected, walletConnect } from 'wagmi/connectors'

export const config = createConfig({
  chains: [base, mainnet],
  connectors: [
    injected(),
    walletConnect({ projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID! }),
  ],
  transports: {
    [base.id]: http(),
    [mainnet.id]: http(),
  },
})
```

## Provider Setup

```tsx
// providers.tsx
'use client'

import { WagmiProvider } from 'wagmi'
import { QueryClientProvider, QueryClient } from '@tanstack/react-query'
import { YieldProvider } from '@yo-protocol/react'
import { config } from './wagmi'

const queryClient = new QueryClient()

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <YieldProvider defaultSlippageBps={50}>
          {children}
        </YieldProvider>
      </QueryClientProvider>
    </WagmiProvider>
  )
}
```

## Chain Support

@yield currently supports:

* **Ethereum Mainnet** (chain ID `1`)
* **Base** (chain ID `8453`)

Your wagmi config should include at least one of these chains. The `useYoClient` hook will return `null` if the user is connected to an unsupported chain.


# Examples

## Vault Dashboard

A minimal vault dashboard showing vault state and user position.

```tsx
import { useVault, useUserBalance, useVaults } from '@yo-protocol/react'
import { useAccount } from 'wagmi'
import { formatUnits } from 'viem'

function VaultDashboard() {
  const { address } = useAccount()
  const { vaults } = useVaults()

  return (
    <div>
      <h1>Available Vaults</h1>
      {vaults.map((v) => (
        <VaultRow key={v.address} address={v.address} account={address} />
      ))}
    </div>
  )
}

function VaultRow({ address, account }) {
  const { vault, isLoading } = useVault(address)
  const { position } = useUserBalance(address, account)

  if (isLoading) return <div>Loading...</div>

  return (
    <div>
      <h2>{vault?.name}</h2>
      <p>TVL: {vault ? formatUnits(vault.totalAssets, vault.assetDecimals) : '—'}</p>
      {position && (
        <p>Your balance: {formatUnits(position.assets, vault!.assetDecimals)}</p>
      )}
    </div>
  )
}
```

## Deposit Flow

Full deposit flow with approval check, approve, and deposit.

```tsx
import { useDeposit, useApprove, useVault } from '@yo-protocol/react'
import { useAccount } from 'wagmi'
import { parseUnits } from 'viem'
import { VAULTS, YO_GATEWAY_ADDRESS } from '@yo-protocol/core'

function DepositForm() {
  const vault = VAULTS.yoUSD
  const { address } = useAccount()
  const { vault: vaultState } = useVault('yoUSD')

  const { approve, isLoading: approving } = useApprove({
    token: vault.underlying.address[8453],
    spender: YO_GATEWAY_ADDRESS,
    onSubmitted: () => console.log('Approved'),
  })

  const { deposit, isLoading: depositing, isSuccess } = useDeposit({
    vault: 'yoUSD',
    onSubmitted: (hash) => console.log('Deposited:', hash),
  })

  const handleDeposit = async () => {
    const amount = parseUnits('100', 6) // 100 USDC
    await approve(amount)
    await deposit(amount)
  }

  return (
    <div>
      <h2>Deposit into {vaultState?.name}</h2>
      <button onClick={handleDeposit} disabled={approving || depositing}>
        {approving ? 'Approving...' : depositing ? 'Depositing...' : 'Deposit 100 USDC'}
      </button>
      {isSuccess && <p>Deposit confirmed!</p>}
    </div>
  )
}
```

## Withdraw Flow

Redeem vault shares for underlying assets via the Yo Gateway.

```tsx
import { useRedeem, useUserBalance } from '@yo-protocol/react'
import { useAccount } from 'wagmi'

function WithdrawForm() {
  const { address } = useAccount()
  const { position } = useUserBalance('yoETH', address)

  const { redeem, isLoading } = useRedeem({
    vault: 'yoETH',
    onSubmitted: (hash) => console.log('Redeemed:', hash),
  })

  return (
    <div>
      <p>Your shares: {position?.shares.toString() ?? '0'}</p>

      <button
        onClick={() => redeem(position!.shares)}
        disabled={isLoading || !position?.shares}
      >
        {isLoading ? 'Withdrawing...' : 'Withdraw All'}
      </button>
    </div>
  )
}
```

## Deposit with Automatic Approval

Using `depositWithApproval` to handle the approve-if-needed + deposit flow in one call.

```tsx
import { useYoKit } from '@yo-protocol/react'
import { useAccount } from 'wagmi'
import { parseUnits } from 'viem'
import { VAULTS } from '@yo-protocol/core'

function SimpleDeposit() {
  const client = useYoKit()
  const { address } = useAccount()

  const handleDeposit = async () => {
    const vault = VAULTS.yoUSD
    const result = await client.depositWithApproval({
      vault: vault.address,
      token: vault.underlying.address[8453],
      amount: parseUnits('100', 6),
    })

    if (result.approveHash) {
      console.log('Approved:', result.approveHash)
    }
    console.log('Deposited:', result.depositHash)
    console.log('Shares:', result.shares)
  }

  return <button onClick={handleDeposit}>Deposit 100 USDC</button>
}
```

## AA Wallet Bundling

Using prepared transactions to build a bundle for account abstraction wallets.

```ts
import { createYoClient, VAULTS } from '@yo-protocol/core'
import { parseUnits } from 'viem'

const client = createYoClient({ chainId: 8453 })
const vault = VAULTS.yoUSD

// Build approve + deposit as raw call data
const bundle = await client.prepareDepositWithApproval({
  vault: vault.address,
  token: vault.underlying.address[8453],
  owner: accountAddress,
  amount: parseUnits('100', 6),
})

// bundle is 1 tx (deposit only) if allowance is sufficient,
// or 2 txs (approve + deposit) if approval is needed.
// Send via your AA bundler:
for (const tx of bundle) {
  console.log({ to: tx.to, data: tx.data, value: tx.value })
}
```

## Checking Pending Redemptions

Query pending async redemptions using the React hook or core client.

```tsx
import { usePendingRedemptions } from '@yo-protocol/react'
import { useAccount } from 'wagmi'

function PendingRedeems() {
  const { address } = useAccount()
  const { pendingRedemptions, isLoading } = usePendingRedemptions({
    vault: 'yoETH',
    user: address,
  })

  if (isLoading) return <p>Loading...</p>

  return (
    <div>
      <h3>Pending Redemptions</h3>
      {pendingRedemptions?.assets ? (
        <p>Assets pending: {pendingRedemptions.assets.formatted}</p>
      ) : (
        <p>No pending redemptions</p>
      )}
    </div>
  )
}
```

## Core SDK (No React)

Using `@yo-protocol/core` directly for server-side or script usage.

```ts
import { createYoClient, VAULTS } from '@yo-protocol/core'
import { formatUnits } from 'viem'

async function main() {
  const client = createYoClient({ chainId: 8453, partnerId: 42 })

  // Fetch on-chain state
  const state = await client.getVaultState(VAULTS.yoETH.address)
  console.log(`${state.name}: ${formatUnits(state.totalAssets, state.assetDecimals)} ETH`)

  // Fetch API snapshot
  const snapshot = await client.getVaultSnapshot(VAULTS.yoETH.address)
  console.log(`APY: ${snapshot.apy}%`)
  console.log(`TVL: ${snapshot.tvl.formatted}`)

  // Historical data
  const yields = await client.getVaultYieldHistory(VAULTS.yoETH.address)
  console.log(`${yields.length} data points`)
}

main()
```

## Provider Setup (Next.js)

Complete provider setup for a Next.js App Router project.

```tsx
// app/providers.tsx
'use client'

import { WagmiProvider } from 'wagmi'
import { QueryClientProvider, QueryClient } from '@tanstack/react-query'
import { YieldProvider } from '@yo-protocol/react'
import { config } from '@/lib/wagmi'

const queryClient = new QueryClient()

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <YieldProvider
          defaultSlippageBps={50}
          onError={(err) => console.error('@yield error:', err)}
        >
          {children}
        </YieldProvider>
      </QueryClientProvider>
    </WagmiProvider>
  )
}
```

```tsx
// app/layout.tsx
import { Providers } from './providers'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  )
}
```


# yoGateway

## Overview

The [**yoGateway**](https://basescan.org/address/0xF1EeE0957267b1A474323Ff9CfF7719E964969FA) 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.&#x20;

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. &#x20;

Ping us on our [Discord](http://discord.gg/yoprotocol) or [Telegram](https://t.me/yo_protocol) to get your unique partner ID or if you have further questions.&#x20;

## Contract Addresses

<table><thead><tr><th width="144.61328125">Contract</th><th>Address</th></tr></thead><tbody><tr><td>YoGateway</td><td>0xF1EeE0957267b1A474323Ff9CfF7719E964969FA</td></tr></tbody></table>

***

## Instantiation

*Solidity:*

```solidity
IYoGateway gateway = IYoGateway(0xF1EeE0957267b1A474323Ff9CfF7719E964969FA);
```

*JS/Ethers:*

```js
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://mainnet.base.org");
const gateway = new ethers.Contract(
  "0xF1EeE0957267b1A474323Ff9CfF7719E964969FA",
  YoGatewayAbi,
  provider
);
```

{% file src="/files/2U2O1HYI8UghLBpN8Yx0" %}

***

## Quoting

### Convert Assets → Shares

*Solidity:*

```solidity
uint256 shares = gateway.quotePreviewDeposit(yoVault, assets);
```

*JS/Ethers:*

```js
const shares = await gateway.quotePreviewDeposit(yoVault, ethers.parseUnits("1", decimals));
```

### Convert Shares → Assets

*Solidity:*

```solidity
uint256 assets = gateway.quotePreviewWithdraw(yoVault, shares);
```

*JS/Ethers:*

```js
const assets = await gateway.quotePreviewWithdraw(yoVault, ethers.parseUnits("1", decimals));
```

***

### Allowance Helpers

The Gateway exposes helper functions to query allowances granted to the Gateway itself, either for redeeming shares or for depositing assets.

*Solidity*

```solidity
gateway.getShareAllowance(yoVault, owner);
gateway.getAssetAllowance(yoVault, owner);
```

JS/Ethers:

```javascript
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
const yoETH = "0x3a43aec53490cb9fa922847385d82fe25d0e9de7";
const asset = "0x4200000000000000000000000000000000000006";

const shareAllowance = await gateway.getShareAllowance(yoVault, signer.address);
const assetAllowance = await gateway.getAssetAllowance(asset, signer.address);
```

***

## Depositing Assets

Solidity:

```solidity
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
);
```

*JS/Ethers:*

```js
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();
```

***

## Redeeming Shares

*Solidity:*

```solidity
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
);
```

*JS/Ethers:*

```js
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();
```

***

## Function Recap

| Action                  | Quote Function         | Execution Function |
| ----------------------- | ---------------------- | ------------------ |
| Deposit (assets→shares) | `quotePreviewDeposit`  | `deposit`          |
| Redeem (shares→assets)  | `quotePreviewWithdraw` | `redeem`           |

***

## Notes

1. **Decimals must be respected when parsing values**

   * WETH / yoETH: <mark style="color:red;">18</mark>
   * cbBTC / yoBTC: <mark style="color:red;">8</mark>
   * USDC / yoUSD: <mark style="color:red;">6</mark>
   * USDT / yoUSDT: <mark style="color:red;">6</mark>
   * EURC / yoEUR: <mark style="color:red;">6</mark>
   * XAUT / yoGOLD: <mark style="color:red;">6</mark>

   \
   Example: `ethers.parseUnits("1.0", 18)`
2. **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`**.
3. **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.<br>

***

### 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.

```js
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);
});
```


# Individual Contracts

This guide explains how to interact with the `yoVaults` smart contracts (`yoETH, yoUSD, yoBTC, yoEUR, yoGOLD`). These contracts implement the [ERC-4626](https://eips.ethereum.org/EIPS/eip-4626) Tokenized Vault Standard, enabling users and integrators to deposit ERC-20 tokens ("assets") and receive yield-bearing yoTokens in return.&#x20;

The guide outlines how to:

* Connect to the vaults with Ethers.js
* Use read functions (`previewDeposit`, `previewMint`, `previewRedeem`) to estimate outcomes
* Execute deposit and redemption transactions
* Understand how yoTokens ↔ assets conversion works

> All vaults follow the same contract interface and live on **Base chain (chain ID 8453) and on Ethereum mainnet (chain ID 1)**.

NOTE: yoGOLD is only available on Ethereum.&#x20;

***

## ⚙️ Setup

### Install Ethers

```bash
npm install ethers
```

### Connect to an RPC & Instantiate the Contract

```ts
import { ethers } from "ethers";
import abi from "./yoAbi.json"; // Use the ABI attached below 

const provider = new ethers.JsonRpcProvider("https://mainnet.base.org"); // or use any RPC for Ethereum chain
const signer = new ethers.Wallet(PRIVATE_KEY, provider);

const YO_VAULTS = {
  yoETH: "0x3a43aec53490cb9fa922847385d82fe25d0e9de7",
  yoUSD: "0x0000000f2eb9f69274678c76222b35eec7588a65",
  yoBTC: "0xbcbc8cb4d1e8ed048a6276a5e94a3e952660bcbc",
  ...,
};

const vault = new ethers.Contract(YO_VAULTS.yoETH, abi, signer); // Swap as needed
```

{% file src="/files/S6idsNvxUyPjEGiLcEiR" %}

***

## 🔍 Simulate with `preview*` and `convertTo` Functions

These functions estimate how many shares or assets you'll receive/spend before making a transaction or to price your position.

### Pricing your positions:

#### `maxWithdraw(owner)`

Returns the **maximum amount of assets** that can currently be withdrawn by the given address.

```ts
const maxAssets = await vault.maxWithdraw(await signer.getAddress());
```

#### `convertToAssets(shares)`

Estimate how many yoTokens you get for a given asset amount (excludes fees):

```ts
const yoTokens = await vault.convertToShares(ethers.parseUnits("1.0", 18));
```

### Quoting before building a transaction

#### `previewDeposit(assets)`

Estimate how many yoTokens you get for a given asset amount net of deposit fees:

```ts
const yoTokens = await vault.previewDeposit(ethers.parseUnits("1.0", 18));
```

#### `previewRedeem(shares)`

Estimate how many assets you'd get back when redeeming yoTokens net of withdrawal fees:

```ts
const assetsOut = await vault.previewRedeem(ethers.parseUnits("1.0", 18));
```

***

## ✍️ Execute Transactions

### `deposit(assets, receiver)`

Deposit a specific amount of assets and receive yoTokens in return:

```ts
const tx = await vault.deposit(
  ethers.parseUnits("1.0", 18),       // Assets to deposit
  await signer.getAddress()           // Receiver of yoTokens
);
await tx.wait();
```

***

### `redeem(yoTokens, receiver, owner)`

Burn yoTokens and receive assets in return. You **cannot request an exact asset amount**. See our Notes below.

```ts
const tx = await vault.redeem(
  ethers.parseUnits("1.0", 18),       // yoTokens to redeem
  await signer.getAddress(),          // Receiver of assets
  await signer.getAddress()           // Owner of shares
);
await tx.wait();
```

***

## &#x20;Recap: Share-to-Asset Logic

<table><thead><tr><th width="267.7734375">You Want To...</th><th width="125">Use This Function</th><th>Simulation Tool</th></tr></thead><tbody><tr><td>Deposit assets for yoTokens</td><td><code>deposit()</code></td><td><code>previewDeposit()</code></td></tr><tr><td>Mint exact amount of yoTokens</td><td><code>mint()</code> </td><td><code>previewMint()</code></td></tr><tr><td>Redeem yoTokens for assets</td><td><code>redeem()</code></td><td><code>previewRedeem()</code></td></tr></tbody></table>

***

## Notes

* All values must be parsed using correct decimals (e.g. `ethers.parseUnits("1.0", 18)`).
  * WETH / yoETH decimals: <mark style="color:red;">18</mark>&#x20;
  * cbBTC / yoBTC decimals: <mark style="color:red;">8</mark>
  * USDC / yoUSD and yoUSD Edge decimals: <mark style="color:red;">6</mark>
  * USDT / yoUSDT decimals: <mark style="color:red;">6</mark>
  * EURC / yoEUR: <mark style="color:red;">6</mark>
  * XAUT / yoGOLD: <mark style="color:red;">6</mark>
* Only `redeem` is supported for withdrawals because depending on the withdrawal amount, the yoVault may not have enough available liquidity to fill the redeem order. In those cases, the withdrawal will remain pending for up to 24 hours. The protocol will fill the redeem order and send the assets automatically to the `receiver` specified in the `requestRedeem` transaction.&#x20;
* All the yoVaults follow the same ABI and differ only by address.


# AI Agents

Leverage your agentic framework to build with you in a few prompts

Build AI-powered applications on top of YO Protocol using our open-source agent skills.&#x20;

Whether you're scripting vault interactions from the command line, building React dashboards, or writing backend services that prepare deposit and redeem transactions, our skills give your AI coding agent full context on the SDK, CLI, and React hooks, so it can generate correct, up-to-date code without hallucinating APIs.&#x20;

Install them with `npx skills add yoprotocol/yo-protocol-skills --all` or browse the individual skills below

{% embed url="<https://github.com/yoprotocol/yo-protocol-skills>" %}


# API

## YO Protocol API&#x20;

Anyone can use the API to fetch historical information at the protocol or address-level. <br>

**Base URL:** <mark style="color:orange;background-color:orange;">`https://api.yo.xyz`</mark>

### Protocol-level data

#### Get a snapshot of the current TVL, yield, underlying pools and allocation of the protocol vaults.&#x20;

## GET /api/v1/vault/{network}/{vaultAddress}

>

```json
{"openapi":"3.0.0","info":{"title":"Yo Protocol API","version":"1.0"},"paths":{"/api/v1/vault/{network}/{vaultAddress}":{"get":{"operationId":"VaultController_getVault_v1","parameters":[{"name":"vaultAddress","required":true,"in":"path","schema":{"type":"string"}},{"name":"network","required":true,"in":"path","schema":{"enum":["base","ethereum","unichain","arbitrum","tac","plasma","hyperevm"],"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Vault"]}}}}
```

#### Check the status of pending redeem requests for a given YO vault on a given blockchain.&#x20;

## GET /api/v1/vault/pending-redeems/{network}/{vaultAddress}

>

```json
{"openapi":"3.0.0","info":{"title":"Yo Protocol API","version":"1.0"},"paths":{"/api/v1/vault/pending-redeems/{network}/{vaultAddress}":{"get":{"operationId":"VaultController_getTotalPendingRedeems_v1","parameters":[{"name":"vaultAddress","required":true,"in":"path","schema":{"type":"string"}},{"name":"network","required":true,"in":"path","schema":{"enum":["base","ethereum","unichain","arbitrum","tac","plasma","hyperevm"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/AmountDto"}}}]}}}}},"tags":["Vault"]}}},"components":{"schemas":{"ApiResponseDto":{"type":"object","properties":{"data":{"type":"object","description":"The response data"},"message":{"type":"string","description":"Message describing the response"},"statusCode":{"type":"number","description":"HTTP status code of the response"}},"required":["data","message","statusCode"]},"AmountDto":{"type":"object","properties":{"raw":{"format":"int64","type":"integer"},"formatted":{"type":"string"}},"required":["raw","formatted"]}}}}
```

#### Fetch the historical  yield of a specific YO vault.

## GET /api/v1/vault/yield/timeseries/{network}/{vaultAddress}

>

```json
{"openapi":"3.0.0","info":{"title":"Yo Protocol API","version":"1.0"},"paths":{"/api/v1/vault/yield/timeseries/{network}/{vaultAddress}":{"get":{"operationId":"VaultController_getYieldTimeseries_v1","parameters":[{"name":"vaultAddress","required":true,"in":"path","schema":{"type":"string"}},{"name":"network","required":true,"in":"path","schema":{"enum":["base","ethereum","unichain","arbitrum","tac","plasma","hyperevm"],"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Vault"]}}}}
```

#### Fetch the historical TVL of a specific YO vault

## GET /api/v1/vault/tvl/timeseries/{network}/{vaultAddress}

>

```json
{"openapi":"3.0.0","info":{"title":"Yo Protocol API","version":"1.0"},"paths":{"/api/v1/vault/tvl/timeseries/{network}/{vaultAddress}":{"get":{"operationId":"VaultController_getTvlTimeseries_v1","parameters":[{"name":"vaultAddress","required":true,"in":"path","schema":{"type":"string"}},{"name":"network","required":true,"in":"path","schema":{"enum":["base","ethereum","unichain","arbitrum","tac","plasma","hyperevm"],"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Vault"]}}}}
```

### User-level data

#### Fetch the historical deposits and withdrawals of a specific address for a specific YO vault on a specific blockchain.&#x20;

## GET /api/v1/history/user/{network}/{vaultAddress}/{userAddress}

>

```json
{"openapi":"3.0.0","info":{"title":"Yo Protocol API","version":"1.0"},"paths":{"/api/v1/history/user/{network}/{vaultAddress}/{userAddress}":{"get":{"operationId":"HistoryController_getAggregatedHistory_v1","parameters":[{"name":"vaultAddress","required":true,"in":"path","schema":{"type":"string"}},{"name":"userAddress","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"type":"number"}},{"name":"network","required":true,"in":"path","schema":{"enum":["base","ethereum","unichain","arbitrum","tac","plasma","hyperevm"],"type":"string"}}],"responses":{"200":{"description":""}},"tags":["History"]}}}}
```

#### Fetch the pending redemptions for a specific user on a specific vault

## GET /api/v1/vault/pending-redeems/{network}/{vaultAddress}/{userAddress}

>

```json
{"openapi":"3.0.0","info":{"title":"Yo Protocol API","version":"1.0"},"paths":{"/api/v1/vault/pending-redeems/{network}/{vaultAddress}/{userAddress}":{"get":{"operationId":"VaultController_getPendingRedeemsForUser_v1","parameters":[{"name":"vaultAddress","required":true,"in":"path","schema":{"type":"string"}},{"name":"userAddress","required":true,"in":"path","schema":{"type":"string"}},{"name":"network","required":true,"in":"path","schema":{"enum":["base","ethereum","unichain","arbitrum","tac","plasma","hyperevm"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/PendingRedeemsForUserResponseDto"}}}]}}}}},"tags":["Vault"]}}},"components":{"schemas":{"ApiResponseDto":{"type":"object","properties":{"data":{"type":"object","description":"The response data"},"message":{"type":"string","description":"Message describing the response"},"statusCode":{"type":"number","description":"HTTP status code of the response"}},"required":["data","message","statusCode"]},"PendingRedeemsForUserResponseDto":{"type":"object","properties":{"assets":{"$ref":"#/components/schemas/AmountDto"},"shares":{"$ref":"#/components/schemas/AmountDto"}},"required":["assets","shares"]},"AmountDto":{"type":"object","properties":{"raw":{"format":"int64","type":"integer"},"formatted":{"type":"string"}},"required":["raw","formatted"]}}}}
```

#### Fetch the P\&L of a user in a specific vault

## GET /api/v1/performance/user/{network}/{vaultAddress}/{userAddress}

>

```json
{"openapi":"3.0.0","info":{"title":"Yo Protocol API","version":"1.0"},"paths":{"/api/v1/performance/user/{network}/{vaultAddress}/{userAddress}":{"get":{"operationId":"PerformanceController_getUserPerformance_v1","parameters":[{"name":"vaultAddress","required":true,"in":"path","schema":{"type":"string"}},{"name":"userAddress","required":true,"in":"path","schema":{"type":"string"}},{"name":"network","required":true,"in":"path","schema":{"enum":["base","ethereum","unichain","arbitrum","tac","plasma","hyperevm"],"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Performance"]}}}}
```


# Brand kit

Downloadable assets and brand guidelines.

### Overview

The YO brand is designed to be bold, clean, and unmistakably modern. This brand kit provides everything partners need to represent YO accurately and respectfully across written, digital, and visual media. YO’s brand personality can be described as:

* Reliable
* Transparent
* Trustworthy
* Determined
* Sincere
* Sleek

\
Use this guide whenever referencing YO, yoVaults, yoTokens or the broader YO ecosystem in your product, documentation, content, or press materials.

#### Approved descriptions

<table><thead><tr><th width="390.1632080078125" valign="top">Protocol</th><th valign="top">yoVaults (eg yoETH, yoUSD, etc)</th></tr></thead><tbody><tr><td valign="top"><p>YO, short for Yield Optimizer, is the yield engine for the crypto economy. It connects capital to the best yield across 50+ DeFi protocols while balancing risk and reward through its novel risk-adjusted approach. With over 100 integrations and more on the way, YO delivers unmatched diversification while continuously reallocating assets across all of DeFi to maximize yield. With simple yoETH, yoBTC, yoEUR and yoUSD tokens, users get access to the best of DeFi yield in a single deposit. YO isn’t just another vault, it's the only vault you’ll ever need. </p><p></p><p>Learn more at <a href="http://yo.xyz">yo.xyz</a> </p><p></p></td><td valign="top">Earn the best risk-adjusted yield through the yo___ Vault. YO connects your assets with the top DeFi yield opportunities across lending, staking, market making, bridging, and more. Leveraging Exponential.fi's Risk Ratings and continuous rebalancing, YO smartly balances risk and reward to ensure you’re getting yield that is transparent, verifiable, and sustainable. </td></tr></tbody></table>

### Logo Assets

#### Approved Logo Variants

YO has exactly two official logo versions. No additional variants are permitted.

* Neon green background (#D6FF34) + black wordmark
* Black background (#2B2C2A) + neon green wordmark

Each yoVault has its own unique logo with one variant only

**Download as png:**

<table><thead><tr><th width="187.62847900390625">Asset</th><th>Primary</th><th>Black</th></tr></thead><tbody><tr><td>Round logo</td><td><img src="/files/qIl3TfjmL5purF4nx6QM" alt="" data-size="original"></td><td><img src="/files/28Kwo3WOlwRI7GNmHfsb" alt="" data-size="original"></td></tr><tr><td>Square logo</td><td><p><img src="/files/EucPYvUQU71P3eQjbCm8" alt="" data-size="original"></p><p></p></td><td><p><img src="/files/J2EcduZqBlOjXeEzh4Pc" alt="" data-size="original"></p><p></p></td></tr><tr><td>Wordmark</td><td><img src="/files/vYYuHy8auN3LAyLKl8Nd" alt="" data-size="original"></td><td><img src="/files/D0T81IwBurwF6vDXeG8n" alt="" data-size="original"></td></tr></tbody></table>

<table><thead><tr><th width="372.31640625">Asset</th><th>Logo</th></tr></thead><tbody><tr><td>yoETH</td><td><p><img src="/files/wRuiOFl5Xo8KFUsHwnGV" alt="" data-size="original"></p><p></p></td></tr><tr><td>yoUSD</td><td><img src="/files/8T76KDhXP6SJNqYFmZkg" alt="" data-size="original"></td></tr><tr><td>yoUSDT</td><td><p></p><p><img src="/files/nqgqY3BoRQVzFTPSPGF2" alt="" data-size="original"></p><p></p></td></tr><tr><td>yoUSD Edge</td><td><p><img src="/files/mNuYvbv3kZ4q0zIhLiqh" alt="" data-size="original"></p><p></p></td></tr><tr><td>yoBTC</td><td><p></p><p><img src="/files/luXL93YpkTAFEjLzJ7wz" alt="" data-size="original"></p></td></tr><tr><td>yoEUR</td><td><p><img src="/files/S1iCfZbdMfk6VMvh112P" alt="" data-size="original"></p><p></p></td></tr><tr><td>yoGOLD</td><td><p><img src="/files/n8LzJCR3sHVOpey6CCKX" alt="" data-size="original"></p><p></p></td></tr><tr><td>yoSOL</td><td><p><img src="/files/vaf1T03tocIJgaCyNTQJ" alt="" data-size="original"></p><p></p></td></tr></tbody></table>

**Download as svg:**

{% file src="/files/vzkilTL37pxrtXY7j4Xt" %}

{% file src="/files/Oros9615LVGdfD6UDOM3" %}

#### Logo Usage Guidelines

**Minimum Rules**

* Use only the two approved background/wordmark combinations.
* Maintain original proportions; never stretch, skew, or rotate the logo.
* Preserve color accuracy — no alternative neon, tints, or brand recolors.
* Use adequate spacing around the logo (½ the height of the wordmark).

**DOs**

* Use the provided assets without modification.
* Use logos at high resolution for all partner, press, and product placements.
* Place the logo on solid backgrounds only.

**DON’Ts**

* ❌ Change colors, apply gradients, or add effects.
* ❌ Modify the shape, weight, or spacing of the wordmark.
* ❌ Create AI-generated or “styled” logo variants.
* ❌ Combine YO with mascots, characters, or fictional elements.
* ❌ Use YO’s logo to imply endorsements or affiliations that have not been explicitly approved.

### Color System

#### Core Brand Colors

These colors define the YO identity and may not be modified.

| Purpose           | Hex     |
| ----------------- | ------- |
| YO Neon (Primary) | #D6FF34 |
| Primary Dark      | #000000 |

YO colors are not interchangeable, must never be tinted or brightened, and should always appear as defined.

#### yoVault Color Assignments

Each vault has a single immutable color used for charts, badges, tags, and documentation:

| Vault      | Color name      | Hex     |
| ---------- | --------------- | ------- |
| yoETH      | Electric Blue   | #2B2C2A |
| yoUSD      | Neon Green      | #00FF8B |
| yoUSD Edge | Frontier Green  | #00B161 |
| yoBTC      | Ligtning Orange | #FFAF4F |
| yoEUR      | Brussels Blue   | #4E6FFF |
| yoGOLD     | Yield Yellow    | #FFBF00 |
| yoSOL      | IBRL Purple     | #DA6AFF |

No gradients, dual-tones, overlays, or recolored variants are allowed.

### Typography

#### Primary Typeface

* Space Grotesk

  Used for headings, sub-headings, and body text.

#### Fallbacks

* System UI sans-serif (only when necessary, e.g., code environments)
* Never substitute with stylistic, serif, or script typefaces.

#### Usage Notes

* Use medium/semibold for titles; regular for paragraphs.
* Maintain generous whitespace and a clean hierarchy.
* Keep typography factual, readable, and direct — in line with YO’s voice.

### Brand Voice & Copy Guidelines

YO communicates with clarity, confidence, and honesty. YO avoids jargon for the sake of jargon, and never oversells risk. YO’s tone of voice should be professional yet approachable.

#### Tone

* Approachable
* Bold and concise
* Competent
* Earnest
* Factual
* Professional

#### Example Behaviors

* Do: explain mechanisms clearly, even when technical.
* Do: use plain, direct language.
* Don’t: promise outcomes or imply guaranteed returns.
* Don’t: use memes, mascots, or playful personas in official materials.

### Allowed vs. Not Allowed Usage

#### Allowed

* Use YO assets exactly as provided.
* Reference YO.xyz as a decentralized protocol.
* Provide educational descriptions of vaults, strategies, or yield mechanics.
* Use YO vault colors in dashboards or reporting.
* Embed YO’s official wordmark in integration docs, partner pages, or press mentions.

#### Not Allowed

* ❌ Do not imply guaranteed returns, safety, or zero-risk yield.
* ❌ Do not provide financial advice under the YO brand.
* ❌ Do not modify or recolor logos or brand colors.
* ❌ Do not create mascot-based, cartoonish, or AI-generated logo variations.
* ❌ Do not indicate partnerships, affiliations, or endorsements unless explicitly approved.
* ❌ Do not combine YO branding with any entity (protocol, company, individual) without approval.

### Contact & Approval Process

All requests for:

* custom assets
* press usage
* partnership listings
* co-branding
* public integrations

must go through the official [YO Intake Form](/integrations/build-with-yo) and the team inquire about your use-case and project details. Authorizations must be granted by a YO Labs representative.&#x20;

### Sacred Brand Rules (Do Not Break)

* The YO neon (#D6FF34) and all vault colors must remain unaltered.
* Only the two official logo variants may be used.
* No gradients, no recolors, no artistic reinterpretations.
* No mascots or characters tied to the brand.
* No AI-generated YO visuals that alter the logos, wordmark or colors of the brand.
* No third-party affiliations unless explicitly approved through the intake form.

### Legal notes

Users of this brand kit acknowledge and agree to:

* YO is a decentralized protocol.
* Information provided through the API is provided on an "as-is" basis and for educational purposes only, not investment advice.
* Using YO materials does not imply investment advice or recommendations.
* Any misuse of the brand to suggest “safe,” “guaranteed,” or “risk-free” returns is prohibited.
* Logos and colors are protected assets and may not be altered.
* YO Labs reserves the right to revoke usage rights for any violation.
* The YO Terms of Service, YO branding guidelines. All company, product and service names used in this website are for identification purposes only and do not imply endorsement.
* User acknowledge that YO is the sole owner of YO trademarks and promise not to use the site content or YO marks for personal or commercial use.
* YO may review use of the branding materials at any time and reserves the right to terminate or modify any use.


# YO Risk Graph

Risk Graph is YO's risk intelligence layer for DeFi. It scores pools, assets, protocols, and chains with a letter grade (A–F) based on their full dependency stack — not just the entity in isolation. This is the same system YO uses to inform vault allocations and due diligence.

Two ways to access it:

1. **Vault Exposure API** — free, public, no auth. Returns a vault's collateral exposure breakdown.
2. **Agent API** — paid via x402, for full risk grading and dependency mapping.

### Which one should I use?

<table><thead><tr><th width="158.546875"></th><th>Vault Exposure API</th><th>Agent API</th></tr></thead><tbody><tr><td>Cost</td><td>Free</td><td>Pay-per-query (x402/USDC)</td></tr><tr><td>Auth</td><td>None</td><td>Wallet signature</td></tr><tr><td>Returns</td><td>Collateral exposure for one vault</td><td>Risk grades, dependency graphs, entity search</td></tr><tr><td>Best for</td><td>Quick exposure checks, UX display</td><td>Full risk assessment, contagion analysis, agentic decision-making</td></tr></tbody></table>

Use the Vault Exposure API to see what a vault holds. Use the Agent API to grade what it holds and trace how risk propagates through it.


# Vault Exposure API

Returns the current collateral exposure of a vault: the underlying assets, their USD value, and their share of total allocation.

No API key required. Works with most Morpho vaults today.

**Use cases**

* **Agentic exploration** — drop this into any agent flow to instantly surface a vault's full collateral picture.
* **Real-time decisions** — let an agent evaluate what a vault actually holds, not just its headline yield, before allocating.
* **UX enrichment** — surface exposure breakdowns directly in your product without a backend integration.

#### Endpoint

<mark style="color:green;">`GET`</mark> `https://risk.yo.xyz/api/v1/public/vault/:chain/:vaultAddress/exposure`

**Headers**

| Name         | Value              |
| ------------ | ------------------ |
| Content-Type | `application/json` |

**Query Parameters**

| Name           | Type   | Description                 |
| -------------- | ------ | --------------------------- |
| `chain`        | string | Chain slug, e.g. `ethereum` |
| `vaultAddress` | string | Vault contract address      |

**Response fields**

| Field                                         | Description                                                                           |
| --------------------------------------------- | ------------------------------------------------------------------------------------- |
| `vault`                                       | Vault identity — `id`, `name`, `tvlUsd`                                               |
| `allocatedUsd`                                | Total USD value allocated by the vault                                                |
| `underlying`                                  | The vault's base asset(s) and their share of allocation                               |
| `collateral`                                  | Each collateral asset backing the vault's positions, with USD exposure and percentage |
| `uncollateralizedUsd` / `uncollateralizedPct` | Portion of the vault with no identified collateral backing                            |

**Example Response**

{% tabs %}
{% tab title="200" %}

```json
{
  "data": {
    "vault": {
      "id": "pool:ethereum:0xb576765fb15505433af24fee2c0325895c559fb2",
      "name": "Paypal USD Main",
      "tvlUsd": "0"
    },
    "allocatedUsd": "302736823.84312195",
    "underlying": [
      {
        "assetId": "asset:ethereum:0x6c3ea9036406852006290770bedfcaba0e23a0e8",
        "symbol": "PYUSD",
        "chain": "ethereum",
        "exposureUsd": "302736823.84312195",
        "exposurePct": "1"
      }
    ],
    "collateral": [
      {
        "assetId": "pool:ethereum:0x8236a87084f8b84306f72007f36f2618a5634494",
        "symbol": "LBTC",
        "chain": "ethereum",
        "exposureUsd": "86096652.66067237",
        "exposurePct": "0.2843943844283958"
      }
    ],
    "uncollateralizedUsd": "0",
    "uncollateralizedPct": "0"
  },
  "message": "SUCCESS",
  "statusCode": 200
}
```

{% endtab %}
{% endtabs %}


# Agent API

For full risk grading and dependency mapping across pools, assets, protocols, and chains. Built for AI agents and programmatic clients. No API key required, plain pay-per-query via the x402 protocol.

**Base URL**

```
https://risk.yo.xyz
```

All endpoints resolve under `https://risk.yo.xyz/api/v1/agent/...`. Treat `resource.url` in the 402 invoice as the canonical source rather than hardcoding this host — if it ever moves, agents reading from the invoice keep working without a code change.

#### Payment

Every `/api/v1/agent/*` route is monetized via [x402](https://x402.org) (v2).

|                |                                                                                      |
| -------------- | ------------------------------------------------------------------------------------ |
| Network        | `eip155:8453` (Base mainnet)                                                         |
| Asset          | USDC — `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` (6 decimals)                     |
| Settlement     | EIP-3009 `transferWithAuthorization` via Coinbase CDP — payer pays no gas, only USDC |
| Onboarding fee | None — plain pay-per-query from the first call                                       |
| Rate limit     | \~10 requests/second per payer                                                       |

**Flow**

1. Send an unpaid request → receive `402 Payment Required` with a base64-encoded invoice in the `PAYMENT-REQUIRED` header, including a canonical `resource.url`.
2. Sign the invoice amount (use [`@x402/fetch`](https://www.npmjs.com/package/@x402/fetch) or [`@x402/core`](https://www.npmjs.com/package/@x402/core) to handle this automatically).
3. Retry with an `X-PAYMENT` header.
4. Receive the resource with a `PAYMENT-RESPONSE` header confirming on-chain settlement (verifiable on [Basescan](https://basescan.org)). Only successful (`2xx`) responses are charged. `400`, `403`, `404`, `429`, and `5xx` responses are free — point lookups (`/node`, `/dependencies`) are safe to probe. `/search` is the one exception: it always settles, even on a zero-result query, since the scan itself is the billable work.

If your price changes between calls (see escalation below), the server re-issues a fresh `402` with the corrected amount — always sign the amount in the invoice you actually receive, not a cached one.

**Minimal client**

```ts
import { x402Client } from '@x402/core/client';
import { ExactEvmScheme } from '@x402/evm/exact/client';
import { wrapFetchWithPayment } from '@x402/fetch';
import { privateKeyToAccount } from 'viem/accounts';
 
const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);
const client = new x402Client();
client.register('eip155:*', new ExactEvmScheme(signer));
const fetchPaid = wrapFetchWithPayment(fetch, client);
 
const res = await fetchPaid('https://risk.yo.xyz/api/v1/agent/search?q=morpho');
const json = await res.json();          // { data: { nodes }, … }
const receipt = res.headers.get('payment-response'); // base64 settlement receipt
```

Fund the signer wallet with a small USDC balance on Base. No ETH needed — the facilitator pays gas. At base pricing, **$1 covers roughly 1,000 cheap calls** (schema/search); heavier use costs more under the escalation rule below.

#### Endpoints

| Endpoint                                 | Price  | Returns                                                                                                                      |
| ---------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------- |
| `GET /api/v1/agent/schema`               | $0.001 | Data model: node types, edge types, grade letters. Call this first.                                                          |
| `GET /api/v1/agent/search?q=`            | $0.001 | Lean teaser per hit — `name`, `network`, `tvlUsd`/`marketCapUsd`, `address`/`uniqueKey`. **No grade.** Capped at 10 results. |
| `GET /api/v1/agent/node/:nodeId`         | $0.05  | Full properties + grade `_riskTier` + `riskBreakdown` (rationale as Q\&A pairs). `404` (free) if not indexed.                |
| `GET /api/v1/agent/dependencies?nodeId=` | $1.00  | A pool's direct (1-hop) dependencies — edges and neighboring nodes, each stamped with `lastUpdatedAt`.                       |

`/search` and `/node` are deliberately not interchangeable: `/search` is for finding an entity cheaply, `/node` is for reading its grade. Always follow up a search hit with a `/node` call to get the actual grade.

**The risk signal**

The only risk value exposed is `_riskTier` — a letter grade from **A** (safest) to **F** (riskiest), present on `/node` and `/dependencies` results (not on `/search` teasers). `/node` also returns **`riskBreakdown`**: the grade's rationale as plain `{ question, answer }` pairs.

**Search filters**

| Param   | Description                                                   |
| ------- | ------------------------------------------------------------- |
| `q`     | Required. Asset address or protocol/asset name. No wildcards. |
| `label` | Restrict to `Pool`, `Asset`, `Protocol`, or `Chain`           |
| `limit` | 1–10, default 10                                              |
| `tvl`   | Comparator, e.g. `>1000000`                                   |
| `grade` | Comparator over A–F, e.g. `<=B`                               |

**Suggested flow**

```
1. GET /schema                          → learn the node/edge model
2. GET /search?q=<name-or-address>      → find the entity (teaser only)
3. GET /node/<nodeId>                   → read its grade + rationale
4. GET /dependencies?nodeId=<poolId>    → map its dependencies (with freshness stamps)
```

#### Full reference

Machine-readable agent documentation:

* [llms.txt](https://www.yo.xyz/risk-graph/llms.txt) — endpoint catalogue and quick reference
* [llms-full.txt](https://www.yo.xyz/risk-graph/llms-full.txt) — full DTO schemas, error semantics, worked examples


