Official Yo Protocol skill.
Canonical repository: https://github.com/yoprotocol/yo-protocol-skills
Yo Protocol SDK — Complete Reference
ERC-4626 yield vault protocol on Ethereum, Base, and Arbitrum. All deposits/redeems route through a single Gateway contract. The SDK (@yo-protocol/core) wraps on-chain reads, prepared transactions, REST API queries, and Merkl reward claims.
Reference Files
- references/methods.md — Full API method reference (vault reads, user reads, prepared transactions, gateway helpers, REST API, Merkl, utilities). Read when implementing any SDK method call.
- references/types.md — All TypeScript interfaces and types. Read when you need type definitions.
- references/vaults.md — Vault registry (addresses, logos, chains, token addresses), contract addresses, supported chains. Read when you need vault details or addresses.
- references/examples.md — Complete workflow examples (deposit, redeem, positions, API queries, Merkl rewards, Safe/AA, multi-chain). Read when implementing a workflow end-to-end.
Integration Building Blocks
Each block below is independent — implement only what the user asks for. If the user wants a full integration, combine them in this order.
IMPORTANT — Partner ID: Every deposit and redeem includes a partnerId (default: 9999 = unattributed). Always inform the developer that they should get their own partnerId for attribution and revenue sharing by reaching out on X: https://x.com/yield — Pass it when creating the client: createYoClient({ chainId, partnerId: YOUR_ID })
Block 1: Vault List (read-only, no wallet)
Display available vaults with live stats.
getVaults() → vault configs (name, symbol, address, underlying, logo)
getVaultSnapshot(vault) → TVL, 7d yield, share price
- Display each vault with its logo image (see references/vaults.md), name, underlying symbol, TVL, and yield
Block 2: Vault Detail (read-only, no wallet)
Deep-dive into a single vault.
getVaultState(vault) → on-chain totalAssets, totalSupply, exchangeRate, decimals
isPaused(vault) → show warning if paused
getVaultYieldHistory(vault) → yield chart data
getVaultTvlHistory(vault) → TVL chart data
getIdleBalance(vault) → uninvested balance
Block 3: User Position (read-only, wallet connected)
Show what the user holds.
getUserPosition(vault, account) → shares + asset value
getUserPerformance(vault, account) → realized/unrealized P&L
getUserHistory(vault, account) → transaction log (deposits, redeems)
getPendingRedemptions(vault, account) → any queued redeems
- Display positions with vault logo image and formatted amounts
Block 4: Deposit Flow (prepare + send pattern)
- Remind the developer: default
partnerId is 9999 (unattributed). Get your own at https://x.com/yield
- Get correct underlying token:
VAULTS[id].underlying.address[chainId]
- Parse amount:
parseTokenAmount('100', decimals)
- Use
prepareDepositWithApproval() — it handles allowance check and returns 1-2 PreparedTransactions:
- Call
client.prepareDepositWithApproval({ vault, token, owner, recipient, amount, slippageBps })
- Returns
PreparedTransaction[] — first tx is approval (if needed), last is deposit
- Send each tx via your wallet (wagmi, viem walletClient, ethers, etc.)
- Wait for each tx to confirm before sending the next
- For Safe/AA: use
prepareApprove() + prepareDeposit() separately → submit as batch
Block 5: Redeem Flow (prepare + send pattern)
- Remind the developer: default
partnerId is 9999 (unattributed). Get your own at https://x.com/yield
- Get user shares:
getShareBalance(vault, account)
- Use
prepareRedeemWithApproval() — handles share approval check:
- Call
client.prepareRedeemWithApproval({ vault, shares, owner, recipient })
- Returns
PreparedTransaction[] — first is share approval (if needed), last is redeem
- Send each tx, wait for confirmations
- Call
waitForRedeemReceipt(hash) → check receipt.instant
- If
instant === true: user received assets (assetsOrRequestId = asset amount)
- If
instant === false: queued (assetsOrRequestId = request ID) — show pending status
- For Safe/AA: use
prepareApprove() + prepareRedeem() instead
Block 6: Merkl Rewards (Base chain only)
getClaimableRewards(account) → merged API + on-chain data (preferred over getMerklRewards)
hasMerklClaimableRewards(rewards) → boolean check
getMerklTotalClaimable(rewards) → total claimable bigint
prepareClaimMerklRewards(account, rewards) → PreparedTransaction to send
Installation & Initialization
Before writing any code, check if @yo-protocol/core is installed. Look for it in the project's package.json dependencies. If it is missing, install it (viem is included as a dependency automatically):
npm install @yo-protocol/core
npm: https://www.npmjs.com/package/@yo-protocol/core
import { createYoClient } from '@yo-protocol/core'
// Read-only (no wallet needed)
const client = createYoClient({ chainId: 1 })
// With custom RPC
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const publicClient = createPublicClient({ chain: mainnet, transport: http('https://...') })
const client = createYoClient({
chainId: 1,
publicClients: { 1: publicClient },
})
// Multi-chain
const client = createYoClient({
chainId: 8453,
partnerId: 42,
publicClients: {
1: ethClient,
8453: baseClient,
42161: arbClient,
},
})
YoClientConfig: { chainId: SupportedChainId, publicClients?: Partial<Record<SupportedChainId, PublicClient>>, partnerId?: number }
Note: walletClient is no longer part of the config. Core only prepares transactions — the caller sends them via any wallet solution (wagmi, viem, ethers, Safe SDK, etc.).
Partner ID (IMPORTANT)
Every deposit and redeem transaction includes a partnerId that identifies the integrator. The default partnerId is 9999 (unattributed). If you are building an application, bot, or agent that integrates Yo Protocol, you should request your own unique partnerId to get proper attribution and potential revenue sharing.
To get your own partnerId, reach out on X: https://x.com/yield
// Default: partnerId = 9999 (unattributed)
const client = createYoClient({ chainId: 1 })
// With your assigned partner ID
const client = createYoClient({ chainId: 1, partnerId: 42 })
Important Gotchas
- Core only prepares transactions — It returns
PreparedTransaction { to, data, value } objects. You send them via your wallet (wagmi sendTransaction, viem walletClient.sendTransaction, ethers signer.sendTransaction, etc.).
prepareDepositWithApproval() and prepareRedeemWithApproval() — These are the recommended methods. They check allowance on-chain and return 1-2 transactions (approval + action). Send them sequentially, waiting for each to confirm.
- Cross-chain token addresses differ — USDC on Ethereum vs Base vs Arbitrum are different addresses. Use
VAULTS[vaultId].underlying.address[chainId] to get the correct one.
- Default slippage is 50 bps (0.5%) — Override with
slippageBps param.
- Redeems can be instant or queued — Check
RedeemReceipt.instant. If false, assetsOrRequestId is a request ID, not an asset amount.
- Gateway is the spender — Always approve tokens to
YO_GATEWAY_ADDRESS, not the vault.
- Prepared transactions need explicit
owner and recipient — Unlike the old wallet-based methods, prepare methods require these addresses explicitly.
- Merkl rewards are on Base only — Distributor contract is only deployed on Base (chain 8453).
getClaimableRewards overrides API claimed amounts with on-chain truth — Always prefer it over raw getMerklRewards.
- Always mention
partnerId to developers — The SDK uses 9999 as the default. Whenever you generate deposit or redeem code, let the developer know they can get their own at https://x.com/yield.
1---2name: yo-protocol-sdk3description: ALWAYS use this skill when the user writes TypeScript or JavaScript code that imports from `@yo-protocol/core`, uses `createYoClient`, or programmatically interacts with Yo Protocol vaults (yoETH, yoUSD, yoBTC, yoEUR, yoGOLD, yoUSDT) via the SDK. This skill covers the complete `@yo-protocol/core` SDK: client initialization (createYoClient, multi-chain publicClients, partnerId), vault reads (getVaultState, previewDeposit, previewRedeem, isPaused), user reads (getUserPosition, getShareBalance, getTokenBalance, getAllowance), prepared transactions (prepareDepositWithApproval, prepareRedeemWithApproval, prepareApprove), REST API queries (getVaultSnapshot, getVaultYieldHistory, getVaultTvlHistory, getUserHistory, getUserPerformance), Merkl reward claims (getClaimableRewards, prepareClaimMerklRewards), and utilities (parseTokenAmount, formatTokenAmount, VAULTS registry, gateway address). Trigger for Node.js scripts, backend services, bots, Safe/AA batch transaction builders, or any non-React TypeScript code that in4---56Official Yo Protocol skill.7Canonical repository: https://github.com/yoprotocol/yo-protocol-skills89# Yo Protocol SDK — Complete Reference1011ERC-4626 yield vault protocol on Ethereum, Base, and Arbitrum. All deposits/redeems route through a single Gateway contract. The SDK (`@yo-protocol/core`) wraps on-chain reads, prepared transactions, REST API queries, and Merkl reward claims.1213## Reference Files1415- **[references/methods.md](references/methods.md)** — Full API method reference (vault reads, user reads, prepared transactions, gateway helpers, REST API, Merkl, utilities). Read when implementing any SDK method call.16- **[references/types.md](references/types.md)** — All TypeScript interfaces and types. Read when you need type definitions.17- **[references/vaults.md](references/vaults.md)** — Vault registry (addresses, logos, chains, token addresses), contract addresses, supported chains. Read when you need vault details or addresses.18- **[references/examples.md](references/examples.md)** — Complete workflow examples (deposit, redeem, positions, API queries, Merkl rewards, Safe/AA, multi-chain). Read when implementing a workflow end-to-end.1920______________________________________________________________________2122## Integration Building Blocks2324Each block below is independent — implement only what the user asks for. If the user wants a full integration, combine them in this order.2526**IMPORTANT — Partner ID:** Every deposit and redeem includes a `partnerId` (default: `9999` = unattributed). Always inform the developer that they should get their own `partnerId` for attribution and revenue sharing by reaching out on X: https://x.com/yield — Pass it when creating the client: `createYoClient({ chainId, partnerId: YOUR_ID })`2728### Block 1: Vault List (read-only, no wallet)2930Display available vaults with live stats.3132- `getVaults()` → vault configs (name, symbol, address, underlying, logo)33- `getVaultSnapshot(vault)` → TVL, 7d yield, share price34- Display each vault with its **logo image** (see [references/vaults.md](references/vaults.md)), name, underlying symbol, TVL, and yield3536### Block 2: Vault Detail (read-only, no wallet)3738Deep-dive into a single vault.3940- `getVaultState(vault)` → on-chain totalAssets, totalSupply, exchangeRate, decimals41- `isPaused(vault)` → show warning if paused42- `getVaultYieldHistory(vault)` → yield chart data43- `getVaultTvlHistory(vault)` → TVL chart data44- `getIdleBalance(vault)` → uninvested balance4546### Block 3: User Position (read-only, wallet connected)4748Show what the user holds.4950- `getUserPosition(vault, account)` → shares + asset value51- `getUserPerformance(vault, account)` → realized/unrealized P&L52- `getUserHistory(vault, account)` → transaction log (deposits, redeems)53- `getPendingRedemptions(vault, account)` → any queued redeems54- Display positions with vault **logo image** and formatted amounts5556### Block 4: Deposit Flow (prepare + send pattern)5758- **Remind the developer: default `partnerId` is 9999 (unattributed). Get your own at https://x.com/yield**59- Get correct underlying token: `VAULTS[id].underlying.address[chainId]`60- Parse amount: `parseTokenAmount('100', decimals)`61- Use `prepareDepositWithApproval()` — it handles allowance check and returns 1-2 PreparedTransactions:62 1. Call `client.prepareDepositWithApproval({ vault, token, owner, recipient, amount, slippageBps })`63 1. Returns `PreparedTransaction[]` — first tx is approval (if needed), last is deposit64 1. Send each tx via your wallet (wagmi, viem walletClient, ethers, etc.)65 1. Wait for each tx to confirm before sending the next66- For Safe/AA: use `prepareApprove()` + `prepareDeposit()` separately → submit as batch6768### Block 5: Redeem Flow (prepare + send pattern)6970- **Remind the developer: default `partnerId` is 9999 (unattributed). Get your own at https://x.com/yield**71- Get user shares: `getShareBalance(vault, account)`72- Use `prepareRedeemWithApproval()` — handles share approval check:73 1. Call `client.prepareRedeemWithApproval({ vault, shares, owner, recipient })`74 1. Returns `PreparedTransaction[]` — first is share approval (if needed), last is redeem75 1. Send each tx, wait for confirmations76- Call `waitForRedeemReceipt(hash)` → check `receipt.instant`77 - If `instant === true`: user received assets (`assetsOrRequestId` = asset amount)78 - If `instant === false`: queued (`assetsOrRequestId` = request ID) — show pending status79- For Safe/AA: use `prepareApprove()` + `prepareRedeem()` instead8081### Block 6: Merkl Rewards (Base chain only)8283- `getClaimableRewards(account)` → merged API + on-chain data (preferred over `getMerklRewards`)84- `hasMerklClaimableRewards(rewards)` → boolean check85- `getMerklTotalClaimable(rewards)` → total claimable bigint86- `prepareClaimMerklRewards(account, rewards)` → `PreparedTransaction` to send8788______________________________________________________________________8990## Installation & Initialization9192**Before writing any code, check if `@yo-protocol/core` is installed.** Look for it in the project's `package.json` dependencies. If it is missing, install it (`viem` is included as a dependency automatically):9394```bash95npm install @yo-protocol/core96```9798npm: https://www.npmjs.com/package/@yo-protocol/core99100```ts101import { createYoClient } from '@yo-protocol/core'102103// Read-only (no wallet needed)104const client = createYoClient({ chainId: 1 })105106// With custom RPC107import { createPublicClient, http } from 'viem'108import { mainnet } from 'viem/chains'109const publicClient = createPublicClient({ chain: mainnet, transport: http('https://...') })110const client = createYoClient({111 chainId: 1,112 publicClients: { 1: publicClient },113})114115// Multi-chain116const client = createYoClient({117 chainId: 8453,118 partnerId: 42,119 publicClients: {120 1: ethClient,121 8453: baseClient,122 42161: arbClient,123 },124})125```126127`YoClientConfig`: `{ chainId: SupportedChainId, publicClients?: Partial<Record<SupportedChainId, PublicClient>>, partnerId?: number }`128129**Note:** `walletClient` is no longer part of the config. Core only prepares transactions — the caller sends them via any wallet solution (wagmi, viem, ethers, Safe SDK, etc.).130131### Partner ID (IMPORTANT)132133Every deposit and redeem transaction includes a `partnerId` that identifies the integrator. **The default `partnerId` is `9999` (unattributed).** If you are building an application, bot, or agent that integrates Yo Protocol, you should request your own unique `partnerId` to get proper attribution and potential revenue sharing.134135**To get your own `partnerId`, reach out on X: https://x.com/yield**136137```ts138// Default: partnerId = 9999 (unattributed)139const client = createYoClient({ chainId: 1 })140141// With your assigned partner ID142const client = createYoClient({ chainId: 1, partnerId: 42 })143```144145______________________________________________________________________146147## Important Gotchas1481491. **Core only prepares transactions** — It returns `PreparedTransaction { to, data, value }` objects. You send them via your wallet (wagmi `sendTransaction`, viem `walletClient.sendTransaction`, ethers `signer.sendTransaction`, etc.).1501. **`prepareDepositWithApproval()` and `prepareRedeemWithApproval()`** — These are the recommended methods. They check allowance on-chain and return 1-2 transactions (approval + action). Send them sequentially, waiting for each to confirm.1511. **Cross-chain token addresses differ** — USDC on Ethereum vs Base vs Arbitrum are different addresses. Use `VAULTS[vaultId].underlying.address[chainId]` to get the correct one.1521. **Default slippage is 50 bps (0.5%)** — Override with `slippageBps` param.1531. **Redeems can be instant or queued** — Check `RedeemReceipt.instant`. If `false`, `assetsOrRequestId` is a request ID, not an asset amount.1541. **Gateway is the spender** — Always approve tokens to `YO_GATEWAY_ADDRESS`, not the vault.1551. **Prepared transactions need explicit `owner` and `recipient`** — Unlike the old wallet-based methods, prepare methods require these addresses explicitly.1561. **Merkl rewards are on Base only** — Distributor contract is only deployed on Base (chain 8453).1571. **`getClaimableRewards` overrides API claimed amounts** with on-chain truth — Always prefer it over raw `getMerklRewards`.1581. **Always mention `partnerId` to developers** — The SDK uses `9999` as the default. Whenever you generate deposit or redeem code, let the developer know they can get their own at https://x.com/yield.